结构体允许储存多个不同类型的变量,并将多个变量包装成为一个整体进行输入或者输出。
结构体如下:
struct Type
{
//变量 _1;
//变量 _2;
//变量 _3;
//变量 _4;
}
struct:定义结构体的关键词。
Type:给当前结构体定义一种类型,着色器函数定义输入和输出数据类型时会用到,结构体内包含的变量仍然需要定义数据类型和名称,然后填充对应的语义。最后通过[结构体名称].[变量名称]的语法访问,
例如:v.vertex,表示访问名称 v 的结构体内的vertex变量。
大概了解了结构体的使用方法,接下来就把Pass第三篇中的1.3.Shader改写为以结构体作为输入和输出的Shader,代码如下:
Shader "Unlit/结构体应用"
{
Properties
{
_MainTex("MainTex", 2D) = "white" {}
_MainColor("MainColor",Color) = (1,1,1,1)
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag//这三行已经很熟悉了吧
//定义顶点着色器的输入结构体
struct appdata //appdata 是 ApplicationData的缩写,意思是获取数据。
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;//这里把顶点着色器的 输入参数 都写在了结构体内。
};
//定义顶点着色器的输出结构体
struct v2f//v2f中 v代表vertex、2代表 to、f代表fragment。表示从顶点着色器传递到片段着色器的数据。
{
float4 position : SV_POSITION;
float2 texcoord : TEXCOORD0;//这里把顶点着色器的 输出参数 写在结构体内。
};//这些语义词,可以看前面Pass第二篇的内容。
float4 _MainColor; //在CG中以float4类型再次声明
sampler2D _MainTex;
float4 _MainColor_ST; //声明纹理属性变量以及ST变量
void vert(in appdata v,out v2f o)//顶点着色器 输入appdata类型的结构体,定义名称为v(vertex的首字母)
{ //顶点着色器 输出v2f类型的结构体,定义名称为o(out的首字母)
o.position = UnityObjectToClipPos(vertex);
//使用公式计算纹理坐标
o.texcoord = uv * _MainColor_ST.xy + _MainColor_ST.zw;
}
//使用结构体传入传出参数
void frag(in v2f i,out float4 color : SV_TARGET)
//顶点着色器经过计算,将v2f结构体传递给片段着色器,于是v2f结构体成了片段着色器的输入结构体
//并且在片段函数中重新定义名称为i(in的首字母)。
{
Color = tex2D(_MainTex,i.texcoord) * _MainColor;
//经过片段着色器的计算之后最终输出fixed4类型的color。
}
ENDCG
}
}
}
1.2.返回结构体的函数
在Pass第一篇里介绍了有返回值的函数,返回函数也可以做到返回结构体,那么话不多说,下面就把无返回值的Shader改写成返回结构体的Shader:
Shader "Unlit/返回结构体的函数"
{
Properties
{
_MainTex("MainTex", 2D) = "white" {}
_MainColor("MainColor",Color) = (1,1,1,1)
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 position : SV_POSITION;
float2 texcoord : TEXCOORD0;
};
float4 _MainColor;
sampler2D _MainTex;
float4 _MainColor_ST;
v2f vert(appdata v)//顶点着色器定义了返回值的类型v2f的结构体,然后输入appdata类型的结构体,名称为v,这里省略了输入关键词in
{
v2f o,//在函数内声明v2f的名称为o
o.position = UnityObjectToClipPos(v.vertex);
o.texcoord = v.uv * _MainColor_ST.xy + _MainColor_ST.zw;
return o;//经过顶点着色器的计算之后返回o
}
fixed4 frag(v2f i) : SV_TARGET // 片段着色器定义了返回类型fixed4,输入类型为v2f的结构体,名称为i
{
return tex2D(_MainTex,i.texcoord) * _MainColor;
}
ENDCG
}
}
}
这样写整洁很多,也就是使用结构体储存变量形式更简洁点。
Unity Shader 中Pass相关介绍到第四篇了,自己会看了一遍又一遍,发现还有很多没有涉及到的内容,比如:顶点和向量变换函数、视角向量函数,其他很多辅助函数,Unity中一些常用的包含文件,还有渲染平台的差异性,渲染流水线都没有细致的捋一遍。一时之间可能做不全,后续会跟着一个一个的案例来补齐不足。
接下来需要完整的补上渲染流水线和Shader概念(是Shader不是Unity Shader哈,这两个词是两个东西。),这样看会更清晰点,之所以放在这些代码块介绍之后,是方便理解GPU渲染管线对应的代码块所在的位置,这个前后学习不受影响。当然在讲述的过程中也有带着解释渲染流程的概念。



