讨论一下着色器需要起作用的变量以及如何将它们添加到代码中。 变量包括我们为每种材质进行设置的变量,作为网格数据一部分的变量以及从顶点传递到片段的数据。
模型数据
在较低的程序级别上,它们是定义将要呈现的内容的数据流,但在更高层次上将其想象为网格更容易理解。对于大多数情况,此数据必须包括顶点位置和它们之间的三角形。通常通过此传递的其他数据是顶点法线,uv坐标和顶点颜色。然后,在渲染之前,顶点阶段会处理每个顶点数据。位置和方向都在局部空间中,因此无论对象如何缩放或移动,我们都可以使用相同的顶点数据而无需额外准备。
在unity着色器中,此数据通常以最常用的appdata结构传递给顶点着色器。可以给数据起任何名字,但是必须添加标识符以告诉统一哪个变量应该用什么数据填充,例如:
struct appdata{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
可以在此处找到常见顶点流的列表 : https://docs.unity3d.com/Manual/SL-VertexProgramInputs.html
插值器
在顶点阶段修改数据后,光栅化程序将其用于生成绘制的像素。 为此,我们必须将局部空间的的位置信息设置在屏幕上(在剪辑空间中),以便光栅化器知道在哪里绘制它,并用SV_POSITION标签标记变量。 任何其他数据都是可选的,并且可以被片段阶段用来生成颜色,包括从纹理读取和照明效果。 对于在顶点与数据之间生成的像素,将对数据进行插值,因此称为插值器。另一个通用描述符是“顶点到片段”的v2f。
一个简单的插值器结构的示例如下所示:
//数据从顶点传递到片段着色器并在光栅化阶段进行插值
struct v2f{
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
};
输出颜色
对于输出,我们通常将简单的4d向量用于输出颜色的红色/绿色/蓝色/ alpha通道。 重要的是,将片段函数标记为SV_Target,以告知编译器将输出用作颜色。
Uniform data
除了着色器中的数据(已渲染网格的一部分)之外,还有为每种材质设置的数据。 这种数据通常称为统一数据,因为它在整个绘图中是统一的。 可以是数字,纹理,向量等等。 此数据的一部分也是定义当前正在渲染的摄像机以及正在渲染的对象的变换的矩阵。 幸运的是,所有这些都是由Unity自动设置的。
要定义新的Uniform data,我们只需要向编写的着色器程序结构或函数之外中添加变量即可。
//纹理以及纹理变换
sampler2D _MainTex;
float4 _MainTex_ST;
//纹理着色
fixed4 _Color;
这些变量一旦存在,我们就可以通过代码(Material.SetType)进行设置。 但是要在编辑器材质面板中显示它们,我们必须在文件顶部将它们声明为属性。
类似
Properties{
_Color ("Tint", Color) = (0, 0, 0, 1)
_MainTex ("Texture", 2D) = "white" {}
}
纹理是一种特殊情况,因为纹理不仅将纹理写入您提供的变量中,而且将平铺和偏移量写入同名变量中,但最后加_ST ST表示缩放变换(旧版本的unity称为平铺偏移)
什么是空间
在谈论着色器中的位置时,经常谈论模型/世界/视图/屏幕/剪辑空间。在这种情况下,空间是要位于的坐标的上下文。
模型空间坐标是对象上下文中的坐标。模型空间中的0,0是该模型的原点。如果模型旋转或缩放,则模型空间中的坐标随之旋转或缩放(主要是相对于世界空间,即“最近”的空间)。顶点的坐标保存在模型空间的文件中,并按原样上传到GPU。
世界空间坐标是相对于其他所有坐标的坐标。这里有一个0、0点,但是在很大程度上是任意的。
视图空间是对象相对于摄像机的位置。剪辑空间是应用投影矩阵之后的位置,因此这些位置将根据摄影机进行缩放,如果这样做,则在世界空间中距离摄影机较远的透视投影对象在剪辑空间中会较小。
屏幕空间是应用了一些需要渲染的技巧之后的位置,因此大多数时候可以忽略视图和剪辑空间并尝试获取屏幕空间坐标。