参考<>第五章
一、如何获取其他模型数据
在001里介绍了通过POSITION获取顶点位置坐标,如果想的到更多的模型数据,比如我们想要得到模型上每个顶点的纹理坐标和法线方向
PS:我们可以通过纹理坐标来访问纹理 法线坐标一般用来计算光照
因此我们需要给顶点着色器定义一个新的参数·这个参数将不是一个简单的数据类型
而是一个结构体
Shader "Customer/SimpleShader003"{
SubShader{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct a2v{
float4 vertex: POSITION;
float3 normal:NORMAL;
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 他包含了顶点着色器需要的模型数据
在a2v的定义中,我们用到了更多的UNITY支持的语义,如
NORMAL 和TEXCOORD0,当他们作为顶点着色器的输入时都是有特定含义的
因为UNITY会根据这些语义来填充这个结构体,对于顶点着色器的输出,UNITY
支持的语义有POSITION,TANGENTM,NORMAL,TEXCOORD0,TEXCOORD1,TEXCOORD2
TEXCOORD3,COLOR等。
为了使用一个自定义的结构体,我们必须使用如下格式
struct name{
Type Name:Semantic;
Type Name:Semantic;
......
};
a表示应用 v表示顶点着色器 a2v的意义就是从应用阶段传递到顶点着色器中
那么填充到POSITION,TANGENT,NORMAL的语义里的数据酒究竟是从哪里来的呢?
在UNITY中,它们是由使用该材质的MeshRender组件提供的。
在每帧调用DRAW CALL的时候,MeshRender组件会把他负责渲染的模型的数据发送给UNITY SHADER,
我们知道,一个模型通常包含了一组三角面片。(我们不知道啊QAQ)
每个三角面片由三个顶点构成,而每个顶点又包含了一些数据,例如顶点位置、发现坐标、顶点颜色等等
通过上面的方法,我们就可以在顶点着色器中访问顶点的这些模型数据。
二、顶点、片元着色器之间如何相互通信
我们在实际开发的过程中,往往希望从顶点着色器输出一些数据,例如把模型的法线纹理坐标等传递给片元着色器
这就涉及到了顶点着色器和片元着色器之间的通信
为此我们需要新建一个结构体.修改后代码如下
Shader "Customer/SimpleShader004"{
SubShader{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
float4 texcoord:TEXCOORD0;
};
//使用一个结构体来定义顶点着色器的输出
struct v2f{
float4 pos :SV_POSITION;
fixed3 color:COLOR0;
};
v2f vert(a2v v):SV_POSITION{
v2f o;
o.pos = mul(UNITY_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{
return fixed4(i.color,1.0);
}
ENDCG
}
}
}
在上面的代码中,我们声明了一个新的结构体v2f
v2f中也需要指定每个变量的语义,在本例中我们定义了SV_POSITION和COLOR0,顶点着色器的输出结构中,必须包含SV_POSITION,否则无法获取
裁剪空间的顶点坐标,COLOR0则由用户自己定义,一般是用来存颜色,例如逐顶点的漫反射颜色等,类似语义还有COLOR1
至此我们完成了从顶点着色器往片元着色器传递数据,顶点着色器是逐顶点的,片元着色器是逐片元的,因此片元着色器的输入实际是把顶点着色器的输出进行插值的结果
二、如何使用属性
unityshader和材质密不可分,shader提供了一些可以设置的参数来调试材质的效果,这些参数需要写在properties语义块里面
比如我们现在有一个新的需求,需要在面板上显示一个颜色拾取器,为此需要修改上面的代码
Shader "Customer/SimpleShader004"{
Properties{
//声明一个color类型的属性
_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:NORMAL;
float4 texcoord:TEXCOORD0;
};
struct v2f{
float4 pos:SV_POSITION;
float3 color:COLOR0;
};
v2f vert(a2v v) :SV_POSITION{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
o.color = v.color*0.5+fixed3(0.5,0.5,0.5);
return o;
}
fixed4 frag(v2f i):SV_Target{
fixed3 = i.color;
c *=_Color.rgb;
return fixed4(c,1.0);
}
ENDCG
}
}
}
在上面的语句里我们定义了一个color,(1.0,1.0,1.0,1.0)代表的是白色
为了在CG代码里面访问他,我们还需要提前自己定义一个新变量 ,该变量名必须和属性里的变量名一致
ShaderLab中变量和CG类型中变量对应的关系如下所示
有时 CG变量前会有一个 uniform 关键字
uniform fixed4 _Color; 该关键字在CG里是用来修饰变量,仅仅提供该变量初始值的是如何指定和存储的相关信息,UNITYSHADER里该关键字可以省略。