顶点着色器和片段着色器。
可编程Shader的特点为:
- 功能最强大、最自由的形态。
- 特征是在Pass里出现CGPROGRAM和ENDCG块
- 编译指令#pragma。详见官网Cg snippets。其中重要的包括:
编译指令
示例/含义
#pragma vertex name
#pragma fragment name替换name,来指定Vertex Shader函数、Fragment Shader函数。
#pragma target name
替换name(为2.0、3.0等)。设置编译目标shader model的版本。
#pragma only_renderers name name ...
#pragma exclude_renderers name name...#pragma only_renderers gles gles3,
#pragma exclude_renderers d3d9 d3d11 opengl,
只为指定渲染平台(render platform)编译
- 关于引用库。通过形如#include "UnityCG.cginc"引入指定的库。常用的就是UnityCG.cginc了。其他库详见官网Built-in shader include files。
- ShaderLab内置值。Unity给Shader程序提供了便捷的、常用的值,比如下面例子中的UNITY_MATRIX_MVP就代表了这个时刻的MVP矩阵。详见官网ShaderLab built-in values。
- Shader输入输出参数语义(Semantics)。在管线流程中每个阶段之间(比如Vertex Shader阶段和FragmentShader阶段之间)的输入输出参数,通过语义字符串,来指定参数的含义。常用的语义包括:COLOR、SV_Position、TEXCOORD[n]。完整的参数语义可见HLSL Semantic(由于是HLSL的连接,所以可能不完全在Unity里可以使用)。
- 特别地,因为Vertex Shader的的输入往往是管线的最开始,Unity为此内置了常用的数据结构:
数据结构
含义
appdata_base
顶点着色器输入位置、法线以及一个纹理坐标。
appdata_tan
顶点着色器输入位置、法线、切线以及一个纹理坐标。
appdata_full
顶点着色器输入位置、法线、切线、顶点颜色以及两个纹理坐标。
appdata_img
顶点着色器输入位置以及一个纹理坐标。
例子如下:
Shader "基础/简单的顶点和片段着色器"
{
//-------------------------------【属性】--------------------------------------
Properties
{
_Color ("Color", Color) = (1.0,1.0,1.0,1.0)
_SpecColor ("Specular Color", Color) = (1.0,1.0,1.0,1.0)
_Shininess ("Shininess", Float) = 10
}
//--------------------------------【子着色器】--------------------------------
SubShader
{
//-----------子着色器标签----------
Tags { "LightMode" = "ForwardBase" }
//----------------通道---------------
Pass
{
//-------------------开始CG着色器编程语言段-----------------
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//---------------声明变量--------------
uniform float4 _Color;
uniform float4 _SpecColor;
uniform float _Shininess;
//--------------定义变量--------------
uniform float4 _LightColor0;
//--------------顶点输入结构体-------------
struct vertexInput
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
//--------------顶点输出结构体-------------
struct vertexOutput
{
float4 pos : SV_POSITION;
float4 col : COLOR;
};
//--------------顶点函数--------------
vertexOutput vert(vertexInput v)
{
vertexOutput o;
//一些方向
float3 normalDirection = normalize( mul( float4(v.normal, 0.0), _World2Object ).xyz );
float3 viewDirection = normalize( float3( float4( _WorldSpaceCameraPos.xyz, 1.0) - mul(_Object2World, v.vertex).xyz ) );
float3 lightDirection;
float atten = 1.0;
//光照
lightDirection = normalize(_WorldSpaceLightPos0.xyz);
float3 diffuseReflection = atten * _LightColor0.xyz * max( 0.0, dot( normalDirection, lightDirection ) );
float3 specularReflection = atten * _LightColor0.xyz * _SpecColor.rgb * max( 0.0, dot( normalDirection, lightDirection ) ) * pow( max( 0.0, dot( reflect( -lightDirection, normalDirection ), viewDirection ) ), _Shininess );
float3 lightFinal = diffuseReflection + specularReflection + UNITY_LIGHTMODEL_AMBIENT;
//计算结果
o.col = float4(lightFinal * _Color.rgb, 1.0);//颜色
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//位置
return o;
}
//--------------片段函数---------------
float4 frag(vertexOutput i) : COLOR
{
return i.col;
}
//-------------------结束CG着色器编程语言段------------------
ENDCG
}
}
//备胎
Fallback "Diffuse"
}