Unity Shader入门精要--第4 章 学习Shader 所需的数学基础:矩阵的几何意义:变换

Unity系列文章目录

前言

关于矩阵,很多困扰初学者的问题都是类似的:
 点和矢量都可以在图像中画出来,那么矩阵可以吗?
 我听说矩阵和线性变换、仿射变换有关,这些变换到底是什么意思呢?
 我总是听到齐次坐标这个名词,它是什么意思呢?
 变换和矩阵的关系又是什么呢?或者说,给定一个变换,我如何得到它对应的矩阵呢?
在学习完本节后,希望读者们能够回答出这些问题。
对于第一个问题,在三维渲染中矩阵可以可视化吗?幸运的是,答案是肯定的,这个可视化
的结果就是变换。因此,如果读者在后面的内容中看到了一个矩阵,那么你可以认为自己看到的
就是一个变换(当然,在线性代数中矩阵的用处不仅是用于变换,但本书的讨论范围仅在于此)。
在游戏的世界中,这些变换一般包含了旋转、缩放和平移。游戏开发人员希望给定一个点或
矢量,再给定一个变换(例如把点平移到另一个位置,把矢量的方向旋转30°等),就可以通过某
个数学运算来求得新的点和矢量。聪明的先人们发现,可以使用矩阵来完美地解决这个问题。那
么问题就变成了,我们如何使用矩阵来表示这些变换?

一、什么是变换

变换(transform),指的是我们把一些数据,如点、方向矢量甚至是颜色等,通过某种方式
进行转换的过程。在计算机图形学领域,变换非常重要。尽管通过变换我们能够进行的操作是有
限的,但这些操作已经足够奠定变换在图形学领域举足轻重的地位了。
我们先来看一个非常常见的变换类型—线性变换(linear transform)。线性变换指的是那
些可以保留矢量加和标量乘的变换。用数学公式来表示这两个条件就是:
f(x)+f(y)=f(x+y)
kf(x)=f(kx)
上面的式子看起来很抽象。缩放(scale)就是一种线性变换。例如,f(x)=2x,可以表示一个
大小为2 的统一缩放,即经过变换后矢量x 的模将被放大两倍。可以发现,f(x)=2x 是满足上面的
两个条件的。同样,旋转(rotation)也是一种线性变换。对于线性变换来说,如果我们要对一个
三维的矢量进行变换,那么仅仅使用3×3 的矩阵就可以表示所有的线性变换。
线性变换除了包括旋转和缩放外,还包括错切(shear)、镜像(mirroring,也被称为reflection)、
正交投影(orthographic projection)等,但本书着重讲述旋转和缩放变换。
但是,仅有线性变换是不够的。我们来考虑平移变换,例如f(x)=x+(1,2,3)。这个变换就不是
一个线性变换,它既不满足标量乘法,也不满足矢量加法。如果我们令x=(1,1,1),那么:
f(x)+f(x)=(4,6,8)
f(x+x)=(3,4,5)

可见,两个运算得到的结果是不一样的。因此,我们不能用一个3×3 的矩阵来表示一个平移
变换。这是我们不希望看到的,毕竟平移变换是非常常见的一种变换。
这样,就有了仿射变换(affine transform)。仿射变换就是合并线性变换和平移变换的变换
类型。仿射变换可以使用一个4×4 的矩阵来表示,为此,我们需要把矢量扩展到四维空间下,这
就是齐次坐标空间(homogeneous space)。
表4.1 给出了图形学中常见变换矩阵的名称和它们的特性。
在这里插入图片描述
在下面的内容中,我们将学习其中一些基本的变换类型:旋转,缩放和平移。对于正交投影
和透视投影,我们将在4.6.7 节中给出它们的表示方法。而对于其他变换类型,本书不再具体讨论,
读者可以在本章的扩展阅读中找到更多内容。
4.5.2 齐次坐标
我们知道,由于3×3 矩阵不能表示平移操作,我们就把其扩展到了4×4 的矩阵(是的,只
要多一个维度就可以实现对平移的表示)。为此,我们还需要把原来的三维矢量转换成四维矢量,
也就是我们所说的齐次坐标(homogeneous coordinate)(事实上齐次坐标的维度可以超过四维,
但本书中所说的齐次坐标将泛指四维齐次坐标)。我们可以发现,齐次坐标并没有神秘的地方,它
只是为了方便计算而使用的一种表示方式而已。
如上所说,齐次坐标是一个四维矢量。那么,我们如何把三维矢量转换成齐次坐标呢?对于
一个点,从三维坐标转换成齐次坐标是把其w 分量设为1,而对于方向矢量来说,需要把其w 分
量设为0。这样的设置会导致,当用一个4×4 矩阵对一个点进行变换时,平移、旋转、缩放都会
施加于该点。但是如果是用于变换一个方向矢量,平移的效果就会被忽略。我们可以从下面的内
容中理解这些差异的原因。
4.5.3 分解基础变换矩阵
我们已经知道,可以使用一个4×4 的矩阵来表示平移、旋转和缩放。我们把表示纯平移、纯
旋转和纯缩放的变换矩阵叫做基础变换矩阵。这些矩阵具有一些共同点,我们可以把一个基础变
换矩阵分解成4 个组成部分:
在这里插入图片描述

其中,左上角的矩阵M3×3 用于表示旋转和缩放,t3×1 用于表示平移,01×3 是零矩阵,即01×3=[0
0 0],右下角的元素就是标量1。
接下来,我们来具体学习如何用这样一个4×4 的矩阵来表示平移、旋转和缩放。
4.5.4 平移矩阵
我们可以使用矩阵乘法来表示对一个点进行平移变换:
在这里插入图片描述
从结果来看我们可以很容易看出为什么这个矩阵有平移的效果:点的x、y、z 分量分别增加
了一个位置偏移。在3D 中的可视化效果是,把点(x,y,z)在空间中平移了(tx,ty,tz)个单位。
有趣的是,如果我们对一个方向矢量进行平移变换,结果如下:

在这里插入图片描述
可以发现,平移变换不会对方向矢量产生任何影响。这点很容易理解,我们在学习矢量的时
候就说过了,矢量没有位置属性,也就是说它可以位于空间中的任意一点,因此对位置的改变(即
平移)不应该对方向矢量产生影响。
现在,读者应该明白当给定一个平移操作时如何构建一个平移矩阵:基础变换矩阵中的t3×1
矢量对应了平移矢量,左上角的矩阵M3×3 为单位矩阵I3。
平移矩阵的逆矩阵就是反向平移得到的矩阵,即
在这里插入图片描述

可以看出,平移矩阵并不是一个正交矩阵。
4.5.5 缩放矩阵
我们可以对一个模型沿空间的x 轴、y 轴和z 轴进行缩放。同样,我们可以使用矩阵乘法来
表示一个缩放变换:

在这里插入图片描述
对方向矢量可以使用同样的矩阵进行缩放:
在这里插入图片描述

如果缩放系数kx=ky=kz,我们把这样的缩放称为统一缩放(uniform scale),否则称为非统一
缩放(nonuniform scale)。从外观上看,统一缩放是扩大整个模型,而非统一缩放会拉伸或挤压
模型。更重要的是,统一缩放不会改变角度和比例信息,而非统一缩放会改变与模型相关的角度
和比例。例如在对法线进行变换时,如果存在非统一缩放,直接使用用于变换顶点的变换矩阵的
话,就会得到错误的结果。正确的变换方法可参见4.7 节。
缩放矩阵的逆矩阵是使用原缩放系数的倒数来对点或方向矢量进行缩放,即

在这里插入图片描述

缩放矩阵一般不是正交矩阵。
上面的矩阵只适用于沿坐标轴方向进行缩放。如果我们希望在任意方向上进行缩放,就需要
使用一个复合变换。其中一种方法的主要思想就是,先将缩放轴变换成标准坐标轴,然后进行沿
坐标轴的缩放,再使用逆变换得到原来的缩放轴朝向。
4.5.6 旋转矩阵
旋转是三种常见的变换矩阵中最复杂的一种。我们知道,旋转操作需要指定一个旋转轴,这
个旋转轴不一定是空间中的坐标轴,但本节所讲的旋转就是指绕着空间中的x 轴、y 轴或z 轴进
行旋转。
如果我们需要把点绕着x 轴旋转度,可以使用下面的矩阵:

在这里插入图片描述
最后,是绕z 轴的旋转:
在这里插入图片描述

旋转矩阵的逆矩阵是旋转相反角度得到的变换矩阵。旋转矩阵是正交矩阵,而且多个旋转矩
阵之间的串联同样是正交的。
4.5.7 复合变换
我们可以把平移、旋转和缩放组合起来,来形成一个复杂的变换过程。例如,可以对一个模
型先进行大小为(2, 2, 2)的缩放,再绕y 轴旋转30°,最后向z 轴平移4 个单位。复合变换可以通
过矩阵的串联来实现。上面的变换过程可以使用下面的公式来计算:
pnew =MtranslationMrotationMscalepold
由于上面我们使用的是列矩阵,因此阅读顺序是从右到左,即先进行缩放变换,再进行旋转
变换,最后进行平移变换。需要注意的是,变换的结果是依赖于变换顺序的,由于矩阵乘法不满
足交换律,因此矩阵的乘法顺序很重要。也就是说,不同的变换顺序得到的结果可能是不一样的。
想象一下,如果让读者向前一步然后左转,记住此时的位置。然后回到原位,这次先左转再向前
走一步,得到的位置和上一次是不一样的。究其本质,是因为矩阵的乘法不满足交换律,因此不
同的乘法顺序得到的结果是不一样的。
在绝大多数情况下,我们约定变换的顺序就是先缩放,再旋转,最后平移。
读者:为什么要约定这样的顺序,而不是其他顺序呢?
我们:因为这样的变换顺序是我们需要的。想象我们对奶牛妞妞进行一个复合变换。如
果我们按先平移、再缩放的顺序进行变换,假设初始情况下妞妞位于原点,我们先按(0, 0, 5)
平移它,现在它距离原点5 个单位。然后再将它放大2 倍,这样所有的坐标都变成了原来的2
倍,而这意味着妞妞现在的位置是(0, 0, 10),这不是我们希望的。正确的做法是,先缩放再平
移。也就是说,我们先在原点对妞妞进行2 倍的缩放,再进行平移,这样妞妞的大小正确了,
位置也正确了。
为了从数学公式上理解变换顺序的本质,我们可以对比不同变换顺序产生的变换矩阵的表达
式。如果我们只考虑对y 轴的旋转的话,按先缩放、再旋转、最后平移这样的顺序组合3 种变换
得到的变换矩阵是:

在这里插入图片描述

而如果我们使用了其他变换顺序,例如先平移,再缩放,最后旋转,那么得到的变换矩阵是:

在这里插入图片描述
从两个结果可以看出,得到的变换矩阵是不一样的。
除了需要注意不同类型的变换顺序外,我们有时还需要小心旋转的变换顺序。在4.5.6 节中,
我们给出了分别绕x 轴、y 轴和z 轴旋转的变换矩阵。一个问题是,如果我们需要同时绕着3 个
轴进行旋转,是先绕x 轴、再绕y 轴最后绕z 轴旋转还是按其他的旋转顺序呢?
当我们直接给出( 
x, 
y, 
z)这样的旋转角度时,需要定义一个旋转顺序。在Unity 中,这个旋转
顺序是zxy,这在旋转相关的API 文档中都有说明。这意味着,当给定( 
x, 
y, 
z)这样的旋转角度时,
得到的组合旋转变换矩阵是:

在这里插入图片描述

一些读者会有疑问:上面的公式书写顺序是不是反了?不是说列矩阵要从右往左读吗?这样
一来顺序不就颠倒了吗?实际上,有一个非常重要的东西我们没有说明白,那就是旋转时使用的
坐标系。给定一个旋转顺序(例如这里的zxy),以及它们对应的旋转角度( 
x, 
y, 
z),有两种坐标
系可以选择。
 绕坐标系E 下的z 轴旋转
z,绕坐标系E 下的y 轴旋转
y,绕坐标系E 下的x 轴旋转
x,
即进行一次旋转时不一起旋转当前坐标系。
 绕坐标系E 下的z 轴旋转
z,在坐标系E 下绕z 轴旋转
z 后的新坐标系E’下的y 轴旋转
y,
在坐标系E’下绕y 轴旋转
y 后的新坐标系E’'下的x 轴旋转
x,即在旋转时,把坐标系一起转动。
很容易知道,这两种选择的结果是不一样的。但如果把它们的旋转顺序颠倒一下,它们得到
的结果就会是一样的!说得明白点,在第一种情况下,按zxy 顺序旋转和在第二种情况下,按yxz
顺序旋转是一样的。而Unity 文档中说明的旋转顺序指的是在第一种情况下的顺序。
和上面不同类型的变换顺序导致的问题类似,不同的旋转顺序得到的结果也可能是不一样的。
我们同样可以通过对比不同旋转顺序得到的变换矩阵来理解为什么会出现这样的不同。而这个验
证过程留给读者作为练习。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity Shader是一种用于渲染图形的程序,它可以控制对象的表面颜色、纹理、透明度、反射等属性,从而实现特殊的视觉效果。对于游戏开发者来说,掌握Shader编写技巧是非常重要的。 以下是关于Unity Shader入门要: 1. ShaderLab语言 ShaderLab是Unity中用于编写Shader的语言,它是一种基于标记的语言,类似于HTML。ShaderLab可以用于定义Shader的属性、子着色器、渲染状态等信息。 2. CG语言 CG语言是Unity中用于编写Shader的主要语言,它是一种类似于C语言的语言,可以进行数学运算、向量计算、流程控制等操作。CG语言可以在ShaderLab中嵌入,用于实现Shader的具体逻辑。 3. Unity的渲染管线 Unity的渲染管线包括顶点着色器、片元着色器、几何着色器等组件,每个组件都有不同的作用。顶点着色器用于对对象的顶点进行变换,片元着色器用于计算每个像素的颜色,几何着色器用于处理几何图形的变形和细节等。 4. 模板和纹理 在Shader中,我们可以使用纹理来给对象添加图案或者贴图,也可以使用模板来控制对象的透明度、反射等属性。纹理可以通过内置函数tex2D()来获取,模板可以通过内置函数clip()来实现裁剪。 5. Shader的实现 Shader的实现要注意以下几点: - 在ShaderLab中定义Shader的属性、子着色器、渲染状态等信息。 - 在CG语言中实现Shader的具体逻辑,包括顶点着色器、片元着色器等内容。 - 使用纹理和模板来实现特定的视觉效果。 - 在对象上应用Shader,通过调整Shader的属性来达到不同的效果。 以上是关于Unity Shader入门要,希望对你有所帮助。如果你想更深入地了解Shader的编写技巧,可以参考官方文档或者相关教程。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值