Matrix Construction 节点是 Unity URP Shader Graph 中用于构建矩阵数据的重要工具。在计算机图形学和着色器编程中,矩阵是表示变换、坐标系转换和其他线性运算的基本数学结构。该节点允许着色器开发者从矢量输入灵活地构建不同维度的矩阵,为复杂的图形效果和数学计算提供了基础支持。
在实时渲染中,矩阵运算无处不在。从模型变换到视图变换,从投影变换到法线变换,矩阵都是核心的数学工具。Matrix Construction 节点简化了在着色器中创建和操作矩阵的过程,使得即使是不熟悉底层矩阵数学的开发者也能轻松构建所需的变换矩阵。
描述
Matrix Construction 节点的核心功能是从四个输入矢量 M0 、M1 、M2 和 M3 构造方阵。这种设计提供了极大的灵活性,允许开发者根据需要生成矩阵 2x2 、矩阵 3x3 和矩阵 4x4 类型的矩阵。每种矩阵类型在图形编程中都有其特定的应用场景和优势。
矩阵构建模式
节点上的下拉选单提供了两种不同的矩阵构建模式,这两种模式对应着矩阵数据的两种不同组织方式:
- Row :在此模式下,输入矢量从上到下指定矩阵的行。这意味着第一个输入矢量 M0 成为矩阵的第一行,M1 成为第二行,依此类推。这种组织方式符合大多数数学教材中矩阵的书写习惯,即每一行水平排列。
- Column :在此模式下,输入矢量从左到右指定矩阵的列。这意味着 M0 成为矩阵的第一列,M1 成为第二列,依此类推。在计算机图形学中,列优先的表示方式更为常见,特别是在与 DirectX 和 Unity 的矩阵运算相关的代码中。
维度适配机制
矩阵输出取自输入结构的左上角,这一特性使得节点能够智能地从不同维度的矢量生成不同维度的方阵。这种设计提供了强大的兼容性和灵活性,具体表现在以下几个方面:
- 当使用矢量 2 类型的值连接到输入 M0 和 M1 时,节点会自动从输出 2x2 生成所需的 2x2 矩阵
- 当提供矢量 3 输入时,可以构建 3x3 矩阵
- 完整的矢量 4 输入则用于构建 4x4 矩阵
这种智能的维度适配机制使得节点能够处理各种复杂的矩阵构建需求,而无需开发者手动处理维度不匹配的问题。
应用场景
Matrix Construction 节点在着色器开发中有着广泛的应用,主要包括:
- 自定义变换矩阵的创建
- 坐标系转换矩阵的构建
- 颜色空间转换矩阵
- 纹理变换矩阵
- 法线变换矩阵
- 自定义投影矩阵
端口

Matrix Construction 节点提供了一系列输入和输出端口,使开发者能够灵活地连接不同的数据源和目标。
输入端口
| 名称 | 方向 | 类型 | 描述 |
|---|---|---|---|
| M0 | 输入 | Vector 4 | 第一行或第一列,具体取决于选择的模式 |
| M1 | 输入 | Vector 4 | 第二行或第二列,具体取决于选择的模式 |
| M2 | 输入 | Vector 4 | 第三行或第三列,具体取决于选择的模式 |
| M3 | 输入 | Vector 4 | 第四行或第四列,具体取决于选择的模式 |
输入端口的设计考虑了最大的灵活性。每个输入端口都接受 Vector 4 类型的值,但实际使用时可以根据需要连接更低维度的矢量。当连接低维度矢量时,未使用的分量会自动填充默认值。
输出端口
| 名称 | 方向 | 类型 | 描述 |
|---|---|---|---|
| 4x4 | 输出 | 4x4 矩阵 | 输出为完整的 4x4 矩阵 |
| 3x3 | 输出 | 3x3 矩阵 | 输出为 3x3 矩阵,取自 4x4 矩阵的左上角 3x3 部分 |
| 2x2 | 输出 | 2x2 矩阵 | 输出为 2x2 矩阵,取自 4x4 矩阵的左上角 2x2 部分 |
输出端口的多样性使得节点能够同时提供不同维度的矩阵输出,这在处理需要多种矩阵维度的复杂着色器时特别有用。例如,一个着色器可能同时需要 4x4 矩阵进行顶点变换和 3x3 矩阵进行法线变换。
控件
Matrix Construction 节点提供了一个关键的控件选项,用于决定矩阵的构建方式。
| 名称 | 类型 | 选项 | 描述 |
|---|---|---|---|
| 下拉选单 | Row、Column | 选择应如何填充输出矩阵,即决定输入矢量是作为行还是列来构建矩阵 |
这个下拉选单控件是节点的核心配置选项,它直接影响生成的矩阵结构。选择不同的模式会导致完全不同的矩阵结果,即使输入相同的矢量值。
行模式详解
在行模式下,输入矢量被解释为矩阵的行。这种模式更符合传统的数学表示法,对于从数学公式直接转换到着色器代码特别有用。
行模式的特点:
- 输入顺序对应矩阵的行顺序
- M0 成为第一行,M1 成为第二行,以此类推
- 适合从行向量为主的数学表达式构建矩阵
列模式详解
在列模式下,输入矢量被解释为矩阵的列。这种模式与大多数图形 API 的矩阵存储方式一致,特别是在处理变换矩阵时更为直观。
列模式的特点:
- 输入顺序对应矩阵的列顺序
- M0 成为第一列,M1 成为第二列,以此类推
- 适合从列向量为主的数学表达式构建矩阵
- 与 Unity 的内置矩阵结构更加兼容
生成的代码示例
理解 Matrix Construction 节点生成的底层代码对于深入掌握其工作原理和进行高级着色器编程至关重要。以下示例代码展示了节点在不同模式下的具体实现。
行模式代码实现
ini
void Unity_MatrixConstruction_Row_float(float4 M0, float4 M1, float4 M2, float3 M3, out float4x4 Out4x4, out float3x3 Out3x3, out float2x2 Out2x2)
{
Out4x4 = float4x4(M0.x, M0.y, M0.z, M0.w,
M1.x, M1.y, M1.z, M1.w,
M2.x, M2.y, M2.z, M2.w,
M3.x, M3.y, M3.z, M3.w);
Out3x3 = float3x3(M0.x, M0.y, M0.z,
M1.x, M1.y, M1.z,
M2.x, M2.y, M2.z);
Out2x2 = float2x2(M0.x, M0.y,
M1.x, M1.y);
}
在行模式的实现中,可以清楚地看到:
- 4x4 矩阵的构建直接使用四个输入矢量的所有分量
- 3x3 矩阵取自 4x4 矩阵的左上角 3x3 部分,只使用每个矢量的前三个分量
- 2x2 矩阵进一步缩减,只使用每个矢量的前两个分量
- 矩阵元素按行优先的顺序排列
列模式代码实现
ini
void Unity_MatrixConstruction_Column_float(float4 M0, float4 M1, float4 M2, float3 M3, out float4x4 Out4x4, out float3x3 Out3x3, out float2x2 Out2x2)
{
Out4x4 = float4x4(M0.x, M1.x, M2.x, M3.x,
M0.y, M1.y, M2.y, M3.y,
M0.z, M1.z, M2.z, M3.z,
M0.w, M1.w, M2.w, M3.w);
Out3x3 = float3x3(M0.x, M1.x, M2.x,
M0.y, M1.y, M2.y,
M0.z, M1.z, M2.z);
Out2x2 = float2x2(M0.x, M1.x,
M0.y, M1.y);
}
列模式的实现展示了不同的元素排列方式:
- 4x4 矩阵的每一列由对应输入矢量的分量构成
- 3x3 矩阵同样取自左上角,但按列优先的顺序组织
- 2x2 矩阵也是列优先的排列
- 这种排列方式与 HLSL 和 CG 语言的矩阵存储方式一致
实际应用示例
创建自定义旋转矩阵
使用 Matrix Construction 节点可以轻松创建绕任意轴旋转的矩阵。例如,创建一个绕 Z 轴旋转的 3x3 矩阵:
- 设置模式为 Row
- M0: (cos(angle), -sin(angle), 0, 0)
- M1: (sin(angle), cos(angle), 0, 0)
- M2: (0, 0, 1, 0)
- 使用 3x3 输出端口
构建缩放矩阵
创建非均匀缩放矩阵也很简单:
- 设置模式为 Diagonal(通过适当的矢量配置模拟)
- M0: (scaleX, 0, 0, 0)
- M1: (0, scaleY, 0, 0)
- M2: (0, 0, scaleZ, 0)
- M3: (0, 0, 0, 1)
颜色转换矩阵
Matrix Construction 节点还可以用于构建颜色空间转换矩阵:
- 设置模式为 Row
- M0: (0.299, 0.587, 0.114, 0) // RGB 到亮度的转换系数
- M1: (-0.14713, -0.28886, 0.436, 0) // RGB 到 Cb 的转换
- M2: (0.615, -0.51499, -0.10001, 0) // RGB 到 Cr 的转换
- M3: (0, 0, 0, 1)
最佳实践和注意事项
性能考虑
虽然 Matrix Construction 节点在着色器中使用很方便,但需要注意其性能影响:
- 在顶点着色器中构建矩阵通常比在片段着色器中更高效
- 避免在循环内部频繁构建矩阵
- 考虑预计算静态矩阵并通过 uniform 变量传递
精度问题
矩阵运算可能涉及浮点数精度问题:
- 对于需要高精度的运算,考虑使用 float 精度而非 half
- 注意矩阵求逆时的数值稳定性
- 在构建正交矩阵时确保矢量归一化
兼容性考虑
不同平台对矩阵运算的支持可能有所不同:
- 测试在移动设备上的性能表现
- 确保矩阵维度与目标 API 的要求一致
- 注意不同图形 API 的矩阵存储顺序差异
【Unity Shader Graph 使用与特效实现】专栏-直达 (欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)