OpenGL rubiks cube - 用鼠标旋转面部
Posted
技术标签:
【中文标题】OpenGL rubiks cube - 用鼠标旋转面部【英文标题】:OpenGL rubiks cube - face rotation with mouse 【发布时间】:2011-10-27 11:26:35 【问题描述】:我正在开发我的第一个真正的 OpenGL 项目。它是一个 3x3x3 魔方。这是我到目前为止的简单截图的链接(my rubiks cube)
旋转立方体是通过按住鼠标右键拖动鼠标来完成的。这可以使用 NeHe Tutorials(NeHe Arcball) 中的轨迹球示例
我有一个类 singleCubes,它通过 6 个实际四边形表示一个立方体,存储在一个显示列表中,可以在它的绘制方法中使用。 ComplexCube 类有一个 3x3x3 singleCubes 数组,在与完整的魔方交互时用作接口。
现在我想根据鼠标左键向下拖动来旋转每个特定的面。我使用pick来获取用户单击的单个立方体的对应侧的ID。这也有效。因此,我单击一个立方体的一侧,并根据拖动的方向设置受影响的立方体的旋转和偏移因子。 (我也想实现你实际上看到脸部旋转而不是仅仅改变颜色)
现在我的问题是,当我用鼠标右键拖动以任何方向旋转魔方时,它会变成上下颠倒。因此,当我单击一侧并想要将面向右旋转时,它会走向错误的方向,因为我无法跟踪立方体是否颠倒或其他。由于使用了轨迹球旋转,我没有可以用来确定这一点的 x 或 y 旋转角度。
问题 1: 如果立方体倒置、倾斜等,我如何跟踪或稍后获取信息,以便在使用上面链接的轨迹球示例?
// In render function
glPushMatrix();
glMultMatrixf(Transform.M); // Rotation applied by arcball object
complCube.draw(); // Draw all the cubes using display lists
glPopMatrix();
设置:C++ 与 Microsoft Visual Studio 2008、GLEW、freeglut
【问题讨论】:
OpenGL 不是场景图,您将“对象放入其中”。它只是画东西。记账是你的工作。 是的,你是对的。也许是我的错,我没有完全理解 NeHe 的轨迹球示例,因此无法保存立方体的旋转状态。 【参考方案1】:您可以使用 gluUnProject 将鼠标坐标转换为 3d 空间并获得一个向量(两点之间的差异)。然后可以使用该向量对选定的面施加“力”。由于 gluUnProject 使用投影矩阵,它会自动处理相机的方向。
基本上,一旦您获得“力”向量,您就可以将其投影到三个轴上(因此投影到 (1,0,0)、(0,1,0)、(0,0,1))。然后选择幅度最大的那个。然后你必须将此方向转换为旋转轴,如下图所示(抱歉绘画技巧不好):
所以我们得到的是黑色的“力”矢量和灰色的选定魔方面。要获得旋转轴,只需将“力”向量与所选面的法线相乘即可。这给出了红色箭头。从此,您应该能够以正确的方向旋转您的立方体。
编辑以更详细地回答问题
继续我的解释,我将举例说明这将如何帮助您。我们首先假设您的屏幕为 800x800 像素,并且您的魔方始终居中。现在我们还假设,根据您在 cmets 中的图纸,我们处于左侧的情况。
我们拖动鼠标,得到两个位置,使用 gluUnProject 将其转换为世界坐标(选择数字是为了表明我的观点,而不是通过任何计算):
p1 : (600, 600) -> (1, -0.5, 0)
p2 : (630, 605) -> (1.3, -0.505, 0)
现在我们得到差分向量:p2 - p1 = v = (0.3, -0.05, 0)。我说“投影到三个轴上”的原因是为了让您提取主要运动(在这种情况下,x 轴为 0.3)(因为魔方不能沿对角线旋转)。要进行“投影”,您只需分别获取 x、y、z 轴并从中创建向量,这样您就可以得到:
v1 = (0.3, 0, 0)
v2 = (0, -0.05, 0)
v3 = (0, 0, 0)
现在取大小并丢弃最小的向量,所以我们剩下向量 v1 = (0.3, 0, 0)。这是您在世界空间中的运动矢量。现在,您将该向量与所选面的法线向量(在本例中为 (0, 0, 1))相乘。这为您提供了一个指向 (0, 1, 0) (标准化后)的向量(在此步骤中,您可能还必须仅提取最大分量 (0.02, 1.2, 0.8) -> (0, 1, 0)否则,如果你的相机没有直接指向主轴,你会得到奇怪的旋转)。您现在可以使用该向量作为旋转轴并使用 0.3 作为旋转量(如果它以与预期相反的方向旋转,只需输入 -)。
现在,如果您的立方体倒置,这有什么帮助?假设我们以同样的方式点击屏幕。我们现在得到:
p1 : (600, 600) -> (-1, 0.5, 0)
p2 : (630, 605) -> (-1.3, 0.505, 0)
看到世界坐标的差异了吗?他们颠倒了!所以当你取差分向量 p2 - p1 = v = (-0.3, 0.05, 0) 时。提取最大分量向量得到 (-0.3, 0, 0)。再次进行叉积会得到旋转轴,但现在旋转方向相反,这正是您想要的。
与面的法线叉积的另一个原因是,如果您要选择顶部的面(在我们的图纸中),那么它会给出一个沿 x 或 z 轴的旋转轴(到左,或进入屏幕)这是您想要的顶面。
【讨论】:
我假设您的立方体总是与主轴对齐,因此投影轴选择 (1,0,0) (0,1,0) (0,0,1)。 我必须承认我无法完全理解您的解释。所以我基本上从我点击的点到我拖动它的地方得到一个向量。然后我将它投影到三个轴上(虽然不确定如何),最大的幅度是我对旋转的提示?我不确定这是否能解决我的问题。 Here an example 又是我的问题。我很感谢您的解释,但您介意更详细地解释吗?我知道我负责跟踪旋转,但这本身也是使用轨迹球实现时的问题。 谢谢更详细的解释。当我没有旋转立方体时它有点工作。一旦我旋转整个立方体,它就不再起作用了。可以使用 gluPerspective 还是会导致问题(尽管它也不完全适用于 glOrtho)?也许我错过了一些东西。还不会放弃。 gluPerspective 很好用。当你不旋转立方体时,你的意思是什么? 好吧,例如,如果立方体处于起始位置并且我将光标从右中间(6)移动到右侧一个单个立方体大小,我在 x 轴上得到大约 15 的差异(使用时大约为 3正交而不是透视)。因此,当我向我旋转立方体时,我也可以看到顶面,并执行相同的鼠标移动,我在 y 轴上得到一个相当大的(-70)差异,不会导致相同的旋转。同样令人困惑的是,当我不再在立方体上时,鼠标的 z 点当然会变为 -70,使其成为最大量级(所以我有点忽略了这一点)。【参考方案2】:像我们大多数人一样,你会遇到一个著名的问题,叫做万向节锁定。
见:http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=208925
这个问题记录得非常好,所以我没有太多意义在这里详细介绍。我相信你会找到很多关于它的信息。
【讨论】:
我不明白这怎么能以任何的方式回答他的问题。即使万向节锁会对他来说是个问题(考虑到他的陈述,这不是预先确定的),那么这可能是一个更好的评论,因为目前它肯定是不是他的问题。 我确实尝试过四元数(这应该是避免万向节锁定的一种方法)并且它的旋转起作用了。但它对我来说并不完全是轨迹球。(离中点越远,旋转速率越高等)然后我使用了 NeHe 教程中的轨迹球示例(我的第一篇文章中的链接),我认为它会以同样的方式避免它。尽管我不得不承认我不能在数学方面完全遵循它,因此判断它是否真的像我之前的四元数课那样避免了万向节锁定。但在我看来,它会这样。任何对此的法官将不胜感激以上是关于OpenGL rubiks cube - 用鼠标旋转面部的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces1594 E2. Rubik‘s Cube Coloring (hard version)(思维+dp记忆化搜索)