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

如何在C++中使用glm将四元数转欧拉角并避免角度异常?

解决glm四元数转欧拉角时Y轴角度突变问题

你遇到的是欧拉角万向锁导致的典型问题:当Y轴旋转到90度时,X轴和Z轴的旋转自由度重合,glm的glm::eulerAngles会选择一种等价但不符合你需求的欧拉角表示(比如(180, 89, 180)和(0, 91, 0)是同一个旋转),但你需要Y轴角度持续递增,同时保持X、Z轴为0。

下面提供两种可行的解决方案:

方案一:直接跟踪Y轴旋转角度

既然你的旋转是固定绕Y轴进行的,完全可以绕过四元数转欧拉角的步骤,直接维护一个Y轴角度变量,每次旋转后递增即可,这是最简洁的解决方式。

#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <chrono>
#include <thread>

int main() {
    glm::quat quaternion = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
    float y_angle = 0.0f; // 直接维护Y轴旋转角度

    for (int i = 0; i < 360; ++i) {
        // 应用Y轴旋转到四元数
        glm::quat rotation_quat = glm::angleAxis(glm::radians(1.0f), glm::vec3(0.0f, 1.0f, 0.0f));
        quaternion = rotation_quat * quaternion;
        
        // 直接递增Y轴角度,保持X、Z轴为0
        y_angle += 1.0f;
        glm::vec3 euler_angles(0.0f, y_angle, 0.0f);

        std::cout << "Euler Angles: " << euler_angles.x << ", " << euler_angles.y << ", " << euler_angles.z << std::endl;

        std::this_thread::sleep_for(std::chrono::milliseconds(50));
    }

    return 0;
}

方案二:修正glm转换后的欧拉角输出

如果必须从四元数反向推导欧拉角,可以自定义转换函数,检测glm输出的特殊情况,将其修正为Y轴持续递增的表示。

#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <chrono>
#include <thread>

// 自定义四元数转欧拉角函数,确保Y轴角度持续递增
glm::vec3 quat_to_euler_y_increasing(const glm::quat& q) {
    glm::vec3 euler = glm::degrees(glm::eulerAngles(q));
    
    // 检测是否进入万向锁的等价表示(X和Z接近180度)
    const float eps = 1e-3;
    if (std::abs(euler.x - 180.0f) < eps && std::abs(euler.z - 180.0f) < eps) {
        // 将Y轴转换为递增方向,重置X、Z轴为0
        euler.y = 360.0f - euler.y;
        euler.x = 0.0f;
        euler.z = 0.0f;
    }
    
    // 确保Y轴角度在0-360范围内
    if (euler.y < 0.0f) {
        euler.y += 360.0f;
    }
    
    return euler;
}

int main() {
    glm::quat quaternion = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);

    for (int i = 0; i < 360; ++i) {
        glm::quat rotation_quat = glm::angleAxis(glm::radians(1.0f), glm::vec3(0.0f, 1.0f, 0.0f));
        quaternion = rotation_quat * quaternion;

        glm::vec3 euler_angles = quat_to_euler_y_increasing(quaternion);

        std::cout << "Euler Angles: " << euler_angles.x << ", " << euler_angles.y << ", " << euler_angles.z << std::endl;

        std::this_thread::sleep_for(std::chrono::milliseconds(50));
    }

    return 0;
}

原理说明

欧拉角的万向锁本质是旋转自由度丢失,此时同一个旋转可以用多种欧拉角组合表示。glm默认选择的组合会让Y轴角度反向递减,同时翻转X/Z轴,但我们可以通过检测这种特殊组合,强制转换为Y轴持续递增的形式,满足你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 14:37:16