theme: arknights highlight: atom-one-dark
原文链接
[Unity Shader内置矩阵 | 鹅厂程序小哥
](https://blog.csdn.net/qq826364410/article/details/81539321)
正文
mul
函数
mul
函数,Z = mul(M, V)
是表示矩阵 M
和向量 V
进行点乘,得到一个向量 Z
,这个向量 Z
就是对向量 V
进行矩阵变换后得到的值。
特别需要 注意 的是,例如 normal
是 float3
类型的,点乘的矩阵也要转换成 float3x3
。
float3 normal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
矩阵
内置的矩阵(float4x4
):
一、这里要特别说明一下 UnityObjectToClipPos(v.vertex)
方法,官方网站上说明,编写着色器脚本时,请始终使用 UnityObjectToClipPos(v.vertex)
而不是 mul(UNITY_MATRIX_MVP,v.vertex)
,因为所有内建的矩阵名字在 Instanced Shader 中都是被重定义过的,如果直接使用 UNITY_MATRIX_MVP
,会引入一个 额外 的矩阵乘法运算,所以 推荐 使用 UnityObjectToClipPos
/ UnityObjectToViewPos
函数,它们会把这一次额外的 矩阵乘法 优化为 向量-矩阵乘法。
二、UNITY_MATRIX_IT_MV
的使用场景,专门针对法线进行变换。但是为什么法线的变换和顶点不一样呢?
之所以法线不能直接使用 UNITY_MATRIX_MV
进行变换,是因为法线是向量,具有方向,在进行空间变换的时候,如果发生 非等比 缩放,方向会发生偏移。为什么呢?举个栗子,我们可以简单的把法线和切线当成三角形的两条边,显然,三角形在空间变换的时候,不管是平移,还是旋转,或者是 等比 缩放,都不会变形,但是如果 非等比 缩放,就会发生拉伸。所以法线和切线的夹角也就会发生变化。(而切线在变换前后,方向总是正确的,所以法线方向就不正确了)。下图,T
、T'
是切线,N
、N'
是法线
经过非等比缩放后
三、UnityObjectToWorldDir()
与 UnityObjectToWorldNormal()
的区别
第一个原图,红色箭头表示法线。第二张图,表示 非等比 缩放,使用UnityObjectToWorldDir()
,把法线从 模型空间 转换到 世界空间,法线也会被压扁并且不再垂直于曲面。第三张图,表示 非等比 缩放,使用UnityObjectToWorldNormal()
,把法线从 模型空间 转换到 世界空间,法线是正确的垂直于曲面的。
当 等比 缩放时,使用 UnityObjectToWorldDir()
和 UnityObjectToWorldNormal()
得到的结果是一样的。
渲染流水线中顶点的空间变换过程
模型空间—>世界空间—>视角(相机)空间—>裁剪空间—>屏幕空间
- 模型空间:每个模型都有自己独立的坐标空间,当它移动或旋转时,模型空间也会跟着它移动或旋转。
模型空间—>世界空间 的变换矩阵:unity_Object2World
2. 世界空间:如果一个 Transform 没有任何父节点,那么这个位置就是在世界空间中的位置。
世界空间—>视角(相机)空间 的变换矩阵:UNITY_MATRIX_V
3. 视角(相机)空间:摄像机决定了我们渲染游戏所使用的视角。
视角(相机)空间—>裁剪空间 的变换矩阵:UNITY_MATRIX_P
4. 裁剪空间:目的是能够方便的对渲染图元进行裁剪,完全位于视锥体空间内部的图元被 保留,完全位于这块空间外部的图元被 剔除,而这块空间边界相交的图元就会被 裁剪。视锥体有两种类型:正交投影 和 透视投影。在使用视锥体进行裁剪时,那么不同的视锥体就需要不同的处理过程。因此,提出了一种通用、方便的方式来裁剪,就是通过一个投影矩阵把顶点转换到一个裁剪空间中。
在 Unity 中,从 裁剪空间 到 屏幕空间 的转换是由 Unity 底层帮我们完成的。
- 屏幕空间:屏幕空间是一个二维空间,因此我们需要把顶点从裁剪空间投影到屏幕空间中,来生成对应的 2D 坐标。首先,用裁剪空间的
x
、y
、z
分量除以w
分量,把坐标从裁剪空间转换到归一化的设备坐标(NDC,一个立方体)中。然后,再映射到屏幕空间中,确定顶点在屏幕空间的像素位置。
在顶点着色器中,通过
UNITY_MATRIX_MVP
这个矩阵,可以把物体的顶点从 模型空间 转换到 裁剪空间。
相机
名称 | 类型 | 数值 |
---|---|---|
_WorldSpaceCameraPos | float3 | 世界空间相机的位置 |
_ProjectionParams | float4 | x = 1.0 (或如果当前使用翻转投影矩阵渲染则为 -1.0), y 是相机的 近平面, z 是相机的 远平面,w 是 1 / FarPlane |
_ScreenParams | float4 | x 是相机的渲染目标在像素里的宽度, y 是相机的渲染目标在像素里的高度, z 是 1.0 + 1.0 /宽度, w 是 1.0 + 1.0 /高度 |
_ZBufferParams | float4 | 用于线性化 Z 缓冲区的值。x (1-far /near), y (far/near)、z (x /far)和 w (y /far) |
unity_OrthoParams | float4 | x 是正交的相机的宽度, y 是正交的相机的高度, z 是未使用的,为 正交 的相机时 w 为 1.0, 透视 相机时 w 为 0.0 |
unity_CameraProjection | float4x4 | 摄像机的投影矩阵 |
unity_CameraInvProjection | float4x4 | 摄像机的投影矩阵的逆矩阵 |
unity_CameraWorldClipPlanes[6] | float4 | 相机锥平面世界空间方程,按顺序为:左、右、底部、顶部、近、远 |
光照
名称 | 类型 | 数值 |
---|---|---|
_LightColor0(Lighting.cginc 中声明) | fixed4 | 光照颜色 |
_worldspacelightpos0 | float4 | 方向光:(世界空间方向,0)。其他光:(世界空间位置,1) |
_LightMatrix0(AutoLight.cginc 声明) | float4x4 | world-to-light 矩阵。用于样品 cookie 和衰减纹理 |
unity_4LightPosX0、unity_4LightPosY0 unity_4lightposz0 | float4 | (仅 ForwardBase 通道)前四个不重要的点光源的世界空间坐标 |
unity_4lightatten0 | float4 | (仅 ForwardBase 通道)前四个不重要的点光源的衰减系数 |
unity_lightcolor | half4[4] | (仅 ForwardBase 通过)前四个不重要的点光源的颜色数组 |
- 在 Shader 的光照通道里的延迟着色和延迟光照(在 unitydeferredlibrary.cginc ):
名称 | 类型 | 数值 |
---|---|---|
_LightColor | float4 | 光照颜色 |
_LightMatrix0 | float4x4 | world-to-light 矩阵。用于样品 cookie 和衰减纹理 |
- 多光源下,最多
8
个 光源在顶点通道,排序为从 最亮 的开始
名称 | 类型 | 数值 |
---|---|---|
unity_LightColor | half4[8] | 光照颜色数组 |
unity_LightPosition | float4[8] | 视图空间光源的位置。方向光源的坐标是(-方向,0);(位置,1)用于点/点指示灯,点光源,聚光灯的坐标是(位置,1) |
unity_LightAtten | half4[8] | 光源衰减的系数。X 是 cos(spotAngle/2) 或非聚光灯为 -1 ;Y 为 1/cos(spotangle/4) 或非聚光灯为 -1 ;Z 是衰减的二次方;W 是正方形光源的范围 |
unity_SpotDirection | float4[8] | 视图空间聚光灯的位置;(0,0,1,0) 则非聚光灯。 |