在 3D 项目开发中,调整摄像机视场角(FOV)是常见操作(如视角切换、镜头缩放),但随之会出现物体在屏幕空间中尺寸偏移的问题:FOV 增大时物体视觉缩小,FOV 减小时物体视觉放大,破坏预设的一些视觉效果。
本文结合代码实现,记录通过基础空间变换实现 “FOV 补偿” 的完整逻辑,用于技术复盘与后续项目参考,同时尽量采用通俗解读,方便后续回顾时快速理解。
一、核心原理:FOV 变化对物体显示的影响机制 要解决问题,需先明确 FOV 与物体屏幕显示的关联逻辑,核心在于 “FOV 半角正切值” 与 “视野范围” 的映射关系。 1. FOV 与正切值的数学关联 在透视投影中,垂直 FOV 决定摄像机的视野垂直范围,其关键参数为 “半 FOV 的正切值”,计算逻辑如下:
(1)将 FOV 从角度转换为弧度(避免三角函数计算误差);
(2)计算tan(FOV/2),该值对应 “相机空间中,距离摄像机 1 单位处的视野半高度”。
示例:当 FOV=90° 时,半 FOV=45°,tan(45°)=1,意味着在相机空间 Z=-1(Unity 默认相机前向为 - Z 轴)平面上,视野垂直范围为 Y=-1 至 Y=1,水平范围同理(由相机宽高比决定)。2. 补偿系数的推导 当 FOV 从 “基础值(baseFOV,如项目默认 60°)” 切换至 “当前值(currentFOV)” 时,视野范围的缩放比例可通过 “两次正切值的比值” 计算,该比值即为 “FOV 补偿系数”,公式如下:

系数意义:
若currentFOV > baseFOV:scale > 1,需放大物体顶点以抵消视野拓宽导致的视觉缩小;
若currentFOV < baseFOV:scale < 1,需缩小物体顶点以抵消视野收窄导致的视觉放大。
二、代码实现:五步完成 FOV 补偿 核心思路是 “顶点空间转换→补偿缩放→逆转换”,通过修改 Mesh 顶点确保视觉稳定,而非仅仅调整 Transform。 步骤 1:初始化与原始顶点备份 修改 Mesh 前需备份原始顶点,避免多次 FOV 调整导致顶点数据失真;使用唯一 Key 区分多物体 / 多实例,防止数据冲突。

步骤 2:获取相机 Transform(确定参考坐标系) 补偿需基于 “相机空间” 计算,因此先获取目标相机的 Transform,用于后续空间转换:

步骤 3:顶点空间转换与补偿 每个顶点需经历 “本地空间→世界空间→相机空间(补偿)→世界空间→本地空间” 的转换流程,确保补偿仅作用于视觉层面。 (1)本地空间 → 世界空间 将物体本地顶点转换为全局坐标系下的坐标,建立与相机位置的关联:

(2)世界空间 → 相机空间 将世界空间顶点转换为以相机为原点的相机空间坐标,便于基于 FOV 补偿:

(3)相机空间内应用补偿 FOV 仅影响水平(X 轴)与垂直(Y 轴)方向,深度(Z 轴)不受影响,因此仅对 X、Y 轴乘补偿系数:

(4)相机空间 → 世界空间 → 本地空间 将补偿后的顶点反向转换回物体本地空间,确保 Mesh 渲染坐标正确:

最终效果:

三、核心逻辑总结(便于快速回顾)
系数计算:补偿系数 = 当前 FOV 半角正切值 / 基础 FOV 半角正切值;
坐标转换:本地→世界→相机(补偿 X/Y)→世界→本地;
本方案通过基础空间变换实现 FOV 补偿,无复杂数学依赖,可直接应用于需视觉稳定的 3D 物体 / 特效面片,特此记录以备后续项目复用与优化。
学习笔记补充(个人复盘)
最初仅考虑 2D 平面场景(物体平面与摄像机完全平行),但实际测试中发现,当物体平面不平行于摄像机时(如倾斜的面板、斜放的模型),直接缩放整个物体的方案会导致物体视觉变形 —— 因为不同深度的顶点受 FOV 影响程度不同,统一缩放无法适配深度差异,后续通过 “逐顶点转换到相机空间补偿” 才解决该问题。
首次实现时误用世界坐标系进行补偿,而非相机局部坐标系:当相机旋转时,物体在屏幕上的位置会出现偏移甚至 “跑位”。原因是世界坐标系无法跟随相机朝向动态调整,而相机局部坐标系(以相机为原点、随相机旋转的坐标系)能精准匹配视野变化,切换后该问题彻底解决。