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
質問が分かりにくくてすみません。

現在はルービックキューブ内部を Box で表現しています。ただ、Box では一つの立方体全体に色が適用され、各面ごとに異なる色を設定できないため、ルービックキューブの1面ずつ9つの Plane に分割して、6面それぞれに異なる色を設定できるようにしたいと考えています。

そして、ルービックキューブの構造上、角のパーツは3色、辺のパーツは2色を持つため、各 Plane の向きや配置もそれに合わせて調整したいです。

どうぞよろしくお願いいたします。
編集
Reputeless  2024/11/05(Tue) 01:47
ルービックキューブを再現できるようサンプルを強化してみたいと思います。
その前に、↑のように、6 つの Plane ではなく 6 つの Box を使うという方向性についてはどうでしょうか。
1 枚 1 枚に回転が必要な Plane よりは簡潔になると思います。
編集
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]));
}
}
}
}
編集
Reputeless  2024/11/05(Tue) 14:30
解決につながったようでよかったです。
将来的にルービックキューブの公式サンプルも用意できればと思います。
編集
件名
Re: Plane自体の回転と3D図形の配置アルゴリズム
名前
コメント
画像添付


投稿修正キー (投稿を修正する時に使います)
画像認証 (右画像の数字を入力) 投稿キー

- WEB PATIO -