如何在全局轴上旋转图形,而不是局部轴?

Posted

技术标签:

【中文标题】如何在全局轴上旋转图形,而不是局部轴?【英文标题】:How to rotate a graphic over global axes, and not to local axes? 【发布时间】:2013-04-27 00:12:52 【问题描述】:

我认为我的问题很简单,但我是 Opengl 的新手,我不知道该怎么办。

我正在尝试旋转金字塔(数字无关紧要),我想相对于 X 旋转 然后相对于 Y 轴旋转。

但是当我在 X 上旋转时,Y 轴也会旋转。然后当我想相对于 Y 旋转一点时,Y 轴不再是原来的了。

下一张图片显示了米金字塔在原点的星形:

然后相对于 X 旋转 winth:

Y轴和Z轴也旋转,然后如果我想相对于Y旋转,金字塔相对于旋转的Y轴旋转,而不是原来的Y轴旋转(深绿色)。

我使用 PushMatrix();和流行矩阵(); :

gl.PushMatrix();             
    gl.Rotate(bx, 1.0f, 0.0f, 0.0f);           

        gl.PushMatrix();
        gl.Rotate(by, 0.0f, 1.0f, 0.0f); 

            //Pyramid                      
            gl.Begin(OpenGL.GL_TRIANGLES);
            gl.Color(1.0f, 0.0f, 0.0f);
            gl.Vertex(0.0f, 1.0f, 0.0f);
            gl.Vertex(-1.0f, -1.0f, 1.0f);
            gl.Vertex(1.0f, -1.0f, 1.0f);

             gl.Color(0.0f, 1.0f, 0.0f);
             gl.Vertex(0.0f, 1.0f, 0.0f);
             gl.Vertex(1.0f, -1.0f, 1.0f);
             gl.Vertex(1.0f, -1.0f, -1.0f);

             gl.Color(0.0f, 0.0f, 1.0f);
             gl.Vertex(0.0f, 1.0f, 0.0f);
             gl.Vertex(1.0f, -1.0f, -1.0f);
             gl.Vertex(-1.0f, -1.0f, -1.0f);

             gl.Color(1.0f, 1.0f, 1.0f);
             gl.Vertex(0.0f, 1.0f, 0.0f);
             gl.Vertex(-1.0f, -1.0f, -1.0f);
             gl.Vertex(-1.0f, -1.0f, 1.0f);
             gl.End();

         gl.PopMatrix();
   gl.PopMatrix();

bxby 只是在您单击按钮时增加或减少角度(现在 Z 无关紧要)

我想相对于 X 和 Y 旋转金字塔,但原始轴(万向轴)独立于局部轴。

注意:我使用的是 SharpGL(用于 c# 的 OpenGL),但它是一样的。

更新

我更改了我的代码:

gl.PushMatrix();             
    gl.Rotate(bx, 1.0f, 0.0f, 0.0f);           

      gl.PushMatrix();
       //gl.Rotate(by, 0.0f, 1.0f, 0.0f); This changes
        gl.Rotate(by, 0.0f, Math.Cos(bx*Math.PI / 180), -Math.Sin(bx*Math.PI / 180));           
         //Pyramid                      

      gl.PopMatrix();
 gl.PopMatrix();

我乘以矩阵Rx逆[1 0 0; 0 余弦; 0 -Sin Cos] 由向量 Y [0 1 0] 得到,得到的向量 [0 Cos -Sin] 由 Y 旋转。

这按我的意愿工作,我按 X 旋转,在按 Y 旋转之后,但是当我按 X 再旋转时,现在旋转是按 X 旋转而不是相对于原始旋转!!!,但 Y 的旋转保持不变。

还有什么想法吗??非常感谢!!!

【问题讨论】:

您必须将全局x 轴解析为局部坐标才能进行旋转。 【参考方案1】:

操作的顺序很重要,根据 OpenGL 中使用的语义,实际转换的应用顺序与它们在代码中发生的顺序相反。因此,如果您想先按 X 旋转,然后按 Y 旋转,则 Y 旋转必须在您的代码中排在第一位。

更深层的原因是 OpenGL 使用(出于各种合理的原因)列主要的右关联矩阵排序。像

这样的转换链
MV = V · M · R_x · R_y

将在列(位置)向量中从右向左相乘,即

MV · ↑v

分解成

V · ( M · ( R_x · ( R_y · ↑v ) ) )

并且由于矩阵不是阿贝尔矩阵,因此有无数个矩阵 A、B

A · B =/= B · A

【讨论】:

如果我先按 Y 旋转,我会遇到同样的问题,但现在 X 轴旋转了,它不是原来的。我只想按原来的 X 和 Y 旋转,与应用的旋转无关 @Johnnie90:嗯,当您使用 OpenGL 内置函数应用变换时,它会修改相对于下一个变换的局部坐标系。对于您想要的,您必须执行左侧乘法。如果您想为此使用 OpenGL 的矩阵数学函数,这将非常麻烦。更简单的解决方案是使用一些真正的矩阵数学库,如 GLM、Eigen 或我的 linmath.h。如果您查看上面的方程式,您会在 M 之后插入每个新的旋转【参考方案2】:

我最近遇到了这个问题并最终得到了这个解决方案:

    使用 glRotate(bx,1f,0f,0f); 围绕局部 x 轴旋转。 计算局部坐标系ux=0uy=cos(bx)uz=sin(bx)中的全局y轴分量。 使用glRotate(by,ux,uy,uz); 围绕局部轴旋转。

注意需要的函数是

Func<float,float> cos = (x)=>(float)(Math.Cos(x*Math.PI/180));
Func<float,float> sin = (x)=>(float)(Math.Sin(x*Math.PI/180));

要将角度转换为弧度,取 sin 和 cos 并返回一个浮点数。

【讨论】:

谢谢,但这不起作用,旋转尊重 Y 不是原始 Y。 我修复了一个错误。 uz=sin(bx) 而不是 uz=sin(by)。我的错。这应该可以解决 OP 问题。

以上是关于如何在全局轴上旋转图形,而不是局部轴?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用按钮在一个轴上停止旋转并在新轴上开始旋转?

在局部轴 Godot 上的弧之间旋转自身

SceneKit:如何将节点的移动限制在本地的一个轴上,而不是整个世界

在matlab画出三维球面并绕轴旋转一定角度

搅拌机轴在其中心点旋转

如何让相机的垂直旋转使相机上下移动?