很难解释我的程序出了什么问题,所以我制作了一个视频来直观地向您展示 https://youtu.be/j8yrB2BQUrI
如视频所示,涉及 y 轴和 z 轴旋转的旋转无法正常工作。我添加了下面的代码,我知道我添加了很多代码,非常抱歉。
rotateX/Y/Z 函数只是更新每个立方体的旋转结构,就是这样,所以我没有添加该代码。对于这个写得不好的问题,我很抱歉,我只是尝试了我能想到的一切,但无法让它工作
`
private async void L(int n) //This is a working function
{
for (int i = 0; i < 15 * n; i++)
{
cube[0].rotateX(6 *DEGREE);
cube[1].rotateX(6 * DEGREE); //rotates the left face of the cube 90 degrees
cube[2].rotateX(6 * DEGREE);
cube[9].rotateX(6 * DEGREE);
cube[10].rotateX(6 * DEGREE);
cube[11].rotateX(6 * DEGREE);
cube[17].rotateX(6 * DEGREE);
cube[18].rotateX(6 * DEGREE);
cube[19].rotateX(6 * DEGREE);
Invalidate(rec);
await Task.Delay(1);
}
cube[0].rotateX(-90 * DEGREE); // here it quickly rotates the cube back to how it was originally
cube[1].rotateX(-90 * DEGREE);
cube[2].rotateX(-90 * DEGREE);
cube[9].rotateX(-90 * DEGREE);
cube[10].rotateX(-90 * DEGREE);
cube[11].rotateX(-90 * DEGREE);
cube[17].rotateX(-90 * DEGREE);
cube[18].rotateX(-90 * DEGREE);
cube[19].rotateX(-90 * DEGREE);
CubeFaces = Rotations.L(1, CubeFaces); // this changes the colours of the left face and then updates the display
Invalidate(rec); // to make it seem as if the cube has rotated
}
private async void R(int n) // this is also a working function
{
for (int i = 0; i < 15 * n; i++)
{
cube[6].rotateX(-6 * DEGREE);
cube[7].rotateX(-6 * DEGREE);
cube[8].rotateX(-6 * DEGREE);
cube[14].rotateX(-6 * DEGREE);
cube[15].rotateX(-6 * DEGREE);
cube[16].rotateX(-6 * DEGREE);
cube[23].rotateX(-6 * DEGREE);
cube[24].rotateX(-6 * DEGREE);
cube[25].rotateX(-6 * DEGREE);
await Task.Delay(1);
Invalidate(rec);
}
cube[6].rotateX(90 * DEGREE);
cube[7].rotateX(90 * DEGREE);
cube[8].rotateX(90 * DEGREE);
cube[14].rotateX(90 * DEGREE);
cube[15].rotateX(90 * DEGREE);
cube[16].rotateX(90 * DEGREE);
cube[23].rotateX(90 * DEGREE);
cube[24].rotateX(90 * DEGREE);
cube[25].rotateX(90 * DEGREE);
CubeFaces = Rotations.R(1, CubeFaces);
Invalidate(rec);
}
private async void U(int n) // this function does not work. you will see why when i run it
{
for (int i = 0; i < 15 * n; i++)
{
cube[0].rotateY(6 * DEGREE);
cube[3].rotateY(6 * DEGREE);
cube[6].rotateY(6 * DEGREE);
cube[9].rotateY(6 * DEGREE);
cube[12].rotateY(6 * DEGREE);
cube[14].rotateY(6 * DEGREE);
cube[17].rotateY(6 * DEGREE);
cube[20].rotateY(6 * DEGREE);
cube[23].rotateY(6 * DEGREE);
//cube[0].rotateX(cube[0].GetRotation().z);
//cube[3].rotateX(-rotation.x);
//cube[6].rotateX(-rotation.x);
//cube[9].rotateX(-rotation.x);
//cube[12].rotateX(-rotation.x);
//cube[14].rotateX(-rotation.x);
//cube[17].rotateX(-rotation.x);
//cube[20].rotateX(-rotation.x);
//cube[23].rotateX(-rotation.x);
await Task.Delay(1);
Invalidate();
}
}
private async void F(int n) // this also doesnt work and you will see why when i run it
{
for (int i = 0; i < 15 * n; i++)
{
cube[0].rotateZ(6 * DEGREE); // so the x axis rotations work however the y and z do not
cube[1].rotateZ(6 * DEGREE);
cube[2].rotateZ(6 * DEGREE);
cube[3].rotateZ(6 * DEGREE);
cube[4].rotateZ(6 * DEGREE);
cube[5].rotateZ(6 * DEGREE);
cube[6].rotateZ(6 * DEGREE);
cube[7].rotateZ(6 * DEGREE);
cube[8].rotateZ(6 * DEGREE);
await Task.Delay(1);
Invalidate();
}
//cube[0].rotateZ(-90 * DEGREE);
//cube[1].rotateZ(-90 * DEGREE);
//cube[2].rotateZ(-90 * DEGREE);
//cube[3].rotateZ(-90 * DEGREE);
//cube[4].rotateZ(-90 * DEGREE);
//cube[5].rotateZ(-90 * DEGREE);
//cube[6].rotateZ(-90 * DEGREE);
//cube[7].rotateZ(-90 * DEGREE);
//cube[8].rotateZ(-90 * DEGREE);
//CubeFaces = Rotations.F(1, CubeFaces);
}
`
我尝试执行 U 函数中注释掉的操作,我认为它可以抵消立方体以奇怪的方式旋转,但这只会让情况变得更糟
您需要使用四元数旋转,否则您最终会得到“guimbal effetc”。 四元数可以根据轴/角度计算并且是累积的。你只需要这样做:
然后旋转:
取决于您是否想要在局部空间或全局空间中旋转。
您可以在 Git 上找到示例。
好吧,让我们在这里写下一些定义。
如何跟踪和识别 26/27 块中的哪一块实际上取决于您,所以我假设您已经完成了工作......
每一块都有一个当前位置和一个当前方向。有一种很好的方法可以在一个完整的实体中表示所有这些信息,那就是 4x4 矩阵(存储单独的平移和欧拉旋转可能是您的错误!)。应该提到的是,你可以代表那些具有位置+四元数的人,但这并不是真正需要的。
最初,对于这 27 件作品,它们都具有相同的方向,但翻译值不同。所以首先,初始化这些转换。
mat4x4 block_orientations[3 * 3 * 3];
for(int z = 0; z < 3; ++z) {
for(int y = 0; y < 3; ++y) {
for(int x = 0; x < 3; ++x) {
int index = z * 9 + y * 3 + x;
block_orientations[index] = mat4x4_translate_matrix(x-1, y-1, z-1);
}
}
}
您还有 9 个旋转平面和关联的枢轴点。
enum CubeRotationPlane {
XMin,
XMid,
XMax,
YMin,
YMid,
YMax,
ZMin,
ZMid,
ZMax,
};
vec4 pivot_points[9] {
// pivots along the x axis
{-1, 0, 0, 1},
{0, 0, 0, 1},
{1, 0, 0, 1},
// pivots along the y axis
{0, -1, 0, 1},
{0, 0, 0, 1},
{0, 1, 0, 1},
// pivots along the z axis
{0, 0, -1, 1},
{0, 0, 0, 1},
{0, 0, 1, 1},
};
从数学上正确的意义上来说,为了转换这些块,你应该做:
在代码中,这看起来像:
mat4x4 inverse_pivot = translateMatrix(-pivot);
mat4x4 rotation = computeYourRotationOffsetAsMatrix();
mat4x4 pivot = translateMatrix(pivot);
// this assumes the multiplication order of (child * parent),
// reverse if your lib is (parent * child).
mat4x4 final = inverse_pivot * rotation * pivot;
然而,在这种情况下,由于您仅使用轴对齐旋转,因此您实际上可以完全跳过枢轴点,直接跳到旋转......
void compute_transforms_for_9_blocks_to_be_moved(
CubeRotationPlane plane, ///< the plane of the cube being rotated
int block_indices[9], ///< the 9 blocks that need to be rotated
mat4x4 initial_block_orientations[3 * 3 * 3],
mat4x4 current_block_orientations[3 * 3 * 3],
float degrees) {
// the rotation to apply
mat4x4 rotate_matrix;
if(plane < yMin) {
// rotating around X
rotate_matrix = mat4x4_rotateX(degrees * M_PI / 180);
}
else
if(plane < zMin) {
// rotating around Y
rotate_matrix = mat4x4_rotateY(degrees * M_PI / 180);
}
else
if(plane) {
// rotating around Z
rotate_matrix = mat4x4_rotateZ(degrees * M_PI / 180);
}
// copy prior values
memcpy(current_block_orientations,
initial_block_orientations,
sizeof(mat4x4) * 27);
// now update the 9 blocks that are in motion...
for(int i = 0; i < 9; ++i) {
int index = block_indices[i];
current_block_orientations[index] =
initial_block_orientations[index] * rotate_matrix;
}
}
这假设动画完成后,您将更新整组矩阵。
或者,您可以指定上面的旋转1度,然后返回最终矩阵(如果您只想在动画时累积变换,避免使用临时数组)。然而,这样做可能会随着时间的推移积累浮点误差。
必须认识到,您必须存储块的累积变换。您在上面的代码中看到的问题是您有一个 XYZ 欧拉旋转顺序(并且您只是更新欧拉值)。因此,这适用于 X 和 Z 旋转,但是一旦您触摸中间旋转,Z 轴就不再位于其原始平面中,并且事情开始出错!