GLM如何实现四元数叉乘与归一化?Rust重写光线追踪遇阻
GLM四元数
cross与normalize实现细节,及Rust cgmath等价写法 问题背景
我正在用Rust跟进TheCherno的光线追踪系列(对应第6集),遇到一段GLM代码里的四元数glm::cross和glm::normalize操作,从数学概念上看似乎不合理——毕竟四元数本身没有“叉乘”的定义。我尝试用Rust的cgmath crate重写这段代码,但找不到对应函数;查GLM源码时仅在旧版文档中查到相关提及,特此求助GLM如何实现四元数的这两个操作。
相关代码片段:
if (delta.x != 0.0f || delta.y != 0.0f) { float pitchDelta = delta.y * GetRotationSpeed(); float yawDelta = delta.x * GetRotationSpeed(); glm::quat q = glm::normalize(glm::cross(glm::angleAxis(-pitchDelta, rightDirection), glm::angleAxis(-yawDelta, glm::vec3(0.f, 1.0f, 0.0f)))); m_ForwardDirection = glm::rotate(q, m_ForwardDirection); moved = true; }
解答
1. GLM四元数glm::cross的真实含义:四元数乘法(Hamilton积)
你觉得困惑是正常的——GLM旧版本里的glm::cross用于四元数时,其实是四元数的乘法(Hamilton积),这是一个命名遗留问题。新版本GLM已经废弃了这个用法,改用glm::operator*或glm::mul来表示四元数乘法,避免和向量叉乘混淆。
GLM中四元数乘法的具体实现逻辑(对应旧版cross):
假设两个四元数 q1 = (w1, x1, y1, z1)、q2 = (w2, x2, y2, z2),相乘结果为 q = q1 * q2,分量计算如下:
q.w = w1*w2 - x1*x2 - y1*y2 - z1*z2 q.x = w1*x2 + x1*w2 + y1*z2 - z1*y2 q.y = w1*y2 + y1*w2 + z1*x2 - x1*z2 q.z = w1*z2 + z1*w2 + x1*y2 - y1*x2
2. GLM四元数glm::normalize的实现
四元数的归一化逻辑和向量归一化完全一致:
- 计算四元数的模长:
length = sqrt(w² + x² + y² + z²) - 将四元数的每个分量除以模长,得到单位四元数(用于旋转时避免累积数值误差,保证旋转的正确性)。
3. Rust cgmath的等价写法
cgmath中没有类似GLM旧版的cross命名混淆,直接用标准的四元数操作即可:
use cgmath::{Quaternion, Vector3, Rotation}; // 假设已定义相关变量:delta: Vector2<f32>, right_direction: Vector3<f32>, m_forward_direction: Vector3<f32> // 假设get_rotation_speed()返回f32类型的旋转速度 if delta.x != 0.0 || delta.y != 0.0 { let pitch_delta = delta.y * get_rotation_speed(); let yaw_delta = delta.x * get_rotation_speed(); // 构造两个旋转四元数 let pitch_quat = Quaternion::from_axis_angle(right_direction, -pitch_delta); let yaw_quat = Quaternion::from_axis_angle(Vector3::unit_y(), -yaw_delta); // 四元数相乘并归一化(对应GLM的cross+normalize) let q = (pitch_quat * yaw_quat).normalize(); // 旋转前向向量 m_forward_direction = q.rotate_vector(m_forward_direction); }
内容的提问来源于stack exchange,提问作者Question Asker
相关产品推荐
相关产品推荐

