Plane自体の回転と3D図形の配置アルゴリズム
Siv3D勉強中の学生 2024/11/01(Fri) 22:39
ルービックキューブの Box の回転は、添え字を使って表現することができました。ありがとうございました。
次に、ルービックキューブの各面を Plane で表現しようとしています。この場合、面の向きを調整する必要があると考えています。
Up面 と Down面 はそのままの向きで配置します。
Right面 と Left面 は、Z 軸周りに90度回転させて配置します。
Front面 と Back面 は、X 軸周りに90度回転させて配置します。
ここで、Plane 自体の回転はどのように記述すればよいでしょうか?
また、前のスレッドで教えていただいた Sphere の座標は、x、y、z の足し算で求まりましたが、今回は各Planeの座標を求めるのは複雑であると考えています。簡潔な書き方があれば教えていただきたいです。
まとめますと、Plane の向きの調整と座標を求めるアルゴリズムについて教えていただきたいです。
現時点で、Planeの添え字は次のように考えています
0 1 2
3 4 5
6 7 8
9 10 11 18 19 20 27 28 29 36 37 38
12 13 14 21 22 23 30 31 32 39 40 41
15 16 17 24 25 26 33 34 35 42 43 44
45 46 47
48 49 50
51 52 53
Array<int32> planes =
{
//Up
0, 1, 2,
3, 4, 5,
6, 7, 8,
//Left
9, 10, 11,
12, 13, 14,
15, 16, 17,
//Front
18, 19, 20,
21, 22, 23,
24, 25, 26,
//Right
27,28,29,
30,31,32,
33,34,35,
//Back
36,37,38,
39,40,41,
42,43,44,
//Down
45, 46, 47,
48, 49, 50,
51, 52, 53
};
どうぞよろしくお願いします。
Reputeless 2024/11/03(Sun) 12:44
質問がよくわかりませんが、前回示したコードを一部変更し、1 つの Transformer3D で移動と回転をまとめて表現するようにしました。また、6 つの Plane ではなく 6 つの Box で表現します。こうすると簡単になると思います。
https://gist.github.com/Reputeless/477dfe5f3820e9d77e0e14070c886942
Siv3D勉強中の学生 2024/11/03(Sun) 22:43
Reputeless 2024/11/05(Tue) 01:47
Siv3D勉強中の学生 2024/11/05(Tue) 04:29
返信ありがとうございます
ご提案していただいた通り、6つのBoxを使って、それぞれの面に異なる色を付けられるクラスを作成しました
ColorfulCubeクラスを使ってルービックキューブの回転アニメーションを作成することができました
ありがとうございました
#include <Siv3D.hpp>
const Array<Array<int32>> rotateCubeIndices{
// X軸
{0, 1, 5, 4, 2, 3}, // 90deg
{0, 1, 3, 2, 5, 4}, // 180deg
{0, 1, 4, 5, 3, 2}, // 270deg
// Y軸
{4, 5, 2, 3, 1, 0}, // 90deg
{1, 0, 2, 3, 5, 4}, // 180deg
{5, 4, 2, 3, 0, 1}, // 270deg
// Z軸
{3, 2, 0, 1, 4, 5}, // 90deg
{1, 0, 3, 2, 4, 5}, // 180deg
{2, 3, 1, 0, 4, 5}, // 270deg
};
/// @brief 各面に異なる色を付けられる立方体
class ColorfulCube
{
private:
// 座標
Array<Vec3> unitBoxPos; // 原点から各面への単位法線ベクトル
Array<Vec3> boxPos; // 実際の座標を保持する
// 辺の長さ
Array<Vec3> unitEdgeLength; // 基準となる大きさ
Array<Vec3> edgeLength; // 実際の辺の長さを保持する
double size; // 倍率
Vec3 center; // 中心座標
Array<Color> colors; // 各面の色
static constexpr double thickness = 0.005; // Boxの厚さ
public:
// デフォルトコンストラクタ
ColorfulCube() : ColorfulCube(Array<Color>{6, Palette::White}, 1, Vec3::Zero())
{
}
/// @brief コンストラクター(Array<Color>による初期化)
/// @param _colors 各面の色
/// @param _size 倍率
/// @param _center 中心座標
ColorfulCube(const Array<Color>& _colors, const double& _size = 1, const Vec3& _center = Vec3::Zero())
: colors(_colors),
size(_size),
center(_center),
unitBoxPos({ {1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1} }),
unitEdgeLength({ {thickness, 1, 1}, {thickness, 1, 1}, {1, thickness, 1}, {1, thickness, 1}, {1, 1, thickness}, {1, 1, thickness} }),
boxPos(unitBoxPos.size()),
edgeLength(unitEdgeLength.size())
{
}
/// @brief コンストラクタ(色をひとつずつ初期化)
/// @param x0 +X側の色
/// @param x1 -X側の色
/// @param y0 +Y側の色
/// @param y1 -Y側の色
/// @param z0 +Z側の色
/// @param z1 -Z側の色
/// @param _size 倍率
/// @param _center 中心座標
ColorfulCube(const Color& x0, const Color& x1, const Color& y0, const Color& y1, const Color& z0, const Color& z1, const double& _size = 1, const Vec3& _center = Vec3::Zero())
: ColorfulCube(Array<Color>{x0, x1, y0, y1, z0, z1}, _size, _center)
{
}
/// @brief 座標を設定する
/// @param _center 中心座標
/// @param _size 倍率
void setPos(const Vec3& _center, double _size)
{
// メンバ変数を更新
center = _center;
size = _size;
for (int32 i : step(6))
{
boxPos[i] = unitBoxPos[i] * (size + thickness) / 2 + center; // Cubeの厚さと中心からの距離/2を加算
edgeLength[i] = unitEdgeLength[i] * size;
}
}
/// @brief cubeを描画する
/// @param _center 中心座標
/// @param _size 倍率
void draw(const Vec3& _center, double _size, bool needUpdate = true)
{
if (needUpdate)
{
setPos(_center, _size);
}
for (int32 i : step(6))
{
Box(boxPos[i], edgeLength[i]).draw(colors[i]);
Box(boxPos[i], edgeLength[i]).drawFrame(Palette::White);
}
}
/// @brief axis周りの回転 (面の色を入れ替える)
/// @param axis 回転軸
/// @param angle 回転角 [0,270]
ColorfulCube rotate(Vec3 axis, int angle)
{
// {1,0,0}->0,{0,1,0}->3,{0,0,1}->6 =>rotateCubeindicesにおいて各軸の先頭になる
int32 axisIndex = static_cast<int32>(Abs(axis.x + axis.y * 3 + axis.z * 6));
// axisが正方向ならそのまま、負方向なら角度反転(90->270,270->90)
angle = static_cast<int32>(Abs(angle + 360 * (axis.x + axis.y + axis.z))) % 360;
// rotateCubeIndicesのindex
int arrayIndex = angle / 90 + axisIndex - 1; // 0basedにする
Array<Color> tmpColors(6);
for (int32 i : step(6))
{
tmpColors[i] = colors[rotateCubeIndices[arrayIndex][i]];
}
return ColorfulCube(tmpColors, size, center);
}
Array<Vec3> getBoxPos() const
{
return boxPos;
}
Array<Vec3> getEdgeLength() const
{
return edgeLength;
}
Array<Color> getColors() const
{
return colors;
}
};
void Main()
{
// ウィンドウの設定
Window::Resize(1280, 720);
const ColorF backgroundColor = ColorF{ 0.4, 0.6, 0.8 }.removeSRGBCurve();
const MSRenderTexture renderTexture{ Scene::Size(), TextureFormat::R8G8B8A8_Unorm_SRGB, HasDepth::Yes };
DebugCamera3D camera{ renderTexture.size(), 30_deg, Vec3{30, 30, 30}, Vec3{0, 0, 0} };
// ColorfulCubeのインスタンスを作成
Array<Color> colors{ Palette::Green, Palette::Blue, Palette::White, Palette::Yellow, Palette::Red, Palette::Orangered };
ColorfulCube colorfulCube(colors);
Array<std::tuple<String, Vec2, Vec3, int32>> buttons
{
{U"90_deg around X axis", Vec2{100, 100}, Vec3::UnitX(), 90},
{U"180_deg around X axis", Vec2{100, 150}, Vec3::UnitX(), 180},
{U"270_deg around X axis", Vec2{100, 200}, Vec3::UnitX(), 270},
{U"90_deg around Y axis", Vec2{100, 250}, Vec3::UnitY(), 90},
{U"180_deg around Y axis", Vec2{100, 300}, Vec3::UnitY(), 180},
{U"270_deg around Y axis", Vec2{100, 350}, Vec3::UnitY(), 270},
{U"90_deg around Z axis", Vec2{100, 400}, Vec3::UnitZ(), 90},
{U"180_deg around Z axis", Vec2{100, 450}, Vec3::UnitZ(), 180},
{U"270_deg around Z axis", Vec2{100, 500}, Vec3::UnitZ(), 270},
};
while (System::Update())
{
// デバッグカメラの更新 (カメラの移動スピード: 2.0)
camera.update(2.0);
Graphics3D::SetCameraTransform(camera);
// 3D描画の準備
const ScopedRenderTarget3D target{ renderTexture.clear(backgroundColor) };
// ColorfulCubeの描画
colorfulCube.draw({ 5, 5, 5 }, 5);
// 3D シーンを 2D シーンに描画
{
Graphics3D::Flush();
renderTexture.resolve();
Shader::LinearToScreen(renderTexture);
}
for (int32 i : step(buttons.size()))
{
if (SimpleGUI::Button(std::get<0>(buttons[i]), std::get<1>(buttons[i]), 240))
{
colorfulCube = colorfulCube.rotate(std::get<2>(buttons[i]), std::get<3>(buttons[i]));
}
}
}
}