关于unity世界坐标和相对坐标
其实就是父子集的关系
估计没有多少人闲着没事写这个问题,但架不住有好学的小伙伴深究这个问题,所以我们从数学角度剖析下。
如果将物体拖拽到某个物体成为子集对象后,此时就变成了这个子集对象的坐标相对于这个父物体坐标,以下我们简称相对坐标。
那么如果我们以世界坐标为基准,来计算这个子集物体对象的坐标该如何计算呢?
首先你得先知道这个父物体的世界坐标,以及代表它当前姿态的四元数
四元数为 w、x、y、z,这个w要注意可能与unity不同
然后这里面有个根据四元数的cbi计算矩阵
下面为cbi矩阵

从计算给定四元数的方向余弦矩阵cbi,经过上面cbi计算,就能得出我们当前的世界坐标
这样就完成了将向量从机体坐标系转换到世界坐标系的全过程,即得出子集对象的世界坐标位置,并会受到当前对象的四元数影响。
用代码实现这个过程如下所示:
using UnityEngine;public class ObjectPositionCalculator : MonoBehaviour
{[Header("参考对象")] public Transform referenceObject; // 提供姿态和位置信息的参考对象[Header("目标对象")] public Transform targetObject; // 需要计算位置的目标对象[Header("CBI参数")] public Vector3 localOffset = Vector3.zero; // 局部坐标系偏移public Vector3 globalOffset = Vector3.zero; // 全局坐标系偏移public bool useQuaternionRotation = true; // 是否使用四元数旋转[Header("平滑设置")] public bool useSmoothing = false;public float smoothingFactor = 0.1f;private Vector3 previousPosition;private Quaternion previousRotation;void Start(){if (referenceObject == null){Debug.LogError("参考对象未设置!");return;}previousPosition = referenceObject.position;previousRotation = referenceObject.rotation;// 初始计算目标对象位置CalculateTargetPosition();}void Update(){if (referenceObject == null || targetObject == null)return;CalculateTargetPosition();}void CalculateTargetPosition(){// 获取参考对象的当前姿态和位置Vector3 referencePosition = referenceObject.position;Quaternion referenceRotation = referenceObject.rotation;// 计算位置变化和旋转变化Vector3 positionDelta = referencePosition - previousPosition;Quaternion rotationDelta = referenceRotation * Quaternion.Inverse(previousRotation);// 基于CBI推算目标位置Vector3 calculatedPosition = CalculateCBIPosition(referencePosition,referenceRotation,positionDelta,rotationDelta);// 应用平滑if (useSmoothing){calculatedPosition = Vector3.Lerp(targetObject.position,calculatedPosition,smoothingFactor * Time.deltaTime);}// 设置目标对象位置targetObject.position = calculatedPosition;// 更新上一帧数据previousPosition = referencePosition;previousRotation = referenceRotation;}Vector3 CalculateCBIPosition(Vector3 refPosition, Quaternion refRotation,Vector3 deltaPosition, Quaternion deltaRotation){Vector3 finalPosition;if (useQuaternionRotation){// 使用四元数旋转的方法// 应用局部偏移(在参考对象的局部坐标系中)Vector3 rotatedOffset = refRotation * localOffset;// 应用全局偏移finalPosition = refPosition + rotatedOffset + globalOffset;// 考虑位置变化的影响finalPosition += deltaPosition;// 考虑旋转变化对位置的影响Vector3 rotationEffect = deltaRotation * (rotatedOffset * 0.5f);finalPosition += rotationEffect;}else{// 简化的位置推算方法finalPosition = refPosition + refRotation * localOffset + globalOffset;}return finalPosition;}// 高级CBI计算方法(可用于更精确的惯性导航)Vector3 CalculateAdvancedCBIPosition(Vector3 refPosition, Quaternion refRotation,Vector3 velocity, Vector3 angularVelocity, float deltaTime){// 基于速度和角速度的预测Vector3 predictedPosition = refPosition + velocity * deltaTime;// 考虑角速度对局部偏移的影响Quaternion predictedRotation = refRotation * Quaternion.Euler(angularVelocity * Mathf.Rad2Deg * deltaTime);// 应用旋转后的偏移Vector3 rotatedOffset = predictedRotation * localOffset;return predictedPosition + rotatedOffset + globalOffset;}// 公共方法:手动触发位置计算public void ForceRecalculate(){CalculateTargetPosition();}// 公共方法:设置偏移参数public void SetOffsets(Vector3 newLocalOffset, Vector3 newGlobalOffset){localOffset = newLocalOffset;globalOffset = newGlobalOffset;ForceRecalculate();}// 公共方法:获取当前推算的位置public Vector3 GetCalculatedPosition(){return CalculateCBIPosition(referenceObject.position,referenceObject.rotation,referenceObject.position - previousPosition,referenceObject.rotation * Quaternion.Inverse(previousRotation));}#if UNITY_EDITORvoid OnDrawGizmosSelected(){if (referenceObject != null && targetObject != null){// 绘制参考对象到目标对象的连线Gizmos.color = Color.yellow;Gizmos.DrawLine(referenceObject.position, targetObject.position);// 绘制局部偏移示意Gizmos.color = Color.blue;Vector3 localOffsetWorld = referenceObject.rotation * localOffset;Gizmos.DrawLine(referenceObject.position, referenceObject.position + localOffsetWorld);}}
}#endif