手写LookAt矩阵出现俯仰/偏航旋转反向问题求解
手动实现LookAt矩阵视角旋转反向问题
问题表现
手动实现LookAt视图矩阵时,相机前后移动功能正常,但鼠标控制视角旋转时,旋转方向和操作方向完全相反。
使用代码中注释的「相机空间转世界空间」旋转矩阵时程序运行效果正常,但按照变换逻辑,视图矩阵应当实现世界空间到相机空间的变换,不清楚当前写法出现旋转反向的原因。
关联代码
视图矩阵计算实现
glm::mat4 Camera::GetViewMatrix() { // UVN相机坐标系计算 // NDC空间中+z指向屏幕外,相机观察方向对应-z轴 // 相机当前看向的目标点 glm::vec3 target = position + front; // 相机朝向的反方向(指向相机后方) glm::vec3 n = glm::normalize(position - target); // 相机右方向向量 glm::vec3 u = glm::normalize(glm::cross(worldUp, n)); // 相机局部上方向向量 glm::vec3 v = glm::normalize(glm::cross(n, u)); // 相机空间转世界空间的基变换矩阵(使用时效果正常,当前被注释) /* glm::mat4 rotate( */ /* u.x, v.x, n.x, 0.0f, */ /* u.y, v.y, n.y, 0.0f, */ /* u.z, v.z, n.z, 0.0f, */ /* 0.0f, 0.0f, 0.0f, 1.0f */ /* ); */ // 认为是世界空间转相机空间的旋转矩阵(使用时旋转方向反向) glm::mat4 rotate( u.x, u.y, u.z, 0, v.x, v.y, v.z, 0, n.x, n.y, n.z, 0, 0.0f, 0.0f, 0.0f, 1.0f ); // 将相机平移回原点的变换矩阵 glm::mat4 trans(glm::translate(glm::mat4(1.0f), -position)); // 相机空间转世界空间是先旋转后平移,因此反向变换(世界转相机)顺序取反 return rotate * trans; }
相机方向向量更新逻辑
void Camera::updateCameraVectors() { glm::vec3 direction; direction.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch)); direction.y = sin(glm::radians(pitch)); direction.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch)); front = glm::normalize(direction); right = glm::normalize(glm::cross(front, worldUp)); up = glm::normalize(glm::cross(right, front)); }
鼠标输入角度更新逻辑
void Camera::ProcessMouseMovement(float xoffset, float yoffset, bool constrainPitch) { xoffset *= sensitivity; yoffset *= sensitivity; yaw += xoffset; pitch += yoffset; if (constrainPitch) { if (pitch > 89.0f) pitch = 89.0f; if (pitch < -89.0f) pitch = -89.0f; } updateCameraVectors(); }
问题原因
核心问题有两个,和基变换的逻辑本身无关:
- GLM默认使用列主序存储矩阵,你手动逐行填入u、v、n向量构造的矩阵,确实是列主序下「相机空间转世界空间」旋转矩阵的转置,也就是理论上的「世界空间转相机空间」旋转矩阵,但你选用的n向量方向不符合OpenGL的视图空间约定。
- 你计算的n是
position - target,也就是和相机front方向完全相反、指向相机身后的向量。你把这个向量作为相机空间的z轴,相当于把相机空间z轴正方向对准了屏幕内侧,和OpenGL约定的*「相机空间-z轴对准观察方向、+z轴指向屏幕外」*完全相反,所有旋转自然会整体反向。
你觉得注释掉的旧旋转矩阵「运行正常」纯粹是两个错误巧合抵消:那个矩阵本来是相机空间转世界空间用的,你直接拿它当视图矩阵,相当于没有做旋转的逆变换,刚好抵消了z轴反向带来的翻转问题,再加平移部分的逻辑本身是对的,所以前后移动看起来正常,并不是这个矩阵写法本身符合视图矩阵的设计逻辑。
修复方案
任选一种修改即可:
- 调整n向量方向和叉乘顺序,适配当前手动填矩阵的写法,其余代码不用动:
// n直接取相机正前方向,也就是target - position glm::vec3 n = glm::normalize(front); // 调整叉乘顺序保证右手坐标系正确性 glm::vec3 u = glm::normalize(glm::cross(n, worldUp)); glm::vec3 v = glm::normalize(glm::cross(u, n)); - 不手动构造转置矩阵,利用正交矩阵逆等于转置的特性计算,同时修正z轴方向:
保留原有u、v、n(n=-front)的计算逻辑,把旋转矩阵部分替换为:glm::mat4 rotate_cam2world( u.x, v.x, -n.x, 0.0f, // 对n取反修正z轴方向 u.y, v.y, -n.y, 0.0f, u.z, v.z, -n.z, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f ); glm::mat4 rotate = glm::transpose(rotate_cam2world);
内容的提问来源于stack exchange,提问作者waz
相关产品推荐
相关产品推荐

