【问题标题】:Rotate Object around origin as it faces origin in OpenGL with GLM?使用GLM在OpenGL中面向原点时围绕原点旋转对象?
【发布时间】:2019-03-17 04:15:46
【问题描述】:

我正在尝试制作一个简单的动画,其中一个对象使用 glm lib 在 OpenGL 中围绕世界原点旋转。我的想法是:

  • 将对象发送到原点

  • 旋转它

  • 回原位

  • 让它看我想要的

这是我的实现:

// Rotates object around point p
void rotate_about(float deltaTime, glm::vec3 p, bool ended) {

    glm::vec3 axis = glm::vec3(0,1,0); //rotation axis
    glm::mat4 scale_m = glm::scale(glm::mat4(1.0f), glm::vec3(scale, scale, scale)); //scale matrix
    glm::mat4 rotation = getMatrix(Right, Up, Front, Position); //builds rotation matrix

    rotation = glm::translate(rotation, p - Position );
    rotation = glm::rotate(rotation, ROTATION_SPEED * deltaTime, axis);
    rotation = glm::translate(rotation, Position - p );

    Matrix = rotation * scale_m;

    //look at point P
    Front = glm::normalize(p - start_Position);
    Right = glm::normalize(glm::cross(WorldUp, Front));
    Up = glm::normalize(glm::cross(Right, Front));

    if (ended == true) { //if last iteration of my animation: saves position
        Position.x = Matrix[3][0];
        Position.y = Matrix[3][1];
        Position.z = Matrix[3][2];  
    }
}

getMatrix() 只返回一个 4x4 矩阵:

| Right.x Right.y Right.z |
| Up.x    Up.y    Up.z    |
| Front.x Front.y Front.z |
| Pos.x   Pos.y   Pos.z   |

我使用这张图片作为参考:

当我开始动画时,我的模型就消失了。如果我删除下面的行"//look at point P" 它会围绕原点旋转,但每次我的动画重新启动时都会抽搐。我猜我正在丢失或混合我不应该在某处的信息。 如何存储我的模型前/右/上信息,以便我可以从头开始重建它的矩阵?

第一次编辑,这是我不尝试让我的模型看点 P 时的效果,在这种情况下是原点。当我尝试时,我的模型消失了。如何让它看起来我想要的位置,以及在我完成旋转后如何让我的模型获得新的 Front/Right/Up 向量?

This是我在上面的gif中运行的代码

【问题讨论】:

  • 先绕外轴旋转(MR1矩阵)。然后平移模型 (MT)。然后绕其自身垂直轴 (MR2) 旋转。组合运动通过 MFInal = MR2 x MT x MR1 实现。矩阵的顺序很重要。
  • 那会让我的模型直面问题?如果是这样,我应该在动画之后保留什么信息,以便我可以将它放置在另一个旋转的位置(从它停止的地方继续)?
  • angleE外旋后,你可以知道你模型的中心在哪里,一个简单的positionNew= matrix x positionOld乘法。使用这个新位置和angleE,您可以计算应用于自旋转的角度。只需存储下一个动作的位置和当前自身角度。
  • 使用这种方法,我必须为每个轴 (x,y,z) 存储一个自角度,然后创建 3 个旋转矩阵?
  • @MatheusIanzer 在Right-handed 系统中,它必须是 [Right = glm::normalize(glm::cross(Front, WorldUp));]`。但目前还不清楚你想要实现什么。

标签: c++ opengl matrix rotation glm-math


【解决方案1】:

glm::translate()glm::roate() 等操作通过其参数构建矩阵并将输入矩阵乘以新矩阵

这意味着

rotation = glm::translate(rotation, Position - p );

可以表示为(伪代码):

rotation = rotation * translation(Position - p);

注意,矩阵乘法必须从左到右“读取”。 (见GLSL Programming/Vector and Matrix Operations

translate * rotate 操作导致围绕对象原点旋转:

rotate * translate 操作导致围绕世界原点旋转:

矩阵glm::mat4 rotation(在您问题的代码中)是您对象的当前模型矩阵。
它包含对象的位置(平移)和方向。
您想围绕世界的原点旋转对象。

为此,您必须创建一个包含新旋转的矩阵

glm::mat4 new_rot = glm::rotate(glm::mat4(1.0f), ROTATION_SPEED * deltaTime, axis);

那么就可以计算出最终的矩阵如下:

Matrix = new_rot * rotation * scale_m;

如果你想围绕一个点p 旋转一个对象并且对象应该总是面对一个点p,那么你只需要对象的位置(start_position)和旋转轴。 在您的情况下,旋转轴是世界的向上向量。

glm::vec3 WorldUp( 0.0f, 1.0f, 0.0f );
glm::vec3 start_position = ...;
float scale = ...;
glm::vec3 p = ...;

计算旋转矩阵和新的(旋转的)位置

glm::mat4 rotate    = glm::rotate(glm::mat4(1.0f), ROTATION_SPEED * deltaTime, WorldUp);
glm::vec4 pos_rot_h = rotate * glm::vec4( start_position - p, 1.0f );
glm::vec3 pos_rot   = glm::vec3( pos_rot_h ) + p;

计算对象应该“看”的方向

glm::vec3 Front    = glm::normalize(p - pos_rot);

您可以使用您的函数getMatrix 来设置对象的当前方向矩阵:

glm::vec3 Right    = glm::normalize(glm::cross(WorldUp, Front));
glm::mat4 pos_look = getMatrix(Right, WorldUp, Front, pos_rot);

计算模型矩阵:

glm::mat4 scale_m = glm::scale(glm::mat4(1.0f), glm::vec3(scale));
Matrix = pos_look * scale_m;

最终代码可能如下所示:

glm::mat4 getMatrix(const glm::vec3 &X, const glm::vec3 &Y, const glm::vec3 &Z, const glm::vec3 &T)
{
    return glm::mat4(
        glm::vec4( X, 0.0f ),
        glm::vec4( Y, 0.0f ),
        glm::vec4( Z, 0.0f ),
        glm::vec4( T, 1.0f ) );
}

void rotate_about(float deltaTime, glm::vec3 p, bool ended) {

    glm::mat4 rotate    = glm::rotate(glm::mat4(1.0f), ROTATION_SPEED * deltaTime, WorldUp);
    glm::vec4 pos_rot_h = rotate * glm::vec4( start_position - p, 1.0f );
    glm::vec3 pos_rot   = glm::vec3( pos_rot_h ) + p;

    glm::vec3 Front    = glm::normalize(p - pos_rot);
    glm::vec3 Right    = glm::normalize(glm::cross(WorldUp, Front));
    glm::mat4 pos_look = getMatrix(Right, WorldUp, Front, pos_rot);

    glm::mat4 scale_m = glm::scale(glm::mat4(1.0f), glm::vec3(scale));
    Matrix = pos_look * scale_m;

    if ( ended == true )
        Position = glm::vec3(Matrix[3]);
}

【讨论】:

  • 感谢您的回答,Rabbid76。但我对你的建议也有同样的行为。我的主要问题是让我的模型在围绕一个点旋转时查看我想要的位置。我编辑了我的问题,以便更清楚地说,如果你能看一下,我会很高兴。
  • @MatheusIanzer 我扩展了答案
【解决方案2】:

解决方案:

问题出在这部分:

rotation = glm::translate(rotation, p - Position ); 
rotation = glm::rotate(rotation, ROTATION_SPEED * deltaTime, axis);
rotation = glm::translate(rotation, Position - p );


if (ended == true) { //if last iteration of my animation: saves position
    Position.x = Matrix[3][0];
    Position.y = Matrix[3][1];
    Position.z = Matrix[3][2];  
}

请注意,我使用世界原点和模型之间的距离作为平移半径。然而,在动画结束后,我更新了模型位置,这改变了p - Position 的结果,即轨道半径。当这种情况发生时,模型会“抽搐”,因为它丢失了旋转信息。

我通过对轨道半径使用不同的变量并在模型的z-axis 上应用平移来解决它。当在 x 轴上应用平移时,最初面向相机的模型最终会侧向 移动到原点。但是,根据信号,在 z 轴上应用平移最终会使模型面向或向后指向原点。

【讨论】:

    猜你喜欢
    • 2020-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多