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

实现球体缩放时光标下点屏幕位置不变的技术方案问询

实现Google Earth式的相机缩放(保持光标球点屏幕位置不变)

核心约束分析

相机始终瞄准原点,光标对应的球上点P的屏幕坐标需全程保持不变。这意味着P在相机视锥中的相对位置(横向/纵向偏移与深度的比值)必须恒定,推导后可知相机的移动轨迹被限制在原点O、点P、初始相机位置C三点确定的平面内,可简化为2D平面几何问题求解。

数学推导与实现步骤

假设:

  • 球半径R=1,球心O(0,0,0)
  • 初始相机位置C,到原点距离d = length(C)
  • 光标对应的球上点P,满足length(P)=1

1. 计算关键恒定比值k

k是P在相机视野中的相对位置比值,直接决定屏幕坐标的恒定关系:

vec3 cross_PC = cross(P, C);
float len_cross = length(cross_PC);
float dot_CC = dot(C, C);
float dot_PC = dot(P, C);
float k = len_cross / (dot_CC - dot_PC);

2. 确定新的相机距离d'

根据滚轮方向调整相机到原点的距离,示例如下:

// 滚轮向前(拉近)用0.9,向后(拉远)用1.1,可根据需求调整缩放系数
float scale = wheel_direction > 0 ? 1.1 : 0.9;
float d_prime = d * scale;

3. 求解相机新方向的夹角参数

通过一元二次方程求解相机新位置与P点的夹角余弦值cosθ',并筛选符合约束的解:

float a = 1.0 + k*k;
float b = -2.0 * k*k * d_prime;
float c = k*k * d_prime*d_prime - 1.0;
float discriminant = b*b - 4.0*a*c;
float sqrt_disc = sqrt(discriminant);

// 计算两个候选根
float cos_theta1 = (-b + sqrt_disc) / (2.0*a);
float cos_theta2 = (-b - sqrt_disc) / (2.0*a);

// 选择正确的根:需保证P在相机前方(d' - cosθ' > 0),且与初始方向同侧
float cos_theta;
float sin_theta_initial = k * (d - dot_PC / d);
float sin_theta1 = k * (d_prime - cos_theta1);
float sin_theta2 = k * (d_prime - cos_theta2);

if ((d_prime - cos_theta1) > 0.0 && sign(sin_theta1) == sign(sin_theta_initial)) {
    cos_theta = cos_theta1;
} else {
    cos_theta = cos_theta2;
}
float sin_theta = k * (d_prime - cos_theta);

4. 计算新的相机位置

构造平面内垂直于P的单位向量Q,生成最终相机位置:

// 生成O-P-C平面内垂直于P的单位向量Q
vec3 Q = normalize(C - dot_PC * P);
// 计算新相机位置
vec3 C_prime = d_prime * (cos_theta * P + sin_theta * Q);

5. 更新视图矩阵

用新相机位置生成视图矩阵:

mat4 view_matrix = lookAt(C_prime, vec3(0.0), vec3(0.0, 0.0, 1.0));

关键说明

  • 相机实际沿O-P-C平面内的圆弧轨迹移动,严格满足P点屏幕位置不变的约束
  • 所有计算基于向量运算,可直接在Shader或CPU端实现,最终通过lookAt生成视图矩阵即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 11:28:08