自定义旋转的glm::lookAt工作异常问题排查
相机环绕模型旋转时视图矩阵逻辑与实际行为不符的问题
我需要实现相机环绕模型旋转的功能,按照几何理论逻辑,视图矩阵的创建应遵循以下步骤:
- 将相机位置平移至场景中心(减去
scene_center) - 对X、Y轴执行旋转操作
- 将相机位置平移回原位置(加上
scene_center)
对应的理论代码如下:
// camera_rotation_angle_x_和camera_rotation_angle_y_初始化为0,可由用户修改 glm::mat4 CreateViewMatrix(glm::vec3 eye_pos, glm::vec3 scene_center, glm::vec3 up_vec) { auto eye_transform = glm::translate(glm::mat4(1.0f), -scene_center); // 重定位至中心 eye_transform = glm::rotate(eye_transform, camera_rotation_angle_x_, glm::vec3(1.0f, 0.0f, 0.0f)); eye_transform = glm::rotate(eye_transform, camera_rotation_angle_y_, glm::vec3(0.0f, 1.0f, 0.0f)); eye_transform = glm::translate(eye_transform, scene_center); // 移回原位置 eye_pos = eye_transform * glm::vec4(eye_pos, 1.0f); up_vec = eye_transform * glm::vec4(up_vec, 0.0f); return glm::lookAt(eye_pos, scene_center, up_vec); }
但实际运行时,只有将平移逻辑完全反转(先加scene_center,再减scene_center),才能保证相机与场景中心的距离恒定、旋转行为正常。修改后的代码如下:
auto eye_transform = glm::translate(glm::mat4(1.0f), scene_center); // 重定位至中心 *符号已更改* ... eye_transform = glm::translate(eye_transform, -scene_center); // 移回原位置 *符号已更改* ... // 正确性测试:只有距离保持恒定,旋转逻辑才正确。 cout << "eye_pos: " << eye_pos[0] << ", " << eye_pos[1] << ", " << eye_pos[2] << endl; cout << "distance: " << (sqrt( pow(eye_pos[0] - scene_center[0], 2) + pow(eye_pos[1] - scene_center[1], 2) + pow(eye_pos[2] - scene_center[2], 2) )) << endl;
从几何逻辑上看,先减后加才是正确的平移-旋转-平移还原流程,先加后减完全不符合理论逻辑,但为什么只有这样写才能让功能正常工作?
另外,调用CreateViewMatrix的代码如下,问题是否出在这里?
// kEyePos、kSceneCenter、kUpVec、kFovY、kAspect、kDistanceEyeToBack和kLightPos在程序生命周期内为常量 UniformBufferObject ubo{}; ubo.model = glm::mat4(1.0f); ubo.view = CreateViewMatrix(kEyePos, kSceneCenter, kUpVec); ubo.proj = glm::perspective(kFovY, kAspect, 0.1f, kDistanceEyeToBack); // GLM最初为OpenGL设计,裁剪坐标的Y轴是反转的。 // 最简单的补偿方法是翻转投影矩阵Y轴缩放因子的符号。 // 由于我们对投影矩阵进行了Y轴翻转,顶点现在将按逆时针顺序绘制,而非顺时针。 // 这会导致背面剔除生效,阻止任何几何体被绘制。 // 你应该修改VkPipelineRasterizationStateCreateInfo中的frontFace为VK_FRONT_FACE_COUNTER_CLOCKWISE来纠正此问题。 ubo.proj[1][1] *= -1; ubo.light_pos = glm::vec4(kLightPos, 1.0f); // 点的w分量为1 memcpy(vk_buffer_->GetUniformBufferMapped(frame_index), &ubo, sizeof(ubo));
内容的提问来源于stack exchange,提问作者pellorao
相关产品推荐
相关产品推荐

