《Unity Shader入门精要》读书笔记03

铁名_IronName Lv2

第 4 章 数学基础

笛卡尔坐标系(Cartesian Coordinate System)

  • 二维笛卡尔坐标系;三维笛卡尔坐标系

  • 基矢量(basis vector):坐标系的坐标轴

  • 标准正交基(orthonormal basis):相互垂直,长度为 1

  • 正交基(orthogonal basis):相互垂直

  • 旋向性(handedness):相同旋向性的坐标轴可通过旋转重合

  • 左手坐标系(left-handed coordinate space):
    左手(拇指,食指,中指)->(+x, +y, +z)
    左手法则(left-hand rule)- 左手“点赞”

  • 右手坐标系(right-handed coordinate space):
    右手(拇指,食指,中指)->(+x, +y, +z)
    右手法则(right-hand rule)- 右手“点赞”

  • Unity 在模型/世界空间中使用左手坐标系,而在观察空间中使用右手坐标系。

练习题:1.右手坐标系 2.(1,0 ,0) (1,0 ,0) 3. -10 10

点和矢量

  • 点(point):一个位置
  • 矢量/向量(vector):n维空间中一种包含了模(magnitude)和方向(direction)的有向线段;是相对量,无论放在哪里都一样。
  • 对于标量,我们使用小写字母来表示,如α,b,x,y,z,θ,α等;
  • 对于矢量,我们使用小写的粗体字母来表示,如abuv 等;
  • 对于后面要学习的矩阵,我们使用大写的粗体字母来表示,如 ABSMR 等。

矢量运算

  1. 矢量和标量乘除
  2. 矢量加减——三角形定则(triangle rule)
  3. 矢量的模
v=vx2+vy2+vz2\left|\textbf{v}\right| = \sqrt{v_x^2 + v_y^2 + v_z^2}
  1. 单位矢量(unit vector)/ 被归一化的矢量(normalized vector)v^\hat{\textbf{v}} ——归一化(normalization)
v^=vv\hat{\textbf{v}} = \frac{\textbf{v}}{\left|\textbf{v}\right|}
  1. 矢量的点积/内积(dot product / inner product)——投影(projection)
ab=abcosθ\textbf{a}\cdot\textbf{b} = \left|\textbf{a}\right|\left|\textbf{b}\right|\cos{\theta}
  1. 矢量的叉积/外积(cross product / outer product)——计算垂直于一个平面、三角形的矢量;判断三角面皮的朝向
a×b不满足结合律/交换律\textbf{a}\times\textbf{b} \text{不满足结合律/交换律}

练习题:
1.(1)错 (2)对 (3)错
2.(1)62\sqrt{62} (2)(12.5, 10, 25) (3)(1.5, 2)
(4)(5/13, 12/13) (5)(33,33,33\frac{\sqrt{3}}{3},\frac{\sqrt{3}}{3},\frac{\sqrt{3}}{3}) (6)(10,9) (7)(-6, 1, 2)
3.308\sqrt{308}
4.(1)75(2)13 (3)13(4)(-9, -13, 17) (5)(9,13,-7)
5.(1)12 (2)20. 784
6.(1)若v(x-p)\textbf{v}\cdot(\textbf{x-p})>0,说明玩家在NPC前方;反之在后方
(2)上述公式中乘积小于零,同时根据画图可知玩家在NPC后方,(1)方法正确。
(3)计算vx-p的夹角θ\textbf{v}\text{和}\textbf{x-p}\text{的夹角}\thetaθ=arccosv(x-p)vx-p\theta = \arccos{\frac{\textbf{v}\cdot(\textbf{x-p})}{|\textbf{v}||\textbf{x-p}|}},然后将θ\thetaϕ\phi比较。也可以比较cosθ\cos\thetacosϕ2\cos\frac{\phi}{2}
(4)计算距离d=x-pd=|\textbf{x-p}|,将d固定的距离比较。
7.计算(p2p1)×(p3p1)(\textbf{p}_2-\textbf{p}_1)\times(\textbf{p}_3-\textbf{p}_1),若结果的z分量>0,根据左手法则,是逆时针排列。

矩阵(matrix)

数学家的Excel(

M=[m11m12m13m21m22m23m31m32m33]M=\begin{bmatrix} m_{11} & m_{12} & m_{13} \\ m_{21} & m_{22} & m_{23} \\ m_{31} & m_{32} & m_{33} \\ \end{bmatrix}

上面是三行三列的的矩阵。行(row)列(column)

矢量可以看成是 n×1n\times1列矩阵(column matrix)1×n1\times{n}行矩阵(row matrix),其中n对应了矢量的维度。

行矩阵[386]\text{行矩阵}\begin{bmatrix} 3 & 8 & 6 \\ \end{bmatrix} 列矩阵[386]\text{列矩阵}\begin{bmatrix} 3 \\ 8 \\ 6 \end{bmatrix}

矩阵运算

1.矩阵和标量的乘法:矩阵的每个元素和该标量相乘。
2.矩阵和矩阵的乘法:第一个矩阵的列数必须和第二个矩阵的行数相同,

cij=ai1b1j+ai2b2j++ainbnj=k=1naikbkjc_{ij}=a_{i1}b_{1j}+a_{i2}b_{2j}+\cdots+a_{in}b_{nj}=\sum_{k=1}^{n}a_{ik}b_{kj}
  • 矩阵乘法不满足交换律
  • 矩阵乘法满足结合律

特殊的矩阵

1.方块矩阵(square matrix)->对角矩阵(diagonal matrix)

[300020001]\begin{bmatrix} 3 & 0 & 0\\ 0 & -2 & 0\\ 0 & 0 & 1 \\ \end{bmatrix}

2.单位矩阵(identity matrix),用In\textbf{I}_n表示。相当于标量中的数字 1 。

I3=[100010001]\textbf{I}_3=\begin{bmatrix} 1 & 0 & 0\\ 0 & 1 & 0\\ 0 & 0 & 1 \end{bmatrix}

3.转置矩阵(transposed matrix),实际是对原矩阵的一种运算

[621037549]T=[672510439]\begin{bmatrix} 6 & 2 & 10 & 3\\ 7 & 5 & 4 & 9 \end{bmatrix}^T= \begin{bmatrix} 6 & 7 \\ 2 & 5 \\ 10 & 4 \\ 3 & 9 \\ \end{bmatrix} [xyz]T=[xyz]\begin{bmatrix} x & y & z \\ \end{bmatrix}^T= \begin{bmatrix} x \\ y \\ z \\ \end{bmatrix}
  • 性质一:矩阵转置的转置等于原矩阵。
(MT)T=M(\textbf{M}^T)^T=\textbf{M}
  • 性质二:矩阵串接的转置,等于反向串接各个矩阵的转置,
(AB)T=BTAT(\textbf{AB})^T=\textbf{B}^{T}\textbf{A}^T

4.逆矩阵(inverse matrix)
不是所有的矩阵都有逆矩阵,首先,该矩阵是一个方阵。
给定一个方阵M\textbf{M},它的逆矩阵用M1\textbf{M}^{-1}来表示。那么 MM1=M1M=I\textbf{M}\textbf{M}^{-1}=\textbf{M}^{-1}\textbf{M}=\textbf{I}

如果一个矩阵有对应的逆矩阵,我们就说这个矩阵是 可逆的(invertible) 或者说是 非奇异的(nonsingular);相反的,如果一个矩阵没有对应的逆矩阵,我们就说它是 不可逆的(noninvertible) 或者说是 奇异的(singular)

  • 判断方法:如果一个矩阵的 行列式(determinant) 不为0,那么它就是可逆的。
  • 性质一:逆矩阵的逆矩阵是原矩阵本身。
(M1)1=M(\textbf{M}^{-1})^{-1}=\textbf{M}
  • 性质二:单位矩阵的逆矩阵是它本身。
I1=I\textbf{I}^{-1}=\textbf{I}
  • 性质三:转置矩阵的逆矩阵是逆矩阵的转置。
(MT)1=(M1)T(\textbf{M}^{T})^{-1}=(\textbf{M}^{-1})^{T}
  • 性质四:矩阵串接相乘后的逆矩阵等于反向串接各个矩阵的逆矩阵。
(ABC)1=C1B1A1(\textbf{ABC})^{-1}=\textbf{C}^{-1}\textbf{B}^{-1}\textbf{A}^{-1}

5.正交矩阵(orthogonal matrix)
一个方阵和它的转置矩阵的乘积是单位矩阵,即 MMT=MTM=I\textbf{M}\textbf{M}^{T}=\textbf{M}^{T}\textbf{M}=\textbf{I}
等价于MT=M1\textbf{M}^{T}=\textbf{M}^{-1}
这个式子可以用于逆矩阵的求解。因为正交矩阵的逆矩阵就是它的转置矩阵。

  • 一个正交矩阵的行和列之间分别构成了一组标准正交基

在Unity中,常规做法是把矢量放在矩阵的右侧,即把矢量转换成列矩阵来进行运算。我们的矩阵乘法通常都是右乘,例如:

CBAv=(C(B(Av)))\textbf{CBAv}=\textbf{(C(B(Av)))}

从右到左,即先对 v\textbf{v} 使用A进行变换,再使用B进行变换,最后使用C进行变换。

练习题
1.(1)[111218]\begin{bmatrix}-1 &11\\-2&18\end{bmatrix}(2)乘积不存在
(3)[11116]\begin{bmatrix}11\\11\\-6\end{bmatrix}
2.(1)不是(2)是(3)是
3.(1)一样(2)不一样(3)一样
为了得到相同的结果,需要矩阵是对称矩阵(symmetric matrix,矩阵和转置矩阵相同);或者进行行矩阵乘法时,对矩阵进行转置。

矩阵和变换

变换(transform) 指的是我们把一些数据,如点、方向矢量甚至是颜色等,通过某种方式进行转换的过程。
线性变换(linear transform),指的是那些可以保留矢量加和标量乘的变换。公式如下

f(x)+f(y)=f(x+y)\textbf{f}(\textbf{x})+\textbf{f}(\textbf{y})=\textbf{f}(\textbf{x}+\textbf{y}) kf(x)=f(kx)k \textbf{f}(\textbf{x})=\textbf{f}(k\textbf{x})

线性变换包括旋转(rotation)和缩放(scale),错切(shear)、镜像(mirroring,也被称为 reflection)、正交投影(orthographic projection)等。

仿射变换(affine transform),是合并线性变换和平移变换的变换类型。仿射变换可以使用一个4x4的矩阵来表示,为此,我们需要把矢量扩展到四维空间下,这就是齐次坐标空间(homogeneous space)

变换名称是线性变换吗是仿射变换吗是可逆矩阵吗是正交矩阵吗
平移矩阵NYYN
绕坐标轴旋转的旋转矩阵YYYY
绕任意轴旋转的旋转矩阵YYYY
按坐标轴缩放的缩放矩阵YYYN
错切矩阵YYYN
镜像矩阵YYYY
正交投影矩阵YYNN
透视投影矩阵NNNN

齐次坐标(homogeneous coordinate)
对于一个点,从三维坐标转换成齐次坐标是把其 w 分量设为1,而对于方向矢量来说,需要把其 w 分量设为0。

分解基础变换矩阵

[M3×3t3×101×31]\begin{bmatrix} \textbf{M}_{3\times3} & \textbf{t}_{3\times1} \\ \textbf{0}_{1\times3} & 1 \end{bmatrix}

其中,M3×3\textbf{M}_{3\times3}表示旋转和缩放,t3×1\textbf{t}_{3\times1}表示平移。

  • 平移矩阵
  • 缩放矩阵——统一缩放(uniform scale),非统一缩放(nonuniform scale)
  • 旋转矩阵

复合变换

Pnew=MtranslationMrotationMscalePold\textbf{P}_{new}=\textbf{M}_{translation}\textbf{M}_{rotation}\textbf{M}_{scale}\textbf{P}_{old}
  • 我们约定变换的顺序是先缩放,再旋转,最后平移。
  • 当我们直接给出(θx\theta_xθy\theta_yθz\theta_z)这样的旋转角度时,需要定义一个旋转顺序。在Unity中,这个旋转顺序是zxy,组合旋转变换矩阵是:
MrotateZMrotateXMrotateY=[cosθzsinθz00sinθzcosθz0000100001][10000cosθxsinθx00sinθxcosθx00001][cosθy0sinθy00100sinθy0cosθy00001]\textbf{M}_{rotate_Z}\textbf{M}_{rotate_X}\textbf{M}_{rotate_Y}= \begin{bmatrix} \cos\theta_z & -\sin\theta_z & 0 & 0 \\ \sin\theta_z & \cos\theta_z & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos\theta_x & -\sin\theta_x & 0 \\ 0 & \sin\theta_x & \cos\theta_x & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} \cos\theta_y & 0 & \sin\theta_y & 0 \\ 0 & 1 & 0 & 0 \\ -\sin\theta_y & 0 & \cos\theta_y & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}

一些读者会有疑问:上面的公式书写顺序是不是反了?不是说列矩阵要从右往左读吗?这样一来顺序不就颠倒了吗?实际上,有一个非常重要的东西我们没有说明白,那就是旋转时使用的坐标系。给定一个旋转顺序(例如这里的zxy),以及它们对应的旋转角度(0,0,0),有两种坐标系可以选择。

Unity 文档中说的是世界坐标系下的旋转;而使用矩阵变换时是在局部坐标系中旋转的

说得明白点,在第一种情况下按zxy顺序旋转和在第二种情况下按yxz顺序旋转是一样的。

坐标空间

  • 坐标空间的变换

  • 顶点的坐标空间变换过程:

    • 模型空间(model space)/对象空间(object space)/局部空间(local space)
    • —模型变换(model transform)
    • 世界空间(world space)
    • —观察变换(view transform)
    • 观察空间(view space)/摄像机空间(camera space)
    • —投影矩阵变换
    • 裁剪空间(clip space)
    • —齐次除法(hemogeneous division)/透视除法(perspective division)
    • 屏幕空间(screen space)
  • 模型空间是在建模软件里确定好的

  • 观察空间(view space)/摄像机空间(camera space)

    Unity中观察空间的坐标轴选择是:+x轴指向右方,+y轴指向上方,而+z轴指向的是摄像机的后方。Unity在模型空间和世界空间中选用的都是左手坐标系,而在观察空间中使用的是右手坐标系。这是符合OpenGL传统的,在这样的观察空间中,摄像机的正前方指向的是-z轴方向。

  • 裁剪空间(clip space)
    裁剪矩阵(clip matrix)/投影矩阵(projection matrix),正交投影(orthographic projection),透视投影(perspective projection),视锥体(view frustum),裁剪平面(clip planes),近剪裁平面(near clip plane),远剪裁平面(far clip plane)

    投影矩阵有两个目的:

    • 首先是为投影做准备。这是个迷惑点,虽然投影矩阵的名称包含了投影二字,但是它并没有进行真正的投影工作,而是在为投影做准备。真正的投影发生在后面的齐次除法
      (homogeneous division)过程中。而经过投影矩阵的变换后,顶点的 w 分量将会具有特殊的意义。

    读者:投影到底是什么意思呢?
    我们:可以理解成是一个空间的降维,例如从四维空间投影到三维空间中。而投影矩阵实际上并不会真的进行这个步骤,它会为真正的投影做准备工作。真正的投影会在屏幕映射时发生,通过齐次除法来得到二维坐标。具体会在4.6.8节中讲到。

    • 其次是对x、y、z分量进行缩放。我们上面讲过直接使用视锥体的6个裁剪平面来进行裁剪会比较麻烦。而经过投影矩阵的缩放后,我们可以直接使用w分量作为一个范围值,如果x、y、z分量都位于这个范围内,就说明该顶点位于裁剪空间内。

    在裁剪空间之前,虽然我们使用了齐次坐标来表示点和矢量,但它们的第四个分量都是固定的:点的w分量是1,方向矢量的w分量是0。经过投影矩阵的变换后,我们就会赋予齐次坐标的第4个坐标更加丰富的含义。

  • 屏幕空间
    归一化的设备坐标(Normalized Device Coordinates,NDC)按照OpenGL的传统,这个立方体的 x、y、z 分量的范围都是[-1,1]。但在 DirectX 这样的 API 中,z分量的范围会是[0,1]。而 Unity 选择了 OpenGL 的齐次裁剪空间。
    在Unity中,从裁剪空间到屏幕空间的转换是由底层完成。我们的顶点着色器只需要把顶点转换到裁剪空间。

法线变换

  • 法线(normal)/法矢量(normal vector)
  • 切线(tangent)/切矢量(tangent vector)——与纹理空间对齐,与法线方向垂直

    要使用原变换矩阵的 逆 转置矩阵 来变换法线。

    • 如果变换矩阵是正交矩阵,那么我们可以使用用于变换顶点的变换矩阵来直接变换法线。如果变换只包括旋转变换,那么这个变换矩阵就是正交矩阵。
    • 而如果变换只包含旋转和统一缩放,而不包含非统一缩放,我们利用统一缩放系数 k 来得到变换矩阵的逆转置矩阵(MABT)1=1kMAB(\textbf{M}_{A\rightarrow B}^{T})^{-1}=\frac{1}{k}\textbf{M}_{A\rightarrow B}
    • 如果变换中包含了非统一变换,那么我们就必须要求解逆矩阵来得到变换法线的矩阵。

Unity Shader 的内置变量

以下是 Unity 2022.3 的内置变量

变换矩阵

NameValue
UNITY_MATRIX_MVP当前的模型-观察-投影矩阵,用于将顶点/方向矢量从模型空间变换到裁剪空间
UNITY_MATRIX_MV当前的模型-观察矩阵,用于将顶点/方向矢量从模型空间变换到观察空间
UNITY_MATRIX_V当前的观察矩阵,用于将顶点/方向矢量从世界空间变换到观察空间
UNITY_MATRIX_P当前的投影矩阵,用于将顶点/方向矢量从观察空间变换到裁剪空间
UNITY_MATRIX_VP当前的观察-投影矩阵,用于将顶点/方向矢量从世界空间变换到裁剪空间
UNITY_MATRIX_T_MVUNITY_MATRIX_MV的转置矩阵
UNITY_MATRIX_IT_MVUNITY_MATRIX_MV的逆转置矩阵,用于将法线从模型空间变换到观察空间,也可用于得到UNITY_MATRIX_MV的逆矩阵
unity_ObjectToWorld当前的模型矩阵,用于将顶点/方向矢量从模型空间变换到世界空间
unity_WorldToObjectObjectToWorld的逆矩阵,用于将顶点/方向矢量从世界空间变换到模型空间

摄像机与屏幕参数

NameTypeValue
_WorldSpaceCameraPosfloat3摄像机在世界空间中的位置。
_ProjectionParamsfloat4x 为 1.0(如果当前使用翻转的投影矩阵进行渲染,则为 -1.0), y 为摄像机的近平面,z 为摄像机的远平面, w 为 1/远平面。
_ScreenParamsfloat4x 是相机目标纹理的宽度(以像素为单位)。y 是相机目标纹理的高度(以像素为单位), z 是 1.0 + 1.0/宽度, w 是 1.0 + 1.0/高度。
_ZBufferParamsfloat4用于线性化 Z 缓冲区值。
x如果 UNITY_REVERSED_Z 设置为 1,则为 1-far/near ,或 -1+far/near
yfar/near ,或者如果 UNITY_REVERSED_Z 设置为 1,则为 1 有关
zx/far
wy/far
unity_OrthoParamsfloat4x 是正交相机的宽度, y 是正交相机的高度, z 未使用, w 在相机为正交相机时为 1.0,在透视相机时为 0.0。
unity_CameraProjectionfloat4x4摄像机的投影矩阵。
unity_CameraInvProjectionfloat4x4摄像机投影矩阵的逆矩阵。
unity_CameraWorldClipPlanes[6]float4摄像机视锥体平面世界空间方程,按此顺序:左、右、下、上、近、远。
除此之外还有 Time、Lighting……这项和引擎相关,需要时再查文档即可。

答疑解惑

  • 3×33\times3 ,还是4×44\times4?:在对顶点的变换中,我们通常使用 4×44\times4 的变换矩阵。而在对方向矢量的变换中,我们通常使用 3×33\times3 的矩阵就足够了。
  • 获取屏幕坐标的方法:ComputeScreenPos/VPOS/WPOS
  • 标题: 《Unity Shader入门精要》读书笔记03
  • 作者: 铁名_IronName
  • 创建于 : 2026-01-13 09:57:36
  • 更新于 : 2026-01-16 18:04:54
  • 链接: https://blog.ironname.top/2026/01/13/《Unity-Shader入门精要》读书笔记03/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论