概述

在学习Shader的过程中,我们最常使用的就是矢量和矩阵(即数学的分支之一——线性代数)。

笛卡儿坐标系

我们使用数学绝大部分都是为了计算位置、距离和角度等变量。而这些计算大部分都是在笛卡儿坐标系 (Cartesian Coordinate System) 下进行的。这个名字来源于法国伟大的哲学家、物理学家、心理学家、数学家笛卡儿(René Descartes)。

二维笛卡儿坐标系

一个二维的笛卡儿坐标系包含了两个部分的信息:

  • 一个特殊的位置,即原点,它是整个坐标系的中心;
  • 两条过原点的互相垂直的矢量,即x 轴和y 轴。这些坐标轴也被称为是该坐标系的基矢量。

三维笛卡儿坐标系

在三维笛卡儿坐标系中,我们需要定义3个坐标轴和一个原点:

这3个坐标轴也被称为是该坐标系的基矢量 (basis vector) 。

  • 通常情况下,这 3 个坐标轴之间是互相垂直的,且长度为1,这样的基矢量被称为标准正交基 (orthonormal basis)
  • 在一些坐标系中坐标轴之间互相垂直但长度不为1,这样的基矢量被称为正交基 (orthogonal basis) 。

正交可以理解成互相垂直的意思

二维笛卡儿坐标系类似,三维笛卡儿坐标系中的坐标轴方向也不是固定的,即不一定是像图4.6中那样的指向。但这种不同导致了两种不同种类的坐标系:左手坐标系 (left-handed coordinate space)右手坐标系 (right-handed coordinate space)

左手坐标系和右手坐标系

为什么在三维笛卡儿坐标系中要区分左手坐标系和右手坐标系:

  • 在二维笛卡儿坐标系中,x 轴和y 轴的指向虽然可能不同,但我们总可以通过一些旋转操作来使它们的坐标轴指向相同。 从这种意义上来说,所有的二维笛卡儿坐标系都是等价的。
  • 对于三维笛卡儿坐标系,靠这种旋转有时并不能使两个不同朝向的坐标系重合, 我们总可以让其中两个坐标轴的指向重合,但第三个坐标轴的指向有可能是相反的。

我们可以利用我们的双手来判断一个坐标系的旋向性。请读者举起你的左手,用食指和大拇指摆出一个“L”的手势,并且让你的食指指向上,大拇指指向右。现在,伸出你的中指,不出意外的话它应该指向你的前方,即可得到一个左手坐标系.

左手坐标系如下图:

通过右手来得到一个右手坐标系。举起你的右手,这次食指仍然指向上,中指指向前方,不同的是,大拇指将指向左侧, 即可得到一个右手坐标系.

右手坐标系如下图:

判断是左手还是右手坐标系

判断前向 (forward) 的方向。

  1. 向右伸直你的右手,此时右手方向就是x 轴的正向,而你的头顶向上的方向就是y 轴的正向。
  2. 这时,如果你的正前方的方向是z 轴的正向,那么你本身所在的坐标系就是一个左手坐标系;
  3. 如果你的正前方的方向对应的是z 轴的负向,那么这就是一个右手坐标系。

左手法则和右手法则的简单说明:

  • 举起你的左手,握拳,伸出大拇指让它指向旋转轴的正方向,那么旋转的正方向就是剩下4个手指的弯曲方向 在右手坐标系中,使用右手法则对旋转正方向的判断类似
  • 在左手坐标系中,旋转正方向是顺时针的,而在右手坐标系中,旋转正方向是逆时针的

Unity使用的坐标系

  1. 对于模型空间和世界空间来说Unity使用的是左手坐标系。

在模型空间中,一个物体的右侧(right)、上侧(up)和前侧(forward)分别对应了x 轴、y 轴和z 轴的正方向。

  1. 于观察空间来说,Unity使用的是右手坐标系。

观察空间,通俗来讲就是以摄像机为原点的坐标系。在这个坐标系中,摄像机的前向是z 轴的负方向,这与在模型空间和世界空间中的定义相反。也就是说,z 轴坐标的减少意味着场景深度的增加。

练习题

(1)在非常流行的建模软件3ds Max中,默认的坐标轴方向是:x 轴正方向指向右方,y 轴正方向指向前方,z 轴正方向指向上方。那么它是左手坐标系还是右手坐标系?

右手坐标系

(2)在左手坐标系中,有一点的坐标是(0, 0, 1),如果把该点绕y 轴正方向旋转+90°,旋转后的坐标是什么?如果是在右手坐标系中,同样有一点坐标为(0, 0, 1),把它绕y 轴正方向旋转+90°,旋转后的坐标是什么?

(3)在Unity中,新建的场景中主摄像机的位置位于世界空间中的(0, 1, −10)位置。在不改变摄像机的任何设置(如保持Rotation为(0, 0, 0),Scale为(1, 1, 1))的情况下,在世界空间中的(0, 1, 0)位置新建一个球体,如图4.14所示。

点和矢量

  • 点 (point) 是n 维空间(游戏中主要使用二维和三维空间)中的一个位置,它没有大小、宽度这类概念
  • 矢量的模指的是这个矢量的长度。一个矢量的长度可以是任意的非负数。
  • 矢量的方向则描述了这个矢量在空间中的指向。
  • 矢量被用于表示相对于某个点的偏移(displacement)

矢量运算

  1. 矢量和标量乘法/除法 我们只需要把矢量的每个分量和标量相乘即可
kv =(kvx ,kvy , kvz )

一个矢量也可以被一个非零的标量除 对于乘法来说,矢量和标量的位置可以互换。但对于除法,只能是矢量被标量除,而不能是标量被矢量除,这是没有意义的。

  1. 矢量的加法和减法 两个矢量进行相加或相减,其结果是一个相同维度的新矢量
a +b =(ax +bx ,ay +by , az +bz )
a –b =(ax −bx ,ay -by , az −bz )

(1,2,3)+(4,5,6)=(5,7,9)
(5,2,7) − (3,8,4)=(2, −6,3)

一个矢量不可以和一个标量相加或相减,或者是和不同维度的矢量进行运算

矢量加法的三角形定则

如果我们从一个起点开始进行了一个位置偏移a ,然后又进行一个位置偏移b ,那么就等同于进行了一个a +b 的位置偏移. 这被称为矢量加法的三 角形定则(triangle rule) 。矢量的减法是类似的

矢量的模

矢量的模是一个标量,可以理解为是矢量在空间中的长度。它的表示符号通常是在矢量两旁分别加上一条垂直线(有的文献中会使用两条垂直线).

三维矢量的模的计算公式如下:

对每个分量的平方相加后再开根号就能得到一个矢量的模。

单位矢量

在计算光照模型时,我们往往需要得到顶点的法线方向和光源方向,此时我们不关心这些矢量有多长.在这种情况下我们就需要计算单位矢量。

  • 单位矢量指的是那些模为1的矢量。
  • 单位矢量也被称为被归一化的矢量(normalized vector) 。对任何给定的非零矢量,把它转换成单位矢量的过程就被称为归一化(normalization) 。

我们通过在一个矢量的头上添加一个戴帽符号来表示单位矢量,例如。为了对矢量进行归一化,我们可以用矢量的模除以该矢量来得到

公式如下:

示例如下:

零矢量

零矢量 (即矢量的每个分量值都为0,如v =(0,0,0))是不可以被归一化的。这是因为做除法运算时分母不能为0。

矢量的点积

矢量的乘法有两种最常用的种类:点积 (dot product, 也被称为内积 ,inner product) 和叉积 (cross product, 也被称为外积 ,outer product) 。

点积的性质

  1. 点积可结合标量乘法。

点积的操作数之一可以是另一个运算的结果,即矢量和标量相乘的结果,也就是说对点积中其中一个矢量进行缩放的结果,相当于对最后的点积结果进行缩放。

公式如下:

(k a )·b = a ·(k b )=k (a ·b )
  1. 点积可结合矢量加法和减法,和性质一类似。点积的操作数可以是矢量相加或相减后的结果
a ·(b + c )= a ·b + a ·c
  1. 一个矢量和本身进行点积的结果,是该矢量的模的平方。

点积公式

  1. 公式一 两个三维矢量的点积是把两个矢量对应分量相乘后再取和,最后的结果是一个标量 矢量的点积满足交换律,即a ·b =b ·a

  2. 公式二, 两个矢量的点积可以表示为两个矢量的模相乘,再乘以它们之间夹角的余弦值

a ·b =|a ||b |cosθ

证明过程:

  • 上图是两个单位矢量点积示意图
  • 我们对两个单位矢量进行点积a ·b,单位矢量的模是1.
  • 直角边/斜边 = consθ
  • cosθ = (a ·b) / |b|
  • |b| = 1
  • (a ·b) = cosθ

应用性质一就可以得到公式二了

当夹角小于90°时,cosθ >0;当夹角等于90°时,cosθ =0;当夹角大于90°时,cosθ <0。

点积的几何意义

点积的几何意义很重要,因为点积几乎应用到了图形学的各个方面。其中一个几何意义就是投影 (projection) 。

假设,有一个单位矢量和另一个长度不限的矢量b 。现在,我们希望得到b 在平行于a的一条直线上的投影。那么,我们就可以使用点积b 来得到b 在方向上的有符号的投影。

投影的通俗解释是 现在有一个光源,它发出的光线是垂直于方向的,那么b 在方向上的投影就是b 在方向上的影子

投影的值可能是负数。投影结果的正负号与和b 的方向有关:

  • 当它们的方向相反(夹角大于90°)时,结果小于0;
  • 当它们的方向互相垂直(夹角为90°)时,结果等于0;
  • 当它们的方向相同(夹角小于90°)时,结果大于0

矢量的叉积

另一个重要的矢量运算就是叉积 (cross product) ,也被称为外积 (outer product) 。与点积不同的是,矢量叉积的结果仍是一个矢量,而非标量.

两个矢量的叉积可以用如下公式:

  • 叉积不满足交换律, 即a ×b≠b×a
  • 叉积是满足反交换律的,即a ×b =−(b ×a )
  • 叉积也不满足结合律,即 (a ×b ) ×c ≠a ×(b ×c )。

a ×b 的长度等于a 和b 的模的乘积再乘以它们之间夹角的正弦值

|a×b |=|a ||b |sinθ

使用左手坐标系还是右手坐标系不会对叉积的计算结果产生任何影响,它影响的只是数字在三维空间中的视觉化表现而已

矩阵运算

矩阵和标量的乘法

和矢量类似,矩阵也可以和标量相乘,它的结果仍然是一个相同维度的矩阵

矩阵和矩阵的乘法

两个矩阵的乘法也很简单,它们的结果会是一个新的矩阵

  • 一个r ×n 的矩阵A 和一个n ×c 的矩阵B 相乘,它们的结果AB 将会是一个r ×c 大小的矩阵
  • 第一个矩阵的列数必须和第二个矩阵的行数相同
  • 它们相乘得到的矩阵的行数是第一个矩阵的行数, 列数是第二个矩阵的列数

设有r ×n 的矩阵A 和一个n ×c 的矩阵B ,它们相乘会得到一个r ×c 的矩阵C =AB 。那么,C 中的每一个元素cij 等于A 的第i 行所对应的矢量和B 的第j 列所对应的矢量进行矢量点乘的结果.

对于每个元素cij ,我们找到A 中的第i 行和B 中的第j 列,然后把它们的对应元素相乘后再加起来,这个和就是cij 。

举个例子来理解这个公式,如下图:

矩阵乘法满足一些性质

  1. 性质一:矩阵乘法并不满足交换律。
  2. 性质二:矩阵乘法满足结合律。

特殊的矩阵

  1. 方块矩阵(square matrix) ,简称方阵,是指那些行和列数目相等的矩阵。在三维渲染里,最常使用的就是3×3和4×4的方阵。

如果一个矩阵除了对角元素外的所有元素都为0,那么这个矩阵就叫做对角矩阵 (diagonal matrix)

2.单位矩阵, 任何矩阵和它相乘的结果都还是原来的矩阵

一个特殊的对角矩阵是单位矩阵 (identity matrix) ,用I n 来表示。一个3×3的单位矩阵如下

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

给定一个r ×c 的矩阵M ,它的转置可以表示成M T ,这是一个c ×r 的矩阵。转置矩阵的计算非常简单,我们只需要把原矩阵翻转一下即可, 原矩阵的第i 行变成了第i 列,而第j 列变成了第j 行。

数学公式如下:

对于行矩阵和列矩阵来说,我们可以使用转置操作来转换行列矩阵

转置矩阵常用的性质

  • 性质一:矩阵转置的转置等于原矩阵。
  • 性质二:矩阵串接的转置,等于反向串接各个矩阵的转置。

逆矩阵 TODO

逆矩阵 (inverse matrix) 大概是本书讲到的关于矩阵最复杂的一种操作了。不是所有的矩阵都有逆矩阵,第一个前提就是,该矩阵必须是一个方阵。

正交矩阵

正交是矩阵的一种属性。如果一个方阵M 和它的转置矩阵的乘积是单位矩阵的话,我们就说这个矩阵是正交的 (orthogonal)

  • 矩阵的每一行,即c 1 、c 2 和c 3 是单位矢量,因为只有这样它们与自己的点积才能是1;
  • 矩阵的每一行,即c 1 、c 2 和c 3 之间互相垂直,因为只有这样它们之间的点积才能是0。

上述两条结论对矩阵的每一列同样适用,因为如果M 是正交矩阵的话,M^T 也会是正交矩阵。

矩阵的几何意义: 变换

什么是变换

变换 (transform) ,指的是我们把一些数据,如点、方向矢量甚至是颜色等,通过某种方式进行转换的过程

坐标空间

法线变换

Unity内置变换

--完--