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

自定义旋转的glm::lookAt工作异常问题排查

相机环绕模型旋转时视图矩阵逻辑与实际行为不符的问题

我需要实现相机环绕模型旋转的功能,按照几何理论逻辑,视图矩阵的创建应遵循以下步骤:

  1. 将相机位置平移至场景中心(减去scene_center)
  2. 对X、Y轴执行旋转操作
  3. 将相机位置平移回原位置(加上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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 09:35:22