C++ 在使用GLM的OpenGL中,当对象面对原点时围绕原点旋转对象?

C++ 在使用GLM的OpenGL中,当对象面对原点时围绕原点旋转对象?,c++,opengl,matrix,rotation,glm-math,C++,Opengl,Matrix,Rotation,Glm Math,我正在尝试制作一个简单的动画,其中一个对象在OpenGL中使用glm lib围绕世界原点旋转。我的想法是: 将对象发送到源 旋转它 发回原位 让它看看我想要什么 以下是我的实现: // 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::

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

将对象发送到源

旋转它

发回原位

让它看看我想要什么

以下是我的实现:

// 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   |
我使用此图像作为参考:

因为它是我的模型只是消失时,我开始动画。如果我删除下面的线//看点P,它会围绕原点旋转,但每次动画重新启动时都会抽动。我猜我正在丢失或混合我不应该在某处的信息。 如何存储模型的前/右/上信息,以便从头开始重建其矩阵

首先编辑,这是当我不试图让我的模型看到点p时产生的效果,在本例中是原点。当我尝试时,我的模型消失了。我怎样才能让它看起来像我想要的,在我完成旋转后,我怎样才能得到我的模型新的前/右/上向量

我在上面的gif中运行的代码是否类似于或通过其参数构建矩阵,并将输入矩阵乘以新矩阵

这意味着

rotation = glm::translate(rotation, Position - p );
可以表示为伪代码:

rotation = rotation * translation(Position - p);
注意,矩阵乘法必须从左到右读取。看

“平移*旋转”操作导致围绕对象原点旋转:

glm::vec3 Right    = glm::normalize(glm::cross(WorldUp, Front));
glm::mat4 pos_look = getMatrix(Right, WorldUp, Front, pos_rot);
“旋转*平移”操作导致围绕世界原点旋转:

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

glm::vec3 WorldUp( 0.0f, 1.0f, 0.0f );
glm::vec3 start_position = ...;
float scale = ...;
glm::vec3 p = ...;
为此,必须创建一个包含新旋转的矩阵

glm::mat4 new_rot = glm::rotate(glm::mat4(1.0f), ROTATION_SPEED * deltaTime, axis);
然后,您可以按如下方式计算最终矩阵:

Matrix = new_rot * rotation * scale_m;
如果要围绕点p旋转对象,且对象应始终面向点p,则只需对象开始位置和旋转轴的位置即可。 在您的例子中,旋转轴是世界的上方向向量

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]);
}
类似于或的操作通过其参数构建矩阵,并将输入矩阵乘以新矩阵

这意味着

rotation = glm::translate(rotation, Position - p );
可以表示为伪代码:

rotation = rotation * translation(Position - p);
注意,矩阵乘法必须从左到右读取。看

“平移*旋转”操作导致围绕对象原点旋转:

glm::vec3 Right    = glm::normalize(glm::cross(WorldUp, Front));
glm::mat4 pos_look = getMatrix(Right, WorldUp, Front, pos_rot);
“旋转*平移”操作导致围绕世界原点旋转:

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

glm::vec3 WorldUp( 0.0f, 1.0f, 0.0f );
glm::vec3 start_position = ...;
float scale = ...;
glm::vec3 p = ...;
为此,必须创建一个包含新旋转的矩阵

glm::mat4 new_rot = glm::rotate(glm::mat4(1.0f), ROTATION_SPEED * deltaTime, axis);
然后,您可以按如下方式计算最终矩阵:

Matrix = new_rot * rotation * scale_m;
如果要围绕点p旋转对象,且对象应始终面向点p,则只需对象开始位置和旋转轴的位置即可。 在您的例子中,旋转轴是世界的上方向向量

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]);
}
解决方案:

问题在于这一部分:

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位置的结果,即轨道半径。发生这种情况时,模型会抖动,因为它丢失了旋转信息

我通过对轨道半径使用不同的变量,并在模型的z轴上应用平移来解决这个问题。当平移应用于x轴时,最初面向摄影机的模型将侧向终止于原点。但是,根据信号,在z轴上应用平移将导致模型朝向或向后到原点。

解决方案:

问题在于这一部分:

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位置的结果,即轨道半径。当这种情况发生时,模型会抽搐,因为它丢失了 轮换信息


我通过对轨道半径使用不同的变量,并在模型的z轴上应用平移来解决这个问题。当平移应用于x轴时,最初面向摄影机的模型将侧向终止于原点。但是,根据信号,在z轴上应用平移将导致模型朝向或向后朝向原点。

谢谢您的回答,拉比76。但我对你的建议也有同样的看法。我这里的主要问题是,当模型围绕一个点旋转时,让它看到我想要的位置。我编辑了我的问题,以便让它更清楚,如果你能看一看,我会很高兴的。@MatheusIanzer我扩展了答案谢谢你的回答,拉比76。但我对你的建议也有同样的看法。我这里的主要问题是,当模型围绕一个点旋转时,让它看到我想要的位置。我编辑了我的问题,以便让它更清楚,如果你能看一下,我会很高兴的。@MatheusIanzer我扩展了答案,首先围绕外轴MR1矩阵旋转。然后平移模型MT,然后围绕其自身垂直轴MR2旋转。合成运动通过MFInal=MR2 x MT x MR1实现。矩阵的顺序是多方面的,这会让我的模型面对问题吗?如果是这样,在动画之后我应该保留什么信息,以便我可以将其放置在位置,以便从停止的位置继续进行另一次旋转?使用angleE进行外部旋转后,您可以知道模型的中心位置,一个简单的位置New=矩阵x位置Old乘法。使用此新位置和角度,可以计算应用于自旋转的角度。只要为下一个运动存储位置和当前自转角。使用这种方法,我必须为每个轴x、y、z存储自转角,然后创建3个旋转矩阵?@MatheusIanzer在系统中,它必须是[Right=glm::normalizeglm::crossFront,WorldUp;]`。但目前还不清楚您想要实现什么。首先围绕外轴MR1矩阵旋转。然后平移模型MT,然后围绕其自身垂直轴MR2旋转。合成运动通过MFInal=MR2 x MT x MR1实现。矩阵的顺序是多方面的,这会让我的模型面对问题吗?如果是这样,在动画之后我应该保留什么信息,以便我可以将其放置在位置,以便从停止的位置继续进行另一次旋转?使用angleE进行外部旋转后,您可以知道模型的中心位置,一个简单的位置New=矩阵x位置Old乘法。使用此新位置和角度,可以计算应用于自旋转的角度。只要为下一个运动存储位置和当前自转角。使用这种方法,我必须为每个轴x、y、z存储自转角,然后创建3个旋转矩阵?@MatheusIanzer在系统中,它必须是[Right=glm::normalizeglm::crossFront,WorldUp;]`。但目前还不清楚你想要实现什么。