Unity3D 知识点:坐标系统

Unity3D 知识点:坐标系统

  • 手系
  • OpenGL内部坐标系空间
  • 坐标系空间的转换
  • 矩阵
    • 矩阵的含义
    • Unity Transform级联约定
      • Unity 旋转的级联约定
    • 矩阵相乘
    • 某点P绕自身所在空间中的某点O旋转
    • 坐标系变换的各矩阵
      • 齐次坐标
      • 平移变换
      • 旋转变换
      • 缩放变换
      • 切边变换
    • UnityShader内部的矩阵
  • Unity中的世界、视口、屏幕坐标系统
    • 坐标转换
      • 屏幕坐标转到视口、世界坐标:
      • 世界坐标转视口、屏幕坐标

手系

  • Unity坐标系统: 模型空间和世界空间使用左手坐标系,Z轴指向屏幕里面;在摄像机空间使用右手坐标系。Z轴指向屏幕外。 (无法看到,只在计算中用到)。转换到裁剪空间又变成左手坐标系.
  • OpenGL: 使用右手坐标系。
  • DirectX: 使用左手坐标系。

OpenGL内部坐标系空间

OpenGL内部只定义了: 裁剪空间规范化设备空间屏幕空间
模型空间、世界空间、摄像机空间是为了方便用户而自定义的空间。

坐标系空间的转换

模型空间 -> 模型变换(M) -> 世界空间 -> 视变换(V) -> 摄像机空间 -> 投影变换( P ) -> 裁剪空间 -> 透视除法 -> 规范化设备空间(NDC) -> 屏幕映射 -> 屏幕空间

链接:模型、世界、观察、裁剪空间坐标转换
链接:unity 七种坐标系统详解与互相转换的方法
链接:矩阵与空间变换
连接:在Unity的后处理shader中通过屏幕像素坐标和深度贴图反推世界坐标

  • 自定义变换:模型空间到裁剪空间的变换在顶点着色器中完成:
    o.pos=mul(_unity_MVP, v.pos)
  • OpenGL变换:裁剪空间到屏幕空间的变换,系统自动完成。
  • 物体在摄像机空间,就变成右手坐标系。

矩阵

矩阵的含义

矩阵一般 用来表示一个点在子空间中的坐标为P,其转换到父空间中的坐标为P,则矩阵M定义了这种转换。
某矩阵可表示为:Unity3D 知识点:坐标系统_第1张图片
Xc,Yc,Zc表示子空间的三个轴在父空间的方向,也表示子空间的三个单位方向轴的终点在父空间中的坐标。
Oc表示子空间的原点在父空间中的位置。
则子空间中的点在父空间中的表示:P=M*P

Unity Transform级联约定

Unity中的Transform组件变换为最终的矩阵。
在这里插入图片描述
两种顺序的理解:

  • 从右向左乘: 把点P放入父空间,在父空间中缩放 => 在父空间中旋转 => 在父空间中位移。
  • 从左向右乘: 把子空间(包含点P)和父空间对齐,子空间沿自身位移 => 子空间沿自身旋转 => 子空间沿自身缩放。

如果以其它顺序,则会产生不正常的结果。参见:

Unity 旋转的级联约定

在这里插入图片描述
两种顺序的理解:

  • 从右向左乘:点P放入父空间(其局部坐标视为在父空间中坐标),绕父空间Y轴旋转 => 绕父空间X轴旋转 => 绕父空间Z轴旋转
  • 从左向右乘:子空间(包含P点)与父空间对齐,绕自身Z轴旋转 => 绕自身X轴旋转 => 绕自身Y轴旋转

矩阵相乘

矩阵相乘满足结合律
((M1 X M2) X M3) X M~4` == M1 X (M2 X (M3 X M4)) == (M1 X M2) X (M3 X M4)
顺序不变,括号随便加。
从左往右乘:表示都是子空间(内含某点)沿自身空间轴变换。
从右向左乘:都是某点在父空间内变换。

某点P绕自身所在空间中的某点O旋转

某空间L内某点p绕L空间内某点o的旋转:p’ = To X R X (-To) X p
To为o点在L空间内的坐标。R为旋转的角度(也可以是一个纯旋转矩阵或者一个四元素)。

  • 从左向右乘的理解为:点p自带的局部空间的原点移到o点上, 局部空间沿自身轴旋转R角度,局部空间沿着自身轴移动(-To)。
  • 从右向左的理解为:点P在L空间内先移动-To(相当于点o移到了L空间的原点,点p跟着移动),点p在L空间中旋转R角度,点P在L空间内再移动To。
  • 还有一种理解:点P被绑定到点O作为原点的一个空间。点O移动到L空间的原点,点O在L空间旋转R角度,点O再移动到原先的位置,由于点P被和点O绑在了一起,所以点P跟着点O移动和转动。

坐标系变换的各矩阵

链接:unity shader中的矩阵变换知识

齐次坐标

  • 用4维来表示3维,其中w=0表示向量,w=1表示点。为了计算上的方便同一。
    齐次坐标矩阵:
    Unity3D 知识点:坐标系统_第2张图片
    点表示为:(Px, Py, Pz, 1),方向表示为:(Vx, Vy, Vz,0)

平移变换

  • (Px+tx, Py+ty, Pz+tz, 1), (Vx+0, Vy+0, Vz+0, 0)

Unity3D 知识点:坐标系统_第3张图片
方向向量(Vx, Vy, Vz,0)乘以该矩阵,结果不变,表示向量无法位移。

旋转变换

点绕X轴旋转:(Px,PycosA-PzsingA, PysinA+pZcosA, 1),向量和点一致(w=0)
表示:点的X坐标不变,Y和Z坐标都变,而且都和YZ坐标有关。
从子空间理解:子空间的Y和Z轴向绕自身X轴旋转,那么子空间的Z轴转到父空间Y轴的下面去了,因此子空间的Z轴点在父空间中Y轴的负方向上。
Unity3D 知识点:坐标系统_第4张图片

缩放变换

(Px Sx, PysY, PzSz,1), (Vx Sx, VysY, VzSz,0),

Unity3D 知识点:坐标系统_第5张图片

切边变换

一共有六种,如:Hxz, Hxy,…
Hxz:表示在xz平面内,沿着x轴进行切变。(Px+Pz*S, Py, Pz,1)
Unity3D 知识点:坐标系统_第6张图片
上图可表示,子空间的Z轴末端点在父空间的X轴上发生位移。
Unity3D 知识点:坐标系统_第7张图片

UnityShader内部的矩阵

1:模型空间 ;2:世界空间; 3:观察空间; 4:裁剪空间(投影空间)

UNITY_MATRIX_MVP:将坐标或者方向从1到4
UNITY_MATRIX_MV:将坐标或者方向从1到3
UNITY_MATRIX_VP:将坐标或者方向从2到4
UNITY_MATRIX_V:将坐标或者方向从2到3
UNITY_MATRIX_P:将坐标或者方向从3到4

unity_ObjectToWorld:将顶点或者方向从1到2
unity_WorldToObject:unity_ObjectToWorld的逆矩阵,用于将顶点方向从2到1

UNITY_MATRIX_IT_MV:

  • 这是 UNITY_MATRIX_MV 的逆转置矩阵,专门用于将法线从模型空间变换到观察空间。如果UNITY_MATRIX_MV为正交矩阵(意味着只有旋转操作),那么UNITY_MATRIX_MV就等于UNITY_MATRIX_IT_MV。如果有统一缩放操作,UNITY_MATRIX_IT_MV = (1/k)*UNITY_MATRIX_MV ,k为缩放系数。
  • 为什么不用UNITY_MATRIX_MV来处理法线,因为如果模型有不统一缩放的时候,用UNITY_MATRIX_MV会造成方向失真。
  • 也可以把这个矩阵转置一下或者UNITY_MATRIX_MV的逆矩阵,就可以把顶点或者方向矢量从观察空间变换到模型空间,例如
    float4 modelPos = mul(transpose(UNITY_MATRIX_IT_MV),viewPos)=mul(viewPos,UNITY_MATRIX_IT_MV);

UNITY_MATRIX_T_MV:

  • UNITY_MATRIX_MV的转置矩阵,因为求一个矩阵的逆矩阵需要巨大的运算量,但是求一个矩阵的转置矩阵就很简单了,所以当一个矩阵为正交矩阵的时候,通过转置矩阵或者逆矩阵是一个很有用的方法,我们在计算一些方向矢量,不考虑平移操作,缩放系数设为1,这样就可以用这个矩阵来计算从观察空间到模型空间的方向矢量变换

Unity中的世界、视口、屏幕坐标系统

  • 世界坐标系统:全局不变
  • 视口坐标系统:左下角为(0,0),右上角为(1,1)。和某个Camera关联。
  • 屏幕坐标系统 : 左下角为(0,0),右上角为(screen.Width,screen.Height),全局不变。

坐标转换

三者之间在Unity脚本内的坐标转换都要使用得到Camera组件。

屏幕坐标转到视口、世界坐标:

//获取鼠标的屏幕系位置
var mousePos		= Input.mousePosition; //此时mousePos.z为0
mousePos.z			= 11.4;	//必须要重新设置鼠标位置的z值。 表示当前离摄像机Z方向的距离(米)。

var viewportPos		= Camera.main.ScreenToViewportPoint(mousePos); //此时viewportPos.z保持和mousePos.z相同。

var worldPos		= Camera.main.ScreenToWorldPoint(mousePos); //此时worldPos.z表示:摄像机前方距离为mousePos.z的世界坐标。
//注意:如果mousePos.z设置为0 , 则worldPos始终为摄像机的世界坐标。

鼠标屏幕坐标转换为世界坐标的意义:相当于鼠标点在摄像机前方z距离的视口形状的平面内移动。
camera.ScreenToWorldPoint()内部应该是先转换到Viewport的坐标,再转换到世界坐标。
如果摄像机的视口没有填充整个屏幕,则以视口在屏幕内的形状为准。

世界坐标转视口、屏幕坐标

//获取某物体的世界坐标
var worldPos	= cube.Transform.position;

var viewportPos	= Camera.main.WorldToViewportPoint(worldPos); //此时的viewportPos.z为该点距离摄像机Z方向的距离。

var screenPos	= Camera.main.WorldToScreenPoint(worldPos);  //此时的screenPos.z为该点距离摄像机Z方向的距离。

相关链接:
Unity中屏幕坐标、视口坐标和世界坐标、局部坐标与其之间的相互转换

你可能感兴趣的:(Unity3D,shader,unity3d)