如何计算任意头部旋转下眼睛看向目标的Yaw与Pitch值
计算任意旋转头部的眼睛看向目标的Yaw/Pitch值
要解决这个问题,核心是把世界空间中的目标方向转换为头部局部坐标系下的方向,再从局部向量推导相对头部的Yaw和Pitch角度——这样不管头部怎么旋转(颠倒、向后),角度值都能精准对应眼睛相对于头部的转动需求,完全适配2D面部纹理的眼睛移动逻辑。
步骤1:计算头部到目标的世界方向向量
先算出目标相对于头部的位置偏移,归一化后得到方向向量(归一化不影响角度计算,可选但推荐):
Vector3 worldTargetDir = targetPosition - headPosition; worldTargetDir.Normalize();
步骤2:转换到头部局部坐标系
头部的旋转(四元数)定义了世界空间到头部局部空间的转换逻辑,我们需要逆旋转来把世界向量转成局部向量——这样得到的向量方向是相对于头部自身的前方(Z轴)、上方(Y轴)的:
Vector3 localTargetDir = Quaternion.Inverse(headRotation) * worldTargetDir;
比如头部上下颠倒时,局部Y轴和世界Y轴相反,此时世界中向下的方向在头部局部就是向上,正好对应需求中“眼睛向上看(世界视角向下)时Pitch为正”的情况。
步骤3:计算Yaw(偏航)角度
Yaw是局部向量在X-Z平面(头部水平平面)的左右偏移角度,用atan2(X, Z)计算(X在前、Z在后对应绕Y轴的旋转),再转成角度:
float yawRad = atan2(localTargetDir.x, localTargetDir.z); float yawDeg = rad2deg(yawRad);
- 正值表示眼睛看向头部自身的右侧,负值表示左侧,完全贴合头部当前朝向。
步骤4:计算Pitch(俯仰)角度
Pitch是局部向量相对于X-Z平面的上下偏移角度,先算出X-Z平面的向量长度,再用atan2(Y, XZ长度)计算:
float xzLength = sqrt(localTargetDir.x * localTargetDir.x + localTargetDir.z * localTargetDir.z); float pitchRad = atan2(localTargetDir.y, xzLength); float pitchDeg = rad2deg(pitchRad);
- 正值表示眼睛看向头部自身的上方,负值表示下方,不管头部是否颠倒,这个值都对应眼睛相对于头部的上下转动。
步骤5:钳制角度到指定范围
最后把计算出的Yaw和Pitch限制在你需要的区间(比如-30°到30°):
float clampedYaw = clamp(yawDeg, -30f, 30f); float clampedPitch = clamp(pitchDeg, -30f, 30f);
完整伪代码示例(Unity风格)
public (float Yaw, float Pitch) CalculateEyeRotation(Vector3 headPosition, Quaternion headRotation, Vector3 targetPosition) { // 计算世界空间方向向量 Vector3 worldTargetDir = targetPosition - headPosition; worldTargetDir.Normalize(); // 转换到头部局部空间 Vector3 localTargetDir = Quaternion.Inverse(headRotation) * worldTargetDir; // 计算偏航角Yaw float yawRad = Mathf.Atan2(localTargetDir.x, localTargetDir.z); float yawDeg = Mathf.Rad2Deg * yawRad; // 计算俯仰角Pitch float xzLength = Mathf.Sqrt(localTargetDir.x * localTargetDir.x + localTargetDir.z * localTargetDir.z); float pitchRad = Mathf.Atan2(localTargetDir.y, xzLength); float pitchDeg = Mathf.Rad2Deg * pitchRad; // 钳制角度范围 float clampedYaw = Mathf.Clamp(yawDeg, -30f, 30f); float clampedPitch = Mathf.Clamp(pitchDeg, -30f, 30f); return (clampedYaw, clampedPitch); }
关键注意事项
- 逆旋转的必要性:只有把世界方向转到头部局部空间,才能得到相对于头部的真实偏移角度,否则角度会和世界空间绑定,无法适配头部的任意旋转状态。
- Pitch计算细节:用X-Z平面长度而非向量总长度,是因为Pitch只关注上下方向与水平平面的夹角,避免向量长度干扰角度计算。
- 引擎适配:不同引擎的三角函数、四元数操作可能有细微差异(比如Unreal的
FRotator或FQuat),但核心逻辑完全通用。
内容的提问来源于stack exchange,提问作者Luke Wenke
相关产品推荐
相关产品推荐

