一、shader基本结构
可以参考 笔记05基本结构介绍
二、代码例子
Shader “Unity Shaders Book/Chapter 5/Simple Shader”
{
SubShader
{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 vert(float4 v: POSITION):SV_POSITION
{
return mul (UNITY_MATRIX_MVP,v);
}
fixed4 frag():SV_Target
{
return fixed4(1.0,1.0,1.0,1.0);
}
ENDCG
}
}
}
#pragma vertex name
#pragma fragment name
这两行是告诉Unity,哪个函数是顶点着色器/片元着色器的代码。
vert() 函数中,POSITION与SV_POSITION是Cg/HLSL中的语义;
POSITION告诉Untiy,把模型顶点坐标传给参数v,
SV_POSITION告诉Unity顶点着色器输出的是裁剪空间坐标。
return中,代表将模型空间转换到裁剪空间中。
frag()函数中,没有输入函数,输出fixed4类型变量。
SV_Target语义用来告诉渲染器,把用户输出的颜色存储到一个渲染目标中,这里将输出到默认的帧缓存中。
片元着色器输出颜色分量范围在[0,1]中,(0,0,0)即代表黑色,(1,1,1)代表白色。此处片元着色器就是返回了表示白色的变量。
三、模型数据来源
Shader “Unity Shaders Book/Chapter 5/Simple Shader”
{
SubShader
{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct a2v
{
float4 vertex:POSITION;
float3 normal:NOLMAL;
float4 texcoord:TEXCOORD0;
};
float4 vert(a2v v):SV_POSITION
{
return mul (UNITY_MATRIX_MVP, v.vertex);
}
fixed4 frag():SV_Target
{
return fixed4(1.0,1.0,1.0,1.0);
}
ENDCG
}
}
}
上面代码,新建了一个结构体,a2v(代表把应用阶段传递到顶点着色器中),包含顶点着色器需要的模型数据,在结构体中进行语义定义,更多语义后面章节介绍。
声名的语义中为什么可以提供数据呢,
它们是由该材质的Mesh Render组件提供的。
Mesh Render组件在系统调用Draw Call时,将它所负责的模型数据发给Untiy Shader。
四、顶点着色器与片元着色器之间通信(传递法线、纹理坐标等等)
还是通过定义新的结构体,代码:
Shader “Unity Shaders Book/Chapter 5/Simple Shader”
{
SubShader
{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct a2v
{
float4 vertex:POSITION;
float3 normal:NOLMAL;
float4 texcoord:TEXCOORD0;
};
struct v2f
{
float4 pos: SV_POSITION;
fixed3 color: COLOR0;
}
float4 vert(a2v v)
{
v2f o;
o.pos=mul(UNTIY_MATRIX_MVP, v.vertex);
//输出的裁剪空间坐标,同样是SV_POSITION语义。
o.color=v.normal*0.5+fixed3(0.5,0.5,0.5);
//v.mormal包含顶点法线,分量范围[-1,1];
//运用计算将其分量范围映射到[0,1];
return o;
}
fixed4 frag(v2f i):SV_Target
{
return fixed4(i.color, 1.0);
}
ENDCG
}
}
}
v2f结构体,用于在顶点和片元着色器间传递信息。
SV_POSITION语义告诉unity,pos里包含了顶点在裁剪空间中的位置信息。
COLOR0语义可以用来储存颜色信息。
顶点着色器是逐顶点调用的,片元着色器是逐片元调用的。
片元着色器的输入实际上是把顶点着色器的输出进行插值后得到的结果。
五、属性的使用
材质可以让我们方便的调节Unity Shader中的参数。
这些参数就要写在属性内。
Shader “Unity Shaders Book/Chapter 5/Simple Shader”
{
Properties
{
_Color("Color Tint",Color)=(1.0,1.0,1.0,1.0)
}
SubShader
{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//定义一个与属性类型名称都相匹配的变量。
fixed4 _Color;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NOLMAL;
float4 texcoord:TEXCOORD0;
};
struct v2f
{
float4 pos: SV_POSITION;
fixed3 color: COLOR0;
}
float4 vert(a2v v)
{
v2f o;
o.pos=mul(UNTIY_MATRIX_MVP, v.vertex);
o.color=v.normal*0.5+fixed3(0.5,0.5,0.5);
return o;
}
fixed4 frag(v2f i):SV_Target
{
fixed3 c=i.color;
c*=_Color.rgb;
return fixed4(c, 1.0);
}
ENDCG
}
}
}
这里的定义属性名称是_Color,类型是Color,面板上名称是Color Tint。
属性类型描述在05中有写过。
在Cg中定义的变量类型与属性类型匹配关系有时,Cg变量前会多一个 uniform 关键字:
uniform fixed4 _Color;
此处与其他编程接口的uniform不同,这里是提供一些关于该变量的初始值是如何指定和存储相关信息。
六、Unity提供的内置文件和变量
使用方法
CGPROGRAM
#include "UnityCG.cginc"
ENDCG
文件位置即相应功能在107页。
其它内置:
七、语义
语义实际上就是一个赋给Shader输入和输出的字符串,这个字符串表达了这个参数的含义。(就是让Shader知道从哪里读取数据,把数据输出到哪里)
110页
变量类型定义建议:
struct v2f
{
float4 pos : SV_POSITION;
fixed3 color0 : COLOR0;
fixed4 color1 : COLOR1;
half value0 : TEXCOORD0;
float2 value1 : TEXCOORD1;
}
如果我们需要定义矩阵类型时,必要时可以将变量拆分成多个变量。
(因为语义使用的寄存器只能处理4个浮点值)。