1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > unity 坐标系转换_Unity3D之笛卡尔坐标系转换——屏幕坐标转换世界坐标 世界坐标转

unity 坐标系转换_Unity3D之笛卡尔坐标系转换——屏幕坐标转换世界坐标 世界坐标转

时间:2023-02-28 12:39:07

相关推荐

unity 坐标系转换_Unity3D之笛卡尔坐标系转换——屏幕坐标转换世界坐标 世界坐标转

因为要做AR的标记功能,所以就要用到坐标的转换,就总结了一下屏幕坐标、世界坐标、相机坐标之间的转换。

首先说明的是Unity3D遵从Direct3D标准的左手笛卡尔坐标系变换规则。

也就是说:

世界坐标系就是左手笛卡尔坐标系(x,y,z),相机也是左手笛卡尔坐标系(u,v,w),且面向自身坐标系w坐标轴正上方,屏幕以中央为原点,右和上分别为x,y的正方向。

我将工具代码直接上:

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class CameraTransformationUtilities : MonoBehaviour

{

public static CameraTransformationUtilities Instance { get; private set; }

protected CameraTransformationUtilities() { }

private void Start()

{

Instance = this;

}

/// 投影矩阵

/// 视点矩阵

/// 列表形式的投影矩阵

/// 列表形式的视点矩阵

/// 要投影的点的引用

/// 要投影的点引用列表

/// 屏幕宽

/// 屏幕高

/// 列表是否以行优先进行矩阵元素的存储

/// 水平翻转

/// 上下翻转

public void UnprojectScreenToWorld(

Matrix4x4 projectionMatrix,

Matrix4x4 viewMatrix,

ref Vector3 p)

{

// 世界坐标->相机坐标, 相机坐标->屏幕坐标 分别需要 viewMatrix和projectionMatrix

Matrix4x4 PV = projectionMatrix * viewMatrix;

// 逆矩阵即为从屏幕到世界的坐标变换,需指定像素深度

p = PV.inverse.MultiplyPoint(p);

}

public void UnprojectScreenToWorld(

IReadOnlyList projection,

IReadOnlyList view,

ref Vector3 p,

bool rowBase = true

)

{

Matrix4x4 projectionMatrix = ConstructMatirx(projection, rowBase);

Matrix4x4 viewMatrix = ConstructMatirx(view, rowBase);

UnprojectScreenToWorld(projectionMatrix, viewMatrix, ref p);

}

public void UnprojectScreenToWorld(

IReadOnlyList projection,

IReadOnlyList view,

ref Vector3 p,

float width,

float height,

bool rowBase = true,

bool flipLeftToRight = false,

bool flipUpsideDown = false

)

{

Matrix4x4 projectionMatrix = ConstructMatirx(projection, rowBase);

Matrix4x4 viewMatrix = ConstructMatirx(view, rowBase);

ScreenSpaceTransform(ref p, width, height, flipLeftToRight, flipUpsideDown);

UnprojectScreenToWorld(projectionMatrix, viewMatrix, ref p);

}

public void UnProjectScreenToWorld(

Matrix4x4 projectionMatrix,

Matrix4x4 viewMatrix,

ref List pl

)

{

Matrix4x4 PV = projectionMatrix * viewMatrix;

for (int i = 0; i < pl.Count; i++)

{

pl[i] = PV.inverse.MultiplyPoint(pl[i]);

}

}

public void UnProjectScreenToWorld(

IReadOnlyList projection,

IReadOnlyList view,

ref List pl,

float width,

float height,

bool rowBase = true,

bool flipLeftToRight = false,

bool flipUpsideDown = false

)

{

Matrix4x4 projectionMatrix = ConstructMatirx(projection, rowBase);

Matrix4x4 viewMatrix = ConstructMatirx(view, rowBase);

Matrix4x4 PV = projectionMatrix * viewMatrix;

ScreenSpaceTransform(ref pl, width, height, flipLeftToRight, flipUpsideDown);

for(int i = 0; i < pl.Count; i++)

{

pl[i] = PV.inverse.MultiplyPoint(pl[i]);

}

}

///

/// 获得相机的世界坐标,遵从 Direct3D 标准的左手笛卡尔坐标系。

///

/// 视点矩阵

///

public Vector3 GetCameraPosition(Matrix4x4 viewMatrix)

{

Matrix4x4 invV = viewMatrix.inverse;

return new Vector3(invV.m30, invV.m31, invV.m32);

}

///

/// 获得相机的世界坐标,遵从 Direct3D 标准的左手笛卡尔坐标系。

///

/// 视点矩阵元素列表

/// 列表是否以行优先进行矩阵元素的存储

///

public Vector3 GetCameraPosition(IReadOnlyList view, bool rowBase = true)

{

Matrix4x4 viewMatrix = ConstructMatirx(view, rowBase);

Matrix4x4 invV = viewMatrix.inverse;

return new Vector3(invV.m30, invV.m31, invV.m32);

}

///

/// 获得相机的视线方向,遵从 Direct3D 标准的左手笛卡尔坐标系。

///

/// 视点矩阵

///

public Vector3 GetCameraViewDirection(Matrix4x4 viewMatrix)

{

Matrix4x4 invV = viewMatrix.inverse;

return new Vector3(invV.m20, invV.m21, invV.m22);

}

///

/// 获得相机的视线方向,遵从 Direct3D 标准的左手笛卡尔坐标系。

///

/// 视点矩阵元素列表

/// 列表是否以行优先进行矩阵元素的存储

///

public Vector3 GetCameraViewDirection(IReadOnlyList view, bool rowBase = true)

{

Matrix4x4 viewMatrix = ConstructMatirx(view, rowBase);

Matrix4x4 invV = viewMatrix.inverse;

return new Vector3(invV.m20, invV.m21, invV.m22);

}

///

/// 将屏幕点坐标转换成以屏幕中心为原点,

/// 右和上分别为x,y正方向,

/// -1到1的坐标

///

/// 屏幕宽或高

/// 像素坐标(指定宽则为横坐标,指定高则为纵坐标)

/// 是否翻转(Unity通常情况下会将纵坐标翻转)

///

public void ScreenSpaceTransform(ref Vector3 p, float width, float height, bool flipLeftToRight = false, bool flipUpSideDown = false)

{

p.Set((p.x / width * 2 - 1) * (flipLeftToRight ? -1 : 1),

(p.y / height * 2 - 1) * (flipUpSideDown ? -1 : 1),

p.z);

}

public void ScreenSpaceTransform(ref List pl, float width, float height, bool flipLeftToRight = false, bool flipUpSideDown = false)

{

for(int i = 0; i

{

pl[i].Set((pl[i].x / width * 2 - 1) * (flipLeftToRight ? -1 : 1),

(pl[i].y / height * 2 - 1) * (flipUpSideDown ? -1 : 1),

pl[i].z);

}

}

///

/// 从列表中构造Matirx4x4矩阵

///

/// 矩阵元素列表

/// 列表是否以行优先进行矩阵元素的存储

///

public Matrix4x4 ConstructMatirx(IReadOnlyList elements, bool rowBase = true)

{

if (elements.Count != 16) return Matrix4x4.identity;

Matrix4x4 mat = new Matrix4x4();

if (rowBase)

{

mat.m00 = elements[0];

mat.m01 = elements[1];

mat.m02 = elements[2];

mat.m03 = elements[3];

mat.m10 = elements[4];

mat.m11 = elements[5];

mat.m12 = elements[6];

mat.m13 = elements[7];

mat.m20 = elements[8];

mat.m21 = elements[9];

mat.m22 = elements[10];

mat.m23 = elements[11];

mat.m30 = elements[12];

mat.m31 = elements[13];

mat.m32 = elements[14];

mat.m33 = elements[15];

}

else

{

mat.m00 = elements[0];

mat.m10 = elements[1];

mat.m20 = elements[2];

mat.m30 = elements[3];

mat.m01 = elements[4];

mat.m11 = elements[5];

mat.m21 = elements[6];

mat.m31 = elements[7];

mat.m02 = elements[8];

mat.m12 = elements[9];

mat.m22 = elements[10];

mat.m32 = elements[11];

mat.m03 = elements[12];

mat.m11 = elements[13];

mat.m23 = elements[14];

mat.m33 = elements[15];

}

return mat;

}

}

坐标的转换,用的地方特别多,尤其是屏幕划线展示在世界坐标中,我把他形成了工具,直接可以用。

unity 坐标系转换_Unity3D之笛卡尔坐标系转换——屏幕坐标转换世界坐标 世界坐标转换相机坐标工具...

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。