本文主要是介绍【Unity Shader入门精要 第4章】数学基础(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1. Unity中的坐标空间
1.1 五个坐标空间
模型空间
- 模型自身的3D坐标系空间,左手坐标系
- 是一个相对空间,坐标轴指向随模型旋转变化
- 当物体有父节点时,Transform组件中各属性的值表示的即为该物体在其父物体的模型空间中的值
- 当模型顶点传入顶点着色器时,其中的空间信息均为自身模型空间的信息
世界空间
- 世界3D坐标系空间,左手坐标系
- 是一个绝对空间,坐标轴指向不会发生变化
- 当物体没有父节点时,Transform组件中各属性的值表示的即为该物体在世界空间中的值
观察空间
- 摄像机的模型空间,也是一个3D坐标系空间
- 是Unity中唯一的一个右手坐标系空间
- 以摄像机位置为坐标原点
- 摄像机面向的方向为Z轴负方向
齐次裁剪空间
- 左手坐标系
- 其本质是视锥体包围的空间,或摄像机渲染范围的空间
- 齐次裁剪空间也被称作投影空间,但实际上这时候并没有进行真正的投影,因为还没有对矢量进行降维,该空间仍然是一个3D空间
- 齐次空间范围内的部分可见,范围外的部分为不可见,需要从渲染中剔除
- 在透视投影下:
- 由近裁截面距离、远裁截面距离、FOV以及横纵比决定空间范围
- 形状为平头四棱锥
- FOV决定锥体竖直方向的张开角度
- 根据近裁截面、远裁截面和FOV可以求出近裁截面和远裁截面的高度,根据横纵比可以求出近裁截面和远裁截面的宽度
- 在正交投影下:
- 由近裁截面距离、远裁截面距离、SIZE以及横纵比决定空间范围
- 形状为立方体
- SIZE决定立方体竖直方向上高度的一半
- 根据近裁截面、远裁截面和SIZE可以求出近裁截面和远裁截面的高度,根据横纵比可以求出近裁截面和远裁截面的宽度
- 齐次空间仍然为一个非归一化的三维空间
屏幕空间
- 左手坐标系
- 对应当前显示屏幕的2D像素空间
- 空间范围为(0, 0 )到(ScreenMaxPixelX, ScreenMaxPixelY)
1.2 四个转换过程
模型变换
- Model Transform —— M
- 将顶点从模型空间转换到世界空间
观察变换
- View Transform —— V
- 将顶点从世界空间转换到观察空间
投影变换
- Projection Tranform —— P
- 将顶点从观察空间转换到投影空间(齐次裁剪空间)
- 根据摄像机的设置不同,分为透视投影(Perspective Projection)和正交投影(Orthographic Projection)两种投影变换方式
- 同样,这里所谓的投影变换并不是真正进行降维投影,仍然是3D空间到3D空间的变换
- 所谓投影变换只是对矢量乘以一个变换矩阵(称为投影矩阵或裁剪矩阵),得到矢量在当前齐次空间中真正的齐次坐标
- 变换矩阵的推导过程并不重要,变换矩阵长什么样也不重要,重要的是我们知道矢量经过与变换矩阵的计算后,其w分量发生了变化,不再是初始的1和0,而是变成了-Z(点)和1(向量)
屏幕映射
- 以上MVP三种变换都是在顶点着色器中完成的,回忆第二章中渲染流水线的几何阶段,在顶点着色器和屏幕映射阶段之间还有一个必不可少的裁剪阶段,因此在做真正的屏幕映射之前,还需要先进行一步裁剪
- 上面我们提到过,齐次裁剪空间是一个非归一化的空间,在不同的摄像机设置下,视锥体的范围是不同的,为了能够对不同的视锥体范围进行统一的裁剪处理,需要先将齐次坐标映射到一个统一的范围之内,这一步通过将齐次坐标的所有分量都除以w分量来完成,称为齐次除法(感觉齐次除法就是一个从四维投影到三维的过程)
- 经过齐次除法后,我们得到了一个(x/w, y/w, z/w, 1)的坐标,称为归一化设备坐标(NDC),而原来的裁剪空间也被投影到了一个(-1,1)的正立方体空间范围(DX为0到1)
- 此时就可以对所有的NDC坐标进行统一的裁剪处理,只需要考虑坐标是否超出(-1,1)的范围即可
- 裁剪结束后,所有剩余的顶点都是在屏幕范围内的点,需要根据其X和Y的值映射到(0, 0)至(MaxScreenPixelX, MaxScreenPixelY)的范围内,可以看到,这时候才真正从3D空间投影到了2D空间
- 剩余的Z值则表示该顶点到屏幕的距离,即深度值
1.3 空间转换图示
2. 坐标空间变换矩阵
对于坐标空间A和坐标空间B,当我们知道了:
- B空间的原点 O 在A空间的表示为 OriginalB
- B空间的 X 轴在A空间的表示为 AxisBx
- B空间的 Y 轴在A空间的表示为 AxisBy
- B空间的 Z 轴在A空间的表示为 AxisBz
则从坐标空间B到坐标空间A的转换矩阵MB→A(4*4)为:
( ∣ ∣ ∣ ∣ A x i s B x A x i s B y A x i s B z O r i g i n a l B ∣ ∣ ∣ ∣ 0 0 0 1 ) \left( \begin{matrix} | & | & | & |\\ AxisB~x~ & AxisB~y~ & AxisB~z~ & OriginalB\\ | & | & | & |\\ 0 &0&0&1 \end{matrix} \right) ∣AxisB x ∣0∣AxisB y ∣0∣AxisB z ∣0∣OriginalB∣1
即将X轴、Y轴、Z轴、原点按列组合形成的4 * 4矩阵(推导过程懒得写了)
由于向量不存在空间位置属性,因此对于向量的变换矩阵可以不关心原点,故可以直接截取3 * 3的轴矩阵 MB→A(3*3):
( ∣ ∣ ∣ A x i s B x A x i s B y A x i s B z ∣ ∣ ∣ ) \left( \begin{matrix} | & | & | \\ AxisB~x~ & AxisB~y~ & AxisB~z~ \\ | & | & | \end{matrix} \right) ∣AxisB x ∣∣AxisB y ∣∣AxisB z ∣
根据以上矩阵可以做如下推导:
- 对于任意B空间内的向量VB,其在A空间的表示 VA = MB→A(3 * 3) * VB
- 两边同时乘以 MB→A(3 * 3) 的逆矩阵 MB→A(3 * 3)-1
- 得到等式 MB→A(3 * 3)-1 * VA = VB
即:MA→B(3 * 3) = MB→A(3 * 3)-1
同时,由于 MB→A(3 * 3)是由坐标空间B的三个坐标轴组合得到的矩阵,而坐标轴组合的矩阵一定是正交矩阵,因此 MB→A(3 * 3)的转置矩阵与逆矩阵相同
因此,此时从坐标空间A反向转换到坐标空间B的转换矩阵 MA→B(3 * 3) = MB→A(3 * 3)-1 = MB→A(3 * 3)T,故 MA→B(3 * 3) 为:
( — A x i s B x — — A x i s B y — — A x i s B z — ) \left( \begin{matrix} — & AxisB~x~ & — \\ — & AxisB~y~ & — \\ — & AxisB~z~ & — \end{matrix} \right) ———AxisB x AxisB y AxisB z ———
3.法线变换
普通的转换矩阵适用于在不同的坐标空间之间对点和普通向量进行空间变换,但是如果直接用该矩阵对法线进行变换,就会出错
这是因为法线并不是空间内真实存在的向量,法线只是对空间内某一平面垂直的一个相对向量,或者说是对空间内真实存在的向量虚构出来的相对向量,具有一定的相对性
当进行空间变换后,这种相对性无法保证依然生效,因此可能导致变换后的法线与变换后的平面并不垂直
而切线是由空间内相邻两点确定的,也就是空间中真实存在的向量,因此可以通过普通的转换矩阵进行空间变换,并且我们可以利用切线来推导出使用于法线的转换矩阵
假设T为切线,N为法线,M为切线的转换矩阵,G为法线的转换矩阵
TB = M * TA
NB = G * NA
由切线与法线垂直可得:
TB · NB = (M * TA) · (G * NA) = 0
注意,上式表示的是两个垂直向量的点乘结果为0
如果将上式改成矩阵乘法来表示,就需要将TB 转置成列矩阵后再与行矩阵 NB 相乘
于是得到:
(M * TA)T · (G * NA) = TAT * MT * G * NA = TAT * (MT * G) * NA = 0
由于TAT * NA = 0,因此要使上式成立,只要 MT * G = I,即G = (MT)-1 = (M-1)T
于是问题转化为求普通转换矩阵 M 的逆矩阵 M-1:
- 如果只存在旋转变换,由于旋转矩阵为正交矩阵,M-1 = MT,因此 G = (M-1)T = (MT)T = M
- 如果只存在旋转变换和统一缩放变换,假设统一缩放系数为K,则G = 1/k * M(这里一直没明白,为什么不是1/k2 * M,有没有大佬给解释一下??)
- 如果存在非统一缩放变换或平移变换,就只能求逆矩阵了
4. Unity内置变换矩阵
Unity内置了一些变量,可以轻松的获取对应的转换矩阵,这里提供的都是4*4的矩阵
变量 | 作用 |
---|---|
_Object2World | 模型空间到世界空间 |
_World2Object | 世界空间到模型空间 |
变量 | 作用 |
---|---|
UNITY_MATRIX_MVP | 模型空间到齐次裁剪空间 |
UNITY_MATRIX_V | 世界空间到观察空间 |
UNITY_MATRIX_P | 观察空间到齐次裁剪空间 |
UNITY_MATRIX_VP | 世界空间到齐次裁剪空间 |
变量 | 作用 |
---|---|
UNITY_MATRIX_MV | 模型空间到观察空间 |
UNITY_MATRIX_T_MV | 模型空间到观察空间的转置 |
UNITY_MATRIX_IT_MV | 模型空间到观察空间的逆转置 |
5. Unity内置摄像机参数
Unity内置了部分变量可以用来获取对应摄像机参数
变量 | 类型 | 作用 |
---|---|---|
_WorldSpaceCameraPos | float3 | 摄像机世界坐标 |
变量 | 类型 | 作用 |
---|---|---|
_ScreenParams | float4 | (width, height, 1 + 1/w, 1 + 1/h) |
_ZBufferParams | float4 | (1 - F/N, F/N, x/F, y/F) |
_ProjectinParams | float4 | (1/-1, N, F, 1 + 1/F),首位为-1时表示使用的是翻转的投影矩阵 |
Unity_OrthoParams | float4 | (w, h, _, 0/1) 最后位为0时为透视相机,为1时为正交相机 |
变量 | 类型 | 作用 |
---|---|---|
Unity_CameraProjection | float4x4 | 摄像机投影矩阵 |
Unity_CameraInvProjection | float4x4 | 摄像机投影矩阵的逆矩阵 |
Unity_CameraWorldClipPlanes[6] | float4 | 左右上下远近 |
这篇关于【Unity Shader入门精要 第4章】数学基础(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!