【问题标题】:OpenGL transforming objects with multiple rotations of Different axisOpenGL转换具有不同轴多次旋转的对象
【发布时间】:2017-12-18 21:04:43
【问题描述】:

我正在构建一个建模程序,我想对它们自己空间中的对象进行转换,然后将该单个对象分配给一个组以围绕该组旋转的另一个轴旋转。但是,我还希望能够在对象自身的空间中进行转换。

操纵单个对象,我选择对象的中心。

glm::mat4 transform;
transform = glm::translate(transform, - obj.meshCenter);
glm::mat4 transform1;
transform1 = glm::translate(transform1, obj.meshCenter);
obj.rotation =  transform1*obj.thisRot*transform;

然后我将它发送到着色器,

glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(obj.translation*obj.rotation*objscale);

我现在想围绕另一个轴旋转这个对象,比如 45 度的 (5,0,0) 轴。

我现在有:

glm::mat4 groupR;
groupR = glm::rotate(groupR,glm::degrees(45.0f),glm::vec3(5,0,0));
obj.groupRotation = groupR;
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, 
glm::value_ptr(obj.groupRotation*obj.translation*obj.rotation*objscale)

我现在已将对象从其本地空间移动到组空间。 当与 Group 的旋转相结合时,我现在在对象自己的空间中操作转换有点困难。 当我像这样将 groupR 轴设置为 (0,1,0) 时,我的成功有限:

///Translating object in its own space///
glm::mat4 R = obj.groupRotation;
obj.translation = glm::inverse(R) * obj.translate * R;

这里的问题是,如果 R 的旋转轴(组的旋转)等于 (0,1,0),这只会在其自己的空间中正确平移对象:

///Rotating object in its own space///
glm::mat4 R = obj.groupRotation;
obj.rotation = glm::inverse(R) * obj.rot * R;

再一次,旋转不正确。我在想也许我必须撤消 groupR 的轴平移?然后在某个地方重新应用它?

【问题讨论】:

  • 我试图做的是撤消 groupRotation 以便我的本地变换计算正确。上面的逆操作会将旋转和平移(尚未尝试缩放)返回到本地空间。挂断是如果 groupRotation 的轴不在原点。我将尝试将轴位置的反向平移插入到上面的矩阵乘法中。我只是不确定它应该是什么顺序,或者它是否会起作用。不过我会在早上好好尝试一下。
  • 不能直接修改obj.thisRot,重新计算组合变换吗?这将不太容易出错。顺便说一句,我不会指望glm::value_ptr() 为在调用glm::value_ptr() 后立即删除的临时对象返回有效地址。

标签: c++ opengl rotation glm-math coordinate-transformation


【解决方案1】:

假设我们有一个被移动、旋转和缩放的对象,我们定义一个变换矩阵如下:

glm::mat4 objTrans ...; // translation 
glm::mat4 objRot ...;   // roation 
glm::mat4 objScale ...; // scaling

glm::mat4 objMat = objTrans * objRot * objScale;

我们有想要在对象上运行的旋转矩阵。在这种情况下,我们围绕 Z 轴旋转:

foat angle ...; // rotation angle

glm::mat4 rotMat = glm::rotate( angle, glm::vec3( 0.0, 0.0, 1.0 ) ); 

我们可以利用这些信息进行多次轮换。 首先我们要在其局部轴上旋转对象:

glm::mat4 modelMat = objMat * rotMat;

可以像这样执行绕世界原点的旋转:

glm::mat4 modelMat = rotMat * objMat;

为了在世界坐标系中围绕物体的原点旋转,我们必须消除物体的旋转:

glm::mat4 modelMat = objMat * (glm::inverse(objRot) * rotMat * objRot);

相对于对象的绕世界原点的旋转,您必须做相反的事情:

glm::mat4 modelMat = (objRot * rotMat * glm::inverse(objRot)) * objMat;

如果你有一个对象的完整变换矩阵,而你不知道旋转部分,那么它可以很容易地确定。

请注意,转换矩阵通常如下所示:

( X-axis.x, X-axis.y, X-axis.z, 0 )
( Y-axis.x, Y-axis.y, Y-axis.z, 0 )
( Z-axis.x, Z-axis.y, Z-axis.z, 0 )
( trans.x,  trans.y,  trans.z,  1 )

要生成仅旋转矩阵,您必须提取归一化的轴向量:

glm::mat4 a ...; // any matrix
glm::vec3 x = glm::normalize( a[0][0], a[0][1], a[0][2] );
glm::vec3 y = glm::normalize( a[1][0], a[1][1], a[1][2] );
glm::vec3 z = glm::normalize( a[2][0], a[2][1], a[2][2] );

glm::mat4 r;
r[0][0] = x[0]; r[0][1] = x[1]; r[0][2] = x[2]; r[0][3] = 0.0f;
r[1][0] = y[0]; r[1][1] = y[1]; r[1][2] = y[2]; r[0][3] = 0.0f;
r[2][0] = z[0]; r[2][1] = z[1]; r[2][2] = z[2]; r[0][3] = 0.0f;
r[3][0] = 0.0f; r[3][1] = 0.0f; r[3][2] = 0.0f; r[0][3] = 1.0f; 

【讨论】:

  • 嗨兔子,感谢您的帮助。我想也许我没有很好地解释这个问题。如果我将问题简化为 (obj.groupRot* obj.translate* (obj.rot = identity) * (obj.scale = identity)。例如,平移和/或缩放将受到 GroupRot 的影响。那是我尝试将我的所有对象变换矩阵乘以 obj.groupRotation 逆以使其进入对象空间的原因,正常执行我的变换,然后乘以 obj.groupRotation 回到正确的空间。obj.groupRotation 的原点位置似乎成为问题。
【解决方案2】:

这是我想要的行为和我使用的设置的部分答案。这似乎是我需要做的才能在对象空间中获得正确的变换,同时除了组旋转。 这里我有一个由 7 个不同的单独网格组成的模型,这些网格围绕 y 轴上 (0,5,0) 的原点旋转,这只是我选择用于测试的任意旋转。

 for (int i = 0; i < models.at(currentSelectedPointer.x)->meshes.size()i++)
    {
    glm::mat4 rotMat;
    rotMat = glm::translate(rotMat, glm::vec3(5, 0, 0));
    rotMat = glm::rotate(rotMat, f, glm::vec3(0, 1.0, 0.0));
    rotMat = glm::translate(rotMat, glm::vec3(-5, 0, 0));
    models.at(currentSelectedPointer.x)->meshes.at(i).groupRotation = rotMat;
    }

所有网格现在作为一个组围绕 (0,5,0) 旋转,而不是在 Y 轴上的 (0,5,0)。

要在其自己的对象空间中对单个对象进行正确的旋转变换,我必须撤消 groupRotation 原点的位置(对不起,代码混乱,但我是按这样的步骤进行的,以保持一切分离和轻松可剖析)。此外,单个对象的平移和缩放都有一个单位矩阵。

     //These will be used to shift the groupRotation origin back to the 
     // origin in order to rotate around the object's origin.

     glm::mat4 gotoGroupAxis;
     gotoGroupAxis= glm::translate(gotoGroupAxis, glm::vec3(5, 0, 0));
     glm::mat4 goBack ;
     goBack = glm::translate(goBack , glm::vec3(-5, 0, 0));

     ////////Group rotation and it's inverse        
     glm::mat4 tempGroupRot = goBack *obj.groupRotation*gotoGroupAxis;
     glm::mat4 tempGroupRotInverse= glm::inverse(tempGroupRot);

     //thisRot and lastRot are matrix variables I use to accumulate and 
     //save rotations       
     obj.thisRot = tempGroupRotInverse* 
     glm::toMat4(currentRotation)*tempGroupRot * 
     obj.lastRot;

     //now I translate the object's rotation origin to it's center.

     glm::mat4 transform = glm::translate(transform, -obj.meshCenter);
     glm::mat4 transform1 = glm::translate(transform1, obj.meshCenter);
     //Finally I rotate the object in it's own space.
     obj.rotation =  transform1*obj.thisRot*transform;

更新:

 //Translation works as well with
 obj.finalTranslation= tempGroupRotInverse* 
 obj.translation * tempGroupRot ;

这只是部分答案,因为我将在对象级别和组级别进行转换,而且我几乎可以肯定在答案未考虑到的情况下会出现问题我已经发过了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-15
    • 1970-01-01
    • 1970-01-01
    • 2017-08-24
    相关资源
    最近更新 更多