Shader基础结构:
Shader "Custom/NewSurfaceShader" { //shader位置以及名字 Properties { //属性 } SubShader {//显卡A使用的子着色器 [Tags] //标签(可选) [RenderSetup] //状态设置(可选) //在Pass外部定义的标签和状态,会应用到所有Pass Pass{ //每个Pass定义了一次完整的渲染流程,可以有多个Pass,但如果Pass过多,会造成渲染性能下降,尽量定义最少的Pass //在Pass内部定义的标签和状态,会应用到当前Pass } } SubShader {//显卡B使用的子着色器 } FallBack "Diffuse" //如果上面所有SubShader在这块显卡上都不能运行,就使用Diffuse这个Shader //Fallback Off --如果上面SubShader都不能运行,就不管它了 }
ShaderLab属性
声明属性:_XXX(展示名, 数据类型) = 默认值
属性数据类型:
Color 颜色,由RGBA(红绿蓝透明度)四个量来定义
2D 一张2次方大小的贴图.这张贴图将在采样后被转为对应基于模型UV的每个像素的颜色,最终被显示出来
Rect 一张非2次方大小的贴图
Cube Cube map texture(立方体纹理),简单说就是6张有联系的2D贴图的组合,主要用来做反射效果(比如天空盒和动态反射),也会被转换为对应点的采样
Range(min, max) 一个介于最小值和最大值之间的浮点数
Float 任意一个浮点数
Vector 一个四维数
例:
_Range("Range", Range(0.0, 2.0)) = 1.0 _Vector("Vector", Vector) = (1, 4, 3, 8) _MainTex("Texture", 2D) = "white" {} _Cube("Cube", Cube) = "white" {}
Cg数据类型
fixed 低精度定点型 [-2, 2]
half 半精度浮点数 [-60000, 60000]
float 浮点数
int 整型
bool 布尔型
sampler* 纹理对象的句柄,分为sampler、sampler1D、sampler2D、sampler3D、samplerCUBE和samplerRECT
内置的数据类型:基于基础数据类型,如float3,表示float类型的三维向量;同理,bool2表示布尔类型的二维向量。
注:向量最长不能超过四元,如float5 vector;//编译错误
uv不能用fixed存储,因为可能通过贴图的Tiling和Offset让其范围超过[0, 1]
向量的赋值 float2 a=float(1.0,1.0);
矩阵数据类型 float1X1 m1; //即float m1,一维矩阵
float3X4 m34 //3*4阶矩阵
注:X是字符,不是乘号,最大的维数为4*4阶
ShaderLab属性类型和Cg变量类型的匹配关系:只有在CGPROGRAM内再次定义一个与属性块内名字与类型相同的变量,属性块对应的变量才能起作用
Color、Vector:float4,half4,fixed4
Range、Float:float, half, fixed
2D:sampler2D
3D:sampler3D
Cube:samplerCube
Int:int(32位整型数据)
状态设置RenderSetup(可选项),ShaderLab提供了一系列渲染状态的设置指令,这个指令可以设置显卡的各种状态:
Cull Back | Front | Off 设置多边形剔除模式:剔除背面/正面/关闭剔除
ZTest Less | Greater | LEqual | GEqual | Equal | NotEqual | Always 设置深度缓冲区测试模式
ZWrite On | Off 设置深度缓冲区写入模式
Blend SrcFactor DstFactor 开启并设置混合模式
Tags规定了混合模型,SubShader用过Tags告诉渲染引擎什么时间什么方式渲染它们
SubShader的标签是一个键值对,它的键和值都是字符串类型:
Queue 控制当前shader渲染顺序:
Background(值1000) - 最早被调用的渲染(用来渲染天空盒或者背景)
Geometry(值2000) - (默认值)用来渲染非透明物体(普通情况下,场景中的绝大多数物体是非透明的)
AlphaTest(值2450) - 用来渲染经过Alpha Test的像素,单独为AlphaTest设定一个Queue是出于对效率的考虑
Transparent(值3000) - 以从后往前的顺序渲染透明物体
Overlay(值4000) - 用来渲染叠加的效果,是渲染的最后阶段(比如镜头光晕等特效)
例"Queue" = "Transparent"
可以指定任意值,比如"Queue" = "Geometry+10"
RenderType 对着色器进行分类
Opaque - 用于大多数着色器(法线着色器,自发光着色器,反射着色器以及地形的着色器)
Transparent - 用于半透明的着色器(透明着色器,粒子着色器,字体着色器,地形额外通道的着色器)
TransparentCutout - 蒙皮透明着色器
Background: Skybox shaders. 天空盒着色器。
Overlay: GUITexture, Halo, Flare shaders. 光晕着色器、闪光着色器。
....
这些RenderType的类型名称实际上是一种约定,并无实际意义,用来区别这个shader要渲染的对象,可以自定义名字
指定RenderType名称,主要是为了配合使用替代渲染的方法:
Camera.SetReplacementShader("shader", "RenderType")
在使用替代渲染方法时,相机会使用指定的shader来代替场景中的其他shader对场景进行渲染
例"RenderType" = "zgxzgx"
DisableBatching = "True"(对此着色器禁用批处理) | "False"(默认值,使用批处理)
ForceNoShadowCasting = "True" 强制无投影
IgnoreProjector = "True" 如果为true,该subshader不会受Projector影响,通常用于半透明物体
CanUseSpriteAtlas = "False" 应用与Sprite,false表示这个sprite被打入图集时,此shader不会工作
PreviewType = "Plane" | "SkyBox" 指明材质面板将如何预览该材质
Tags { "Queue" = "Geometry+100" "RenderType" = "Opaque" "ForceNoShadowCasting" = "True" "DisableBatching" = "False" "IgnoreProjector" = "True" } Pass { Name "MyPass" //定义该Pass名称,可以被其他shader调用(UsrPass "名称")使用,提高代码复用性 //通过给Pass定义的名称,可以在使用UsePass来直接使用其他Shader的Pass,如: UsePass“MyShader/MYPASSNAME” //Unity内部会把所有的Pass名称转换成大写字母,在使用UsePass时必须使用大写形式的名字 Tags { /*Pass同样可以设置标签 LightMode 定义该Pass在Unity的渲染流水线中的角色 RequireOptions 用于指定当满足某些条件时才渲染该Pass,它的值是由空格分隔的字符串 */ "LightMode" = "ForwardBase" "RequireOptions" = "SoftVegetation" } ... }
着色器目标编译
#pragma target 2.0 Shader Model2.0不支持顶点纹理采样,不支持显示的LOD纹理采样
#pragma target 3.0 Shader Model3.0支持顶点纹理采样
#pragma target 4.0 Shader Model4.0支持几何着色器
#pragma target 5.0 Shader Model5.0
语义: 一个语义可以使用的寄存器只能使用4个浮点值
从应用阶段传递模型数据给顶点着色器(appdata)时Unity支持的常用语义
POSITION 模型空间中的顶点位置,通常是float4
NORMAL 顶点法线,通常是float3
TANGENT 顶点切线,通常是float4
TEXCOORDn(如TEXCOORD0,TEXCOORD1) 该顶点的纹理坐标,TEXCOORD0表示第一组纹理,以此类推,通常是float2或float4
COLOR 顶点颜色,通常是float4或fixed4
从顶点着色器传递数据给片元着色器(v2f)时Unity支持的常用语义
SV_POSITION 输出裁剪空间中的顶点坐标,结构体中必须包含一个该语义修饰的变量,float4
COLOR0,COLOR1 输出第一组,第二组顶点颜色,不是必须 float4或fixed4
TEXCOORD0~TEXCOORD7 输出纹理坐标,不是必须 float2或float4
片元着色器输出时Unity支持的常用语义
SV_Target 输出值将会存储到渲染目标 fixed4
Shader "Custom/Shader1" { Properties {
//只有在CGPROGRAM内再次定义一个与属性块内名字与类型相同的变量,属性块对应的变量才能起作用 _MainTex("Main Texture", 2D) = "white" {} _Color("Color", Color) = (1,1,1,1) } SubShader { pass { CGPROGRAM // 使用 "vert" 函数作为顶点着色器 #pragma vertex vert // 使用 "frag" 函数作为像素(片元)着色器 #pragma fragment frag //引入Unity内置定义 #include "UnityCG.cginc"
//与Properties中的属性对应
sampler2D _MainTex; fixed4 _Color; //顶点着色器输入 struct appdata { float4 texcoord : TEXCOORD0;//TEXCOORD0语义告诉unity,用模型的第一套纹理坐标填充texcoord变量 float4 vertex : POSITION;//POSITION语义告诉Unity,用模型空间的顶点坐标填充vertex变量 //float3 normal : NORMAL;//NORMAL语义告诉unity,用模型空间的法线方向填充normal坐标 }; //顶点着色器输出("顶点到片元") struct v2f { float4 texcoord : TEXCOORD0; float4 vertex : SV_POSITION;//SV(system value系统数值)必须有,SV_POSITION语义告诉unity,vertex里面包含了顶点在裁剪空间中的位置信息 //fixed3 color : COLOR;//COLOR语义可以用于存储颜色信息 }; //顶点着色器是逐顶点调用的 v2f vert(appdata d) { v2f v; //将位置转换为裁剪空间 v.vertex = UnityObjectToClipPos(d.vertex); //仅传递纹理坐标 v.texcoord = d.texcoord; //将计算后的结果输出给渲染引擎,底层会根据具体的语义去做对应的处理 return v; } //片元着色器是逐片元调用的,片元着色器的输入实际上是把顶点着色器的输出进行插值后得到的结果; //SV_Target告诉渲染器把用户的输出颜色存储到一个渲染目标中 fixed4 frag(v2f v) : SV_TARGET { //仅对纹理进行采样并将其返回 fixed4 te = tex2D(_MainTex, v.texcoord) * _Color; return te; } ENDCG } } }