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

OpenGL中基于GLM实现相机球面插值的问题咨询

相机球面弧线插值问题解答

关于glm::rotation的正确用法

你当前代码里的glm::rotation(camera_start_pos, vec3(1,1,1))完全误解了这个函数的作用——glm::rotation(a, b)是生成一个将向量a旋转到向量b的四元数。要实现球面位置插值,首先要明确:球面上的点可看作从球面中心(默认原点)出发的向量,第一步需把起始、结束位置向量归一化得到单位方向向量:

glm::vec3 start_dir = glm::normalize(camera_start_pos);
glm::vec3 end_dir = glm::normalize(camera_end_pos);

若想用四元数实现旋转插值,应生成从基准单位向量到这两个方向向量的旋转四元数。更合理的方式是生成能将start_dir旋转到end_dir的旋转四元数,再对旋转进度插值:

// 生成从起始方向到结束方向的旋转四元数
glm::quat rot_q = glm::rotation(start_dir, end_dir);
// 插值旋转进度:cur_time从0到1,0对应无旋转(起始方向),1对应完全转到结束方向
glm::quat interpolated_rot = glm::slerp(glm::quat(1,0,0,0), rot_q, cur_time);

插值后如何得到正确位置

得到插值后的旋转四元数后,将其作用到归一化的起始位置向量上,再乘以原球面半径(即起始位置向量的长度,camera_start_pos到原点的距离):

float radius = glm::length(camera_start_pos);
glm::vec3 interpolated_dir = interpolated_rot * start_dir;
camera_pos = interpolated_dir * radius;

这样就能保证相机始终在以原点为中心、半径固定的球面上,沿弧线从start_pos移动到end_pos。

无需四元数的球面插值方法

完全可以不用四元数,直接对向量做球面线性插值(Vector SLERP),逻辑更直观:

  1. 计算归一化后的起始、结束方向向量的点积,得到夹角余弦值:
glm::vec3 start_dir = glm::normalize(camera_start_pos);
glm::vec3 end_dir = glm::normalize(camera_end_pos);
float dot = glm::dot(start_dir, end_dir);
  1. 限制dot范围避免数值误差:
dot = glm::clamp(dot, -1.0f, 1.0f);
  1. 计算两向量夹角θ,再用三角函数计算插值权重:
float theta = glm::acos(dot);
float sin_theta = glm::sin(theta);
// cur_time为0到1的插值因子
float w0 = glm::sin((1 - cur_time) * theta) / sin_theta;
float w1 = glm::sin(cur_time * theta) / sin_theta;
  1. 加权得到插值方向,再乘以半径得到最终位置:
float radius = glm::length(camera_start_pos);
glm::vec3 interpolated_dir = w0 * start_dir + w1 * end_dir;
camera_pos = interpolated_dir * radius;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 21:23:20