Unity Shader学习三:坐标空间的变换

(注意,由于格式问题,文中如p-c、c-p、c、p这类的为矢量的下标,-1、T为矩阵的上标)

假设现在有一个父坐标空间以及一个子坐标空间,已知父级坐标空间中子级坐标空间的原点位置以及3个单位坐标轴,此时一般由两种需求:一种是将子坐标空间下表示的点或矢量Ac转换到父坐标空间下的表示Ap;另一种需求是反过来,即把父坐标空间下表示的点或矢量Bp转换到子坐标空间下的表示Bc。可以使用下面的两个公式来表示这两种需求:

Ap = Mc-p Ac

Bc = Mp-c Bp

其中Mc-p表示从子坐标空间变换到父坐标空间的变换矩阵,而Mp-c是其逆矩阵(即反向变换)。此时,只需求解出其中一个矩阵,另一个通过求逆矩阵的方法来得到。

当给定一个坐标空间以及其中的一点(a, b, c)时,可以通过4个步骤来确定它的位置:

1.从坐标轴的原点开始;

2.向x轴方向移动a个单位;

3.向y轴方向移动b个单位;

4.向z轴方向移动c个单位。

此时已知子坐标空间C的3个坐标轴在父坐标空间P下的表示Xc,Yc,Zc,以及其原点位置Oc。当给定一个子坐标空间中的一个点Ac = (a,b,c),使用上述的4步来确定点Ac在父坐标空间下的位置Ap:

1.从坐标空间的原点开始:

已知子坐标空间的原点位置Oc;

2.向x轴方向移动a个单位

Oc + aX

3.向y轴方向移动b个单位

Oc + aXc + bYc

4.向z轴方向移动c个单位

Oc + aXc + bYc + cZc

此时得到公式:

Ap = Oc + aXc + bYc + cZc        (将所有矢量展开)

其中“|”符号表示按列展开,最后还可以加上加法表达式即平移变换,此时需要将上面公式中的3x3矩阵扩展到齐次坐标空间中,得到

此时,可得Mc-p 矩阵为

 一旦求出Mc-p矩阵后,Mp-c矩阵可以通过求逆矩阵的方法得到。

由矩阵结果可以看出,变换矩阵Mc-p实际上可以通过坐标空间C在坐标空间P中的原点和坐标轴的矢量表示来构建的:把3个坐标轴一次放入矩阵的前3列,把原点矢量放到最后一列,再用0和1填充最后一行即可。

需要注意的是,并不需要要求3个坐标轴Xc,Yc,Zc是单位矢量,实际上如果存在缩放的话,这3个矢量很可能不是单位矢量。

使用反向思维,可以从这个变换矩阵反推来获得子坐标空间的原点与坐标轴方向。例如,已知从模型空间到世界空间的一个4x4的变换矩阵,可以提取它的第一列再进行归一化后(为了消除缩放的影响)来得到模型空间的x轴再世界空间下的单位矢量表示。同样的方法可以提取y轴和z轴。

从另一个角度来理解这个提取过程,因为矩阵Mc-p可以把一个方向矢量从坐标空间C变换到坐标空间P中,那么只需要用这个矩阵来变换坐标空间C的x轴(1,0,0,0),即使用矩阵乘法         Mc-p[1,0,0,0]T,得到的结果正是Mc-p矩阵的第一列。

由于对方向矢量进行的坐标空间变换是可以忽略位置变换(平移)的,所以对方向矢量的坐标空间变换可以使用3x3矩阵,即

Mc-p = 

再Shader中,常常截取变换矩阵的前3行与前3列来对法线方向、光照方向进行空间变换。

 前面提过Mc-p表示从子坐标空间变换到父坐标空间的变换矩阵,而Mp-c是其逆矩阵(即反向变换由父坐标空间变换到子坐标空间),但是当Mc-p为正交矩阵时,矩阵的逆矩阵等于它的转置矩阵,即Mc-p-1 = Mc-pT,所以

此时,不仅可以通过变换矩阵Mc-p反推出子坐标空间的坐标轴方向再父坐标空间中的表示Xc,Yc,Zc,还可以反推出父坐标空间的坐标轴方向再子坐标空间中的表示Xp,Yp,Zp,这些坐标轴对应的就是变换矩阵Mc-p的每一行。

也就是说,若坐标空间变换矩阵Ma-b是一个正交矩阵,那么就可以提取其第一列来得到坐标空间a的x轴在坐标空间b下的表示,还可以提取其第一行来得到坐标空间b的x轴在坐标空间a下的表示。反过来,如果知道坐标空间b的x,y,z轴(必须是单位矢量,否则构建出来的就不是正交矩阵了)在坐标空间a下的表示,就可以将它们依次放在矩阵的每一行来得到坐标空间a到坐标空间b的变换矩阵了

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,您的第一个问题是关于Unity Shader学习笔记,具体是在表面着色器中控制顶点变换。那么我可以回答您的问题。 在Unity中,表面着色器是一种用于控制物体表面外观的程序。它们可以控制颜色、纹理和光照等方面。而在表面着色器中,我们可以使用顶点变换来控制物体表面的外观。 顶点变换是一个将物体的顶点坐标从局部空间转换为世界空间或者相机空间的过程。在表面着色器中,我们可以通过在CG程序中编写代码来实现顶点变换。以下是一个简单的例子: ```CG // 定义变换矩阵 float4x4 worldMatrix; float4x4 viewMatrix; float4x4 projectionMatrix; // 定义输入结构体 struct appdata { float4 vertex : POSITION; }; // 定义输出结构体 struct v2f { float4 vertex : SV_POSITION; }; // 顶点变换函数 v2f vert (appdata v) { v2f o; o.vertex = mul(mul(mul(v.vertex, worldMatrix), viewMatrix), projectionMatrix); return o; } ``` 在这个例子中,我们定义了变换矩阵:世界矩阵、视图矩阵和投影矩阵。然后定义了一个输入结构体appdata,其中包含了顶点的位置信息。输出结构体v2f则只包含了顶点的位置信息,用于传递给像素着色器。 在vert函数中,我们首先将顶点从局部空间转换到世界空间,然后再从世界空间转换到相机空间,最后再从相机空间转换到屏幕空间。这个过程中使用了mul函数来进行矩阵乘法运算。 通过这样的方式,我们可以在表面着色器中控制顶点变换,从而实现对物体表面外观的控制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值