winforms rubiks cube animation of face rotation旋转在怪异的方式

3htmauhk  于 2023-10-23  发布在  其他
关注(0)|答案(2)|浏览(90)

很难解释我的程序有什么问题,所以我做了一个视频来直观地向你展示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函数中注解掉的东西,我想它可以抵消立方体以其奇怪的方式旋转,但它只会让它变得更糟

0kjbasz6

0kjbasz61#

你需要使用四元数旋转,否则你会得到“吉姆巴尔效果”。四元数可以从轴/Angular 计算,并且是累积的。你只需要做两件事

  • 为模型“MyQuaternion”定义四元数旋转
  • 计算专用于要执行“RotationQuaternion”的旋转的四元数。

然后旋转:

  • MyQuaternion = MyQuaternion * RotationQuaternion
  • MyQuaternion = RotationQuaternion * MyQuaternion

这取决于你想在局部空间还是全局空间中旋转。
你可以在Git上找到例子。

dy2hfwbg

dy2hfwbg2#

好的,让我们在这里写下一些定义。
1.你有9个独立的旋转平面。
1.即x为3,y为3,z为3。
1.这些旋转平面中的每一个都有自己独特的枢轴点 (然而,沿着每个轴的中间平面沿着已经以原点为中心,因此这些情况更容易,因为枢轴已经在原点)
1.对于这些旋转中的任何一个,您都希望围绕给定的轴应用动画旋转。
1.您有6个中心面 (1种颜色)
1.您有8个角件 (3种颜色)
1.您有12个边片 (2种颜色)
1.有一个没有颜色的中心部分,你可能可以忽略它,但是为了让代码更容易理解,我将假装它存在。
你如何跟踪和识别26/27件中的哪一件真的取决于你,所以我假设你已经工作了。
每个片段都有一个当前位置和当前方向。有一种很好的方法可以在一个完整的实体中表示所有这些信息,那就是4x 4矩阵 (存储单独的平移和欧拉旋转可能是你的错误!)。应该提到的是,你可以用位置+四元数来表示那些,但这里并不需要。
最初,对于这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 Euler旋转顺序 (并且您只是更新Euler值)。所以这将适用于X和Z旋转,但是一旦你接触中间旋转,Z轴不再在它的原始平面,东西开始出错!

相关问题