文章目录
标准shader结构(顶点片元)
Shader "Unlit/phong"{
Properties{
SubShader{
【标签、状态】
Pass{
【name、标签、状态】
CGPROGRAM
【#include】
【着色器声明】
【struct】
【属性声明】
【vert】
【frag】
ENDCG
}
Pass{
}
}
SubShader{
}
Fallback
}
}
一些注意事项
-
shaderlab不区分大小写!(尽管不区分,但是引用外部变量和函数时,大小写还是要写对啊!)
-
shaderlab和hlsl很相似,但是不完全相同
Shader “位置”
- 这里表明文件所在的位置和名称
- 经实验,这里的名称及位置和真实的没有相互作用,仅在初始化时一致
Properties
Properties
{
_Name ("display name", Type) = DefaultValue
数
_Int ("Int", Int) = 2
_Float ("Float",Float) = 1.11
_Gloss ("Gloss", Range(8,256)) = 20 //Range(a,b)会产生一个可拖动的条
[IntRange] _Int("Int", Range(0, 255)) = 0 //[_IntRange]用于限定编辑器面板中只能调节为整数值
向量
_Diffuse ("Diffuse", Color) = (1,1,1,1) //Color会产生调色盘
_Vector ("Vector", Vector) = (1,2,3,4)
纹理
_2D("2D", 2D) = ""{
}
_3D("3D", 3D) = ""{
}
_Cube("Cube", CUBE) = ""{
}
}
- 这里的属性会显示在材质面板,方便调节
SubShader
subshader{
//标签 可选
Tags {
"tagname0" = "value0" "tagname1" = "value1"}
//状态 可选
RenderSetup
Pass{
}
//other Passes
}
- subshader只会执行一个,即第一个可以在本机上运行的shader,如果都不行,就执行fallback(相当于
if -> ifelse -> else
) - 一般而言subshader的性能开销从上到下越来越高
- 大部分subshader都包含复数条Pass,但我们一般要求pass数量尽量少,以提高性能
- 此处声明的标签和状态会应用到该subshader中的所有pass
UsePass
UsePass "ShaderName" + "/" + "PassName"
- 这个就是Pass名的使用方式,直接引用一整个pass
- 不用管大小写,shaderlab不区分
- 不用担心UsePass中的vert/frag和当前Shader的vert/frag同名,这两部分是分开的
- 相当于直接把Pass代码复制过去,但是Properties并没有,所以需要手动添加需要的Properties
GrabPass
抓取屏幕存储到纹理中,用于后续的pass处理
Pass
每一条pass都包含了完整的渲染流程
Pass{
Name "mypass" //Name的意义是可以在其他的shader中直接调用该pass
Tags {
"LightMode" = "ForwardBase"}
Rendertype {
"" = ""}
CGPROGRAM
#pragma vertex vert //指定两个着色器的名字
#pragma fragment frag
#include "UnityCG.cginc" //外接一些库
#include "Lighting.cginc"
float4 _Diffuse; //把properties中的值在pass中声明一下才能使用,注意变量类型
float _Gloss;
[vert]
[frag]
ENDCG
}
- 如果着色器需要自定义函数,写在相应的着色器之前
Fallback
Fallback "name"
或关闭
FallBack Off
- fallback一般是该对象渲染的最低限度,但也有其他用处
- fallback是和subshader同级的,不是和pass
- 在阴影纹理渲染中,unity要求每个一个用来透射阴影的Pass,而fallback会内置它,所以在渲染阴影时可以不特地创建一个阴影pass而直接选择fallback代替
特殊结构
CGINCLUDE结构
Subshader
{
CGINCLUDE
#include "UnityCG.cginc"
【声明的property】
【数据结构】
【vert1】
【vert2】
【frag1】
【frag2】
ENDCG
Pass
{
CGPROGRAM
#pragma vertex 【vert1】
#pragma fragment 【frag2】
ENDCG
}
}
-
CGINCLUDE中可以写多个着色器,并且不需要提前声明
-
这个东西存在的意义:减少重复编写,使结构简单
(本质上是把include里面的代码复制到每一条Pass,和引用头文件相同) -
可以这么理解:将顶点/片元着色器视作大型的function,从Pass中抽象出来,写在CGINCLUDE里,之后的多个Pass需要同样的着色器时,只需要引用着色器就好了