使用GLM在OpenGL中面向对象时围绕对象旋转原点吗?

时间:2018-10-12 01:22:10

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

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

  • 将对象发送到原点

  • 旋转

  • 发送回原始位置

  • 看看我想要的东西

这是我的实现方式

{
  "ShoppingCart": {
    "Products": [
      {
        "Sku": "123",
        "Size": "S",
        "Quantity": "1"
      },
      {
        "Sku": "456",
        "Size": "M",
        "Quantity": "2"
      },
      {
        "Sku": "789",
        "Size": "L",
        "Quantity": "3"
      }
    ],
    "ShipToZip": "54452",
    "ShipMethod": "Ground"
  }

}

getMatrix()仅返回一个4x4矩阵,如下所示:

// 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];  
    }
}

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

enter image description here

因为这是我的模型在开始动画时就消失了。如果删除下面的行| Right.x Right.y Right.z | | Up.x Up.y Up.z | | Front.x Front.y Front.z | | Pos.x Pos.y Pos.z | ,它会绕原点旋转,但是每次动画重新启动时都会抽动。我猜我正在丢失或混合我不应该在某处的信息。  如何存储模型的前/右/上信息,以便可以从头开始重建其矩阵?

首次编辑,这是我不尝试使模型查看点P(在本例中为原点)时产生的效果。当我尝试时,我的模型消失了。如何使其旋转到我想要的位置,以及在旋转完后如何为模型添加新的“前/右/上”矢量?

Run example

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

2 个答案:

答案 0 :(得分: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]);
}

答案 1 :(得分:0)

解决方案:

问题出在这部分:

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轴上应用平移将最终使模型面向原点或面向原点。