通常我们会遇到这样的需求:将游戏场景的3D物体,放在UI坐标的某个位置。当游戏场景和UI使用的不同相机渲染,且需要有动画从游戏场景过渡到UI界面时(比如从游戏场景移动到UI上),此时需要将游戏相机视角的坐标和旋转,转换到UI相机视角下的坐标和旋转。
using UnityEngine;
public class CameraUtils {
/// <summary>
/// 将世界坐标tranferWorldPostion从fromCamera转换到toCamera坐标空间
/// </summary>
/// <param name="fromCamera">必须为透视相机</param>
/// <param name="toCamera">必须为透视相机</param>
/// <param name="tranferWorldPostion"></param>
/// <returns></returns>
public static Vector3 TransferPosition(Camera fromCamera, Camera toCamera, Vector3 tranferWorldPostion) {
Vector3 worldPoint = tranferWorldPostion;
Matrix4x4 view1 = fromCamera.transform.worldToLocalMatrix;
Matrix4x4 projection1 = fromCamera.projectionMatrix;
Matrix4x4 view2 = toCamera.transform.localToWorldMatrix;
Matrix4x4 projection2 = toCamera.projectionMatrix;
Vector4 viewPoint1 = view1 * new Vector4(worldPoint.x, worldPoint.y, worldPoint.z, 1.0f);
Vector4 eyePoint = projection1.inverse * viewPoint1;
Vector4 viewPoint2 = projection2 * eyePoint;
Vector3 finalPoint = view2 * viewPoint2;
return finalPoint;
}
/// <summary>
/// 将世界旋转tranferWorldRotation从fromCamera转换到toCamera坐标空间
/// </summary>
/// <param name="fromCamera">必须为透视相机</param>
/// <param name="toCamera">必须为透视相机</param>
/// <param name="tranferWorldRotation"></param>
/// <returns></returns>
public static Quaternion TransferRotation(Camera fromCamera, Camera toCamera, Quaternion tranferWorldRotation) {
Quaternion worldRotation = tranferWorldRotation; // 要转换的旋转
Matrix4x4 viewMatrix1 = fromCamera.worldToCameraMatrix;
Matrix4x4 viewMatrix2 = toCamera.worldToCameraMatrix;
Quaternion cameraRotation = Quaternion.LookRotation(viewMatrix1.GetColumn(2), viewMatrix1.GetColumn(1));
Quaternion localRotation = Quaternion.Inverse(cameraRotation) * worldRotation;
Vector3 screenPos = fromCamera.projectionMatrix.MultiplyPoint(Vector3.zero);
screenPos.z = Mathf.Lerp(fromCamera.nearClipPlane, fromCamera.farClipPlane, screenPos.z);
Quaternion cameraRotation2 = Quaternion.LookRotation(viewMatrix2.GetColumn(2), viewMatrix2.GetColumn(1));
Quaternion worldRotation2 = cameraRotation2 * localRotation;
return worldRotation2;
}
}