【Unity Shader入门】Shader基础概念:渲染流水线
【Unity Shader入门】Shader编程基础:ShaderLab语法
【Unity Shader入门】Shader数学基础:向量(矢量)
【Unity Shader入门】Shader数学基础:矩阵
【Unity Shader入门】Shader数学基础:矩阵变换
【Unity Shader入门】Shader编程初级:Shader结构
Shader数学基础:向量(矢量)
前言
笛卡尔坐标系
二维笛卡尔坐标系
一个二维的笛卡尔坐标系包含了两个部分的信息:
一个特殊的位置,即原点,它是整个坐标系的中心。
两条过原点的互相垂直的矢量,即X轴和Y轴。这些坐标轴也被称为是该坐标的矢量。
OpenGL 和 DirectX 使用了不同的二维笛卡尔坐标系。OpenGL也就是Unity默认的坐标系是以左下角为原点,DirectX是以左上角为原点。如下图:
三维笛卡尔坐标系
在三维笛卡尔坐标系中,我们需要定义三个坐标轴和一个原点
3个坐标轴被称为该坐标系的基矢量,3个坐标轴互相垂直,长度为1,这样的基矢量被称为标准正交基,如果长度不为1,被称为正交基。当然,坐标轴方向也不是固定的,涉及到z轴向里为正还是向外为正,也就有了大家熟知的左手坐标系和右手坐标系。
三维笛卡尔坐标系分为2种不同的坐标系:左手坐标系(left-handed coordinate space)和右手坐标系(right-handed coordinate space)。
Unity使用的是左手坐标系。但对于观察空间来说,Unity使用的是右手坐标系。观察空间,通俗来讲就是以摄像机为原点的坐标系。在这个坐标系中,摄像机的前向是z轴的负方向,这与在模型空间和世界空间中的定义相反。也就是说,z轴坐标的减少意味着场景深度的增加。
点和向量
介绍
点(point):是n维空间(游戏中主要使用二维和三维空间)中的一个位置,它没有大小、宽度这类概念。
向量(vector,也被称为矢量):是指n维空间中一种包含了模(magnitude)和方向(direction)的有向线段。速度(velocity)就是一种典型的向量。向量被用于表示相对于某个点的偏移,也就是说是一个相对量。
向量的模:指的是这个向量的长度。一个向量的长度可以是任意的非负数。
向量的方向:则描述了这个向量在空间中指向。
向量通常由一个箭头表示
向量的头(head):是它的箭头所在的端点处。
向量的尾(tail):是另一个端点处。
只要向量的模和方向保持不变,无论在哪里,都是同一个向量。
标量(scalar):只有模没有方向。例如距离(distance)就是一种标量。
区别
向量可以用于表示相对于另一个点的位置,此时向量的尾是一个位置,那么向量的头就可以表示另一个位置了。如果我们把向量的尾固定在坐标系原点,那么这个向量的表示就和点的表示重合了。尽管点和向量在数学表达式上都是一样的,但区分点和向量之间的不同是非常重要的。可以这样理解,任何一个点都可以表示成一个从原点位置出发的向量。
点:没有大小之分的空间中的位置
向量:有模和方向,但是没有位置的量,相对量(可以描述相对位置),如果向量的头尾都固定在坐标系的原点,则这个向量就和点重合了。
向量运算
向量和标量的乘法和除法
把一个向量和一个标量相乘,意味着对向量进行一个大小为标量的缩放。
k
v
→
=
(
k
v
x
,
k
v
y
,
k
v
z
)
k\overrightarrow v=(k v_x,k v_y,k v_z)
kv=(kvx,kvy,kvz)
一个向量也可以被一个非零的标量除。这等同于和这个标量的倒数相乘。
v → k = ( x , y , z ) k = 1 k ( x , y , z ) = ( x k , y k , z k ) , k ≠ 0 \frac {\overrightarrow v}k=\frac{ (x,y,z) } k=\frac 1k (x,y,z)=(\frac xk,\frac yk,\frac zk),k≠0 kv=k(x,y,z)=k1(x,y,z)=(kx,ky,kz),k=0
注意:对于乘法来说,向量和标量的位置可以互换的。但对于除法,只能是向量被标量除,而不能是标量被向量除,这是没有意义的。当k<0时,向量的方向也会取反。
例如,如果想把一个向量放大两倍,就乘以2,。当标量小于0时,向量的方向也会相反。
向量的加法和减法
两个向量进行相加或相减,其结果是一个相同维度的新向量。需要注意的是,一个矢量不能和一个标量相加或相减。矢量的加减法遵守三角法则。
a
→
+
b
→
=
(
a
x
+
b
x
,
a
y
+
b
y
,
a
z
+
b
z
)
\overrightarrow a+\overrightarrow b=(a_x+b_x,a_y+b_y,a_z+b_z)
a+b=(ax+bx,ay+by,az+bz)
a
→
−
b
→
=
(
a
x
−
b
x
,
a
y
−
b
y
,
a
z
−
b
z
)
\overrightarrow a-\overrightarrow b=(a_x-b_x,a_y-b_y,a_z-b_z)
a−b=(ax−bx,ay−by,az−bz)
向量的模
向量的模是一个标量,是向量在空间中的长度。对于二维向量,其实就是使用了勾股定理,两个直角边的长度为向量的分量的绝对值,斜边的长度为向量的模。
向
量
a
b
→
的
大
小
,
也
就
是
向
量
a
b
→
的
长
度
(
或
称
模
)
,
记
作
∣
a
b
→
∣
向量\overrightarrow {ab}的大小,也就是向量\overrightarrow {ab}的长度(或称模),记作|\overrightarrow {ab}|
向量ab的大小,也就是向量ab的长度(或称模),记作∣ab∣
∣
v
→
∣
=
v
x
2
+
v
y
2
+
v
z
2
|\overrightarrow v| = \sqrt {v_x^2 + v_y^2 + v_z^2}
∣v∣=vx2+vy2+vz2
单位向量
很多情况下,我们只关心向量的方向而不是模。比如光照模型中,往往需要知道法线方向和光源方向,这种情况下我们不关心向量有多长,这样就需要计算单位向量。单位向量指的是模为1的向量,也被称为被归一化的向量(normalized vector),而把非零向量转换为单位向量的过程被称为归一化。计算单位向量公式如下:
∣
v
^
∣
=
v
∣
v
∣
,
v
是
非
零
向
量
|\hat v|= \frac v {|v|},v是非零向量
∣v^∣=∣v∣v,v是非零向量
向量点积
点积有两种定义方式:代数方式和几何方式。通过在欧氏空间中引入笛卡尔坐标系,向量之间的点积既可以由向量坐标的代数运算得出,也可以通过引入两个向量的长度和角度等几何概念来求解。
代数方式
a
⋅
b
=
(
a
x
,
a
y
,
a
z
)
⋅
(
b
x
,
b
y
,
b
z
)
=
a
x
b
x
+
a
y
b
y
+
a
z
b
z
a \sdot b = (a_x,a_y,a_z) \sdot (b_x,b_y,b_z) = a_xb_x + a_yb_y + a_zb_z
a⋅b=(ax,ay,az)⋅(bx,by,bz)=axbx+ayby+azbz
矢量的点积满足交换律:
a
⋅
b
=
b
⋅
a
a \sdot b = b \sdot a
a⋅b=b⋅a
点积具有一些很重要的性质,在Shader计算中,我们经常利用这些性质来帮助计算。
性质一:点积可以结合标量乘法,也就是说,对点积中其中一个矢量进行缩放的结果,相当于对最后的点积结果进行缩放,即:
(
k
a
)
⋅
b
=
a
⋅
(
k
b
)
=
k
(
a
⋅
b
)
(ka)\sdot b = a \sdot (kb) = k(a\sdot b)
(ka)⋅b=a⋅(kb)=k(a⋅b)
性质二:点积可以结合矢量加法和减法,也就是说,点积的操作数可以是矢量相加或相减后的结果。即:
a
⋅
(
b
+
c
)
=
a
⋅
b
+
a
⋅
c
a \sdot (b + c)= a \sdot b + a \sdot c
a⋅(b+c)=a⋅b+a⋅c
性质三:一个矢量和本身进行点积的结果,是该矢量的模的平方,这可以用来比较两个矢量的长度大小。
v
⋅
v
=
v
x
v
x
+
v
y
v
y
+
v
z
v
z
=
∣
v
∣
2
v \sdot v= v_xv_x + v_yv_y + v_zv_z = |v|^2
v⋅v=vxvx+vyvy+vzvz=∣v∣2
几何方式
a
⋅
b
=
∣
a
∣
∣
b
∣
cos
θ
a \sdot b = |a| |b| \cos \theta
a⋅b=∣a∣∣b∣cosθ
两个矢量的点积可以表示为两个矢量的模相乘,再乘以他们之间夹角的余弦值。
利用余弦定理推导:
∣
c
∣
2
=
∣
a
∣
2
∣
b
∣
2
−
2
∣
a
∣
∣
b
∣
cos
θ
|c| ^2= |a|^2 |b|^2 - 2|a| |b| \cos \theta
∣c∣2=∣a∣2∣b∣2−2∣a∣∣b∣cosθ
∣
c
∣
2
=
c
⋅
c
=
(
a
−
b
)
⋅
(
a
−
b
)
=
a
⋅
a
+
b
⋅
b
−
2
a
⋅
b
|c| ^2= c \sdot c = (a-b) \sdot (a-b) = a \sdot a + b \sdot b - 2a \sdot b
∣c∣2=c⋅c=(a−b)⋅(a−b)=a⋅a+b⋅b−2a⋅b
从这个公式可以看出两个向量的夹角对于点积结果的影响,小于90度为正,等于90度为0,大于90度为负。还可以用反余弦求出两个向量的夹角。
cos
θ
=
a
⋅
b
∣
a
∣
∣
b
∣
\cos \theta = \frac {a \sdot b}{|a| |b|}
cosθ=∣a∣∣b∣a⋅b
几何意义
点积的几何意义中一个重要的几意义是投影(projection),点积的符号可以让我们知道两个矢量的方向关系。
向量叉积
叉积在图形学中常用于计算垂直于一个三角面的向量,用于判断三角面片的朝向等。
a
∧
b
=
(
a
x
,
a
y
,
a
z
)
∧
(
b
x
,
b
y
,
b
z
)
=
(
a
y
b
z
−
a
z
b
y
,
a
z
b
x
−
a
x
b
z
,
a
x
b
y
−
a
y
b
x
)
a\wedge b=(a_x,a_y,a_z)\wedge (b_x,b_y,b_z) =(a_yb_z-a_zb_y,a_zb_x-a_xb_z,a_xb_y-a_yb_x)
a∧b=(ax,ay,az)∧(bx,by,bz)=(aybz−azby,azbx−axbz,axby−aybx)
三维向量叉积的计算规律。不同颜色的线表示了计算结果向量中对应颜色的分量的计算路径。
以红色为例,即结果向量的第一个分量,它是从第一个向量的y分量出发乘以第二个向量的z分量,再减去第一个向量的z分量和第二向量的y分量的乘积
向量的叉积满足反交换律:
a
∧
b
=
−
b
∧
a
a\wedge b=-b\wedge a
a∧b=−b∧a
向量的叉积不满足交换律,也不满足结合律:
a
∧
b
/
=
b
∧
a
a\wedge b \mathrlap{\,/}{=} b \wedge a
a∧b/=b∧a
(
a
∧
b
)
∧
c
/
=
a
∧
(
b
∧
c
)
(a\wedge b) \wedge c \mathrlap{\,/}{=} a \wedge (b \wedge c)
(a∧b)∧c/=a∧(b∧c)
叉积的几何意义:
两个向量叉积会得到一个同时垂直于这两个向量的新向量
∣
a
∧
b
∣
=
∣
a
∣
∣
b
∣
s
i
n
θ
,
其
中
∣
a
∧
b
∣
的
值
为
:
以
a
和
b
为
两
边
的
平
行
四
边
形
的
面
积
|a \wedge b|= |a| |b| sin \theta ,其中|a \wedge b|的值为:以a和b为两边的平行四边形的面积
∣a∧b∣=∣a∣∣b∣sinθ,其中∣a∧b∣的值为:以a和b为两边的平行四边形的面积
我们知道两个方向互不平行的向量可以确定一个平面,所以叉积最常见的应用就是计算垂直于一个平面的向量,我们后面会在顶点法线,切线那里用到。