You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenGL物体绕自身X轴旋转异常:Y轴左侧行为异常求助

OpenGL物体绕自身X轴旋转异常问题(Y轴左侧行为异常)

在OpenGL中实现物体绕自身X轴旋转时,物体处于Y轴右侧表现正常,但位于Y轴左侧时出现异常行为。以下是当前实现旋转的代码:

void Animation::rotate_x(float degree) {
    // get the position of the object wrt to origin
    glm::vec3 position = glm::vec3(m_model_mat[3]);
    glm::vec3 position_rev = -position;

    // get the angle of the obj wrt y-axis
    float angleY = atan2(m_model_mat[0][2], sqrt((m_model_mat[0][0] * m_model_mat[0][0]) + (m_model_mat[0][1] * m_model_mat[0][1])));
    angleY = angleY * 180 / M_PI;
    std::cout << angleY << "\n";
    if(position[0] < 0){
        if(angleY > 0){
            angleY = 90 + angleY;
        } else if (angleY < 0)
        {
            angleY = -90 + angleY;
        } else{
            angleY = 180;
        }   
    }
    std::cout << angleY << "\n";

    // rotate so angle with y is 0
    glm::mat4 rot_y_mat = glm::mat4(1.0f);
    rot_y_mat = glm::rotate(rot_y_mat, glm::radians(-angleY), glm::vec3(0.0f, 1.0f, 0.0f));
    

    // rotate to bring back to the correct position wrt y
    glm::mat4 rev_rot_y_mat = glm::mat4(1.0f);
    rev_rot_y_mat = glm::rotate(rev_rot_y_mat, glm::radians(angleY), glm::vec3(0.0f, 1.0f, 0.0f));

    // rotate on x
    glm::mat4 rotation_mat = glm::mat4(1.0f);
    rotation_mat = glm::rotate(rotation_mat, glm::radians(degree), glm::vec3(1.0f, 0.0f, 0.0f));
    
    // translate back to the original position
    glm::mat4 trans_to_position = glm::mat4(1.0f);
    trans_to_position = glm::translate(trans_to_position, position);

    // move obj to origin
    glm::mat4 trans_to_origin = glm::mat4(1.0f);
    trans_to_origin = glm::translate(trans_to_origin, position_rev);

    m_model_mat = trans_to_origin * m_model_mat;
    m_model_mat = rev_rot_y_mat * m_model_mat;
    m_model_mat = rotation_mat * m_model_mat;
    m_model_mat = rot_y_mat * m_model_mat;
    m_model_mat = trans_to_position * m_model_mat;
}

问题分析

原代码的核心错误在于绕Y轴的角度修正逻辑完全错误,当物体处于Y轴左侧(position[0] < 0)时,对angleY的修正没有数学依据,导致后续的反向旋转矩阵无法正确还原物体的朝向,最终使得绕X轴的旋转偏离了物体自身的局部坐标系,出现异常行为。

此外,原代码的实现思路过于复杂:绕物体自身X轴旋转不需要额外修正Y轴角度,只需基于物体当前的局部坐标系直接处理即可。

正确实现方式

要实现物体绕自身X轴旋转,有两种简洁且可靠的方法:

方法1:直接基于局部坐标系旋转

利用glm的内置旋转函数,直接绕物体自身的X轴(模型矩阵的第一列,即局部X轴在世界空间的方向)旋转:

void Animation::rotate_x(float degree) {
    // 提取物体自身的X轴(模型矩阵的第一列,已包含当前朝向信息)
    glm::vec3 local_x = glm::normalize(glm::vec3(m_model_mat[0]));
    // 绕自身X轴旋转,glm::rotate会自动将旋转矩阵与原模型矩阵正确结合
    m_model_mat = glm::rotate(m_model_mat, glm::radians(degree), local_x);
}

方法2:平移-旋转-平移(绕局部X轴等价方式)

如果需要明确的平移-旋转-平移流程,正确的逻辑是先将物体平移到世界原点,绕自身X轴(此时等同于世界X轴,因为物体已回到原点且朝向未变)旋转,再平移回原位置:

void Animation::rotate_x(float degree) {
    glm::vec3 position = glm::vec3(m_model_mat[3]);
    
    // 平移到世界原点
    glm::mat4 to_origin = glm::translate(glm::mat4(1.0f), -position);
    // 绕X轴旋转(此时是物体自身的X轴,因为物体在原点且朝向未改变)
    glm::mat4 rot_x = glm::rotate(glm::mat4(1.0f), glm::radians(degree), glm::vec3(1.0f, 0.0f, 0.0f));
    // 平移回原位置
    glm::mat4 to_position = glm::translate(glm::mat4(1.0f), position);
    
    // 矩阵乘法顺序:从右到左执行变换
    m_model_mat = to_position * rot_x * to_origin * m_model_mat;
}

关键说明

  • 模型矩阵的列向量对应物体局部坐标系的轴在世界空间的方向:第一列是局部X轴,第二列是局部Y轴,第三列是局部Z轴。
  • glm的矩阵乘法遵循右乘优先的规则,即变换的执行顺序是从右到左,因此平移到原点→旋转→平移回原位置的矩阵顺序为to_position * rot_x * to_origin * m_model_mat。

内容的提问来源于stack exchange,提问作者Dhruv Phansalkar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 01:05:17