001-shader基础
2022.5.27
shader通俗理解来说就是shader代码,在Unity里面我们通过shader代码来控制渲染的效果
Unity里面的shader代码叫做shaderlab
当我们在Unity中创建一个Shader时(Surface Shader / Vertex&Fragment Shader),会生成一个 .shader 的文件,打开这个文件时可以看到其内容由一堆代码组成,这堆代码就是控制着我们的渲染效果
我们的shader是赋值给Material的
我们在shader里面设置的参数,都会在Material的面板里面进行显示
我们设置参数的意义,就在于与外界交互,比如说下面的shader
我可以随意修改其参数面板来达到不同的渲染效果
这个修改的过程可以是手动改,也可以是通过代码来控制
对应属性块代码一一对应,发现这些参数的设置还是很有规律的
比如Int类型在参数面板就是一个int输入框
Range类型在参数面板是一个slider
Vector类型在参数面板是一个Vector4
//属性块
Properties
{
_Int("Int",int) = 2
_Float("Float",float)=1.5
_Range("Range",range(0.0,2.0))=1.5
_Color("Color",Color)=(1,1,1,1)
_Vector("Vector",Vector)=(1,4,3,8)
_MainTex ("Texture", 2D) = "red" {} //2d图片 贴图
//CubeMap就是天空盒 我们在这里用一个CubeMap肯定比用六张2d贴图更节省操作,空间
_Cube("Cube",Cube) = "white"{}
_3D("3D",3D) = "black"{} //3D是和CubeMap类似的 不常用
}
我们的Shader标签,就是在子着色器SubShader里面的
这也就意味着,这些标签只对这这一个子着色器产生影响,对这个子着色器内部的所有通道产生影响
同样的,我们可以将Shader标签放在一个通道里面,表示只对这一个通道产生影响
但是内外都定义了同一个Tags 走的还是外面的Tags
//标签 可选 key=value
Tags
{
"Queue"="Transparent" //渲染顺序
"RenderType"="Opaque" //渲染类型 着色器替换功能
//比如说C#代码在渲染完成之后可以根据渲染类型 更换shader
//比如将全部渲染类型为透明的 换为 渲染类型不透明的Shader
"DisableBatching"="True" //是否进行合批
"ForceNoShadowCasting"="True" //是否投射阴影
//projector是unity里面做阴影的一个东西
"IgnoreProjector"="True" //受不受Projector的影响 通常用于透明物体
//比如透明物体肯定不想受阴影影响
"CanUseSpriteAltas"="False" //是否是用于图片的Shader,通常用于UI
"PreviewType"="Plane" //用于shader面板预览的属性 不设定的话就是一个3d的球形状
}
//下面所有Pass都使用这个Tags 但是我们也可以在Pass通道里面进行
//但是内外都定义了同一个Tags 走的还是外面的Tags
这些都是关于Shader渲染过程的一些参数设置
//Render渲染设置 可选
//裁剪 旋转切除掉的面
//off是裁剪关闭让正反两面都渲染 Back是切掉背面渲染前面 front是切掉前面切掉背面
// Cull off/back/front
//深度测试 Z轴 应为屏幕是二维坐标 深度这个概念是在Z轴上的
//比如LEqual 就是less or equal(小于等于)就代表通过深度测试
// ZTest Always/Less Greater/LEqual/GEqual/Equal/NotEqual
//深度写入
// Zwrite off/on
//混合 融合 Src源 Dst目标
//Blend SrcFactor DstFactor
//LOD 不同情况下使用不同的LOD,达到图像性能提升 LOD越大 需要性能越强
//一般手机端可以设置为50 PC设置为100
LOD 100
//下面所有Pass都使用这个渲染设置 但是我们也可以在Pass通道里面进行
//但是内外都定义了同一个渲染设置 走的还是外面的渲染设置
我们现在对这段Pass内部的代码进行分析
Pass
{
Tags
{
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
1.建议不要多个Pass通道 多一个Pass就是多一个DrawCall 但是一个SubShader必须有一个Pass
当我们在另外的Shader文件里面需要使用当前的shader文件的Pass
直接通过 Use 路径加Name就可以实现 Tips:Use Pass通道的时候 要对名字用全大写
Name “Default” //Pass通道名称
Tags{} 可以在每个Pass通道里面进行定义
2.我们可以设置单独的Pass通道内的Tag
Tags
{
//光照模型(渲染方式) ForwardBase前向渲染
//定义该Pass通道在Unity渲染流水中的角色
"LightMode"="ForwardBase"
//"RequireOptions"="SoftVegetation SoftVegetation2" //满足某些条件时才渲染该Pass通道 条件1 条件2 条件3
}
3.Pass内部的代码从 CGPROGRAM 开始 ENDCG 结束
在CGPROGRAM 下面
也就是刚开始的时候我们得指定vertex(顶点着色器)的函数名 和 fragment(片元着色器)的函数名
这里,我指定顶点着色器的函数名为vert,我们在下面写vert这个函数的时候,编辑器就会将其作为顶点着色器函数
同样,frag在这里指定为片元着色器
#pragma vertex vert
#pragma fragment frag
4.在这里,我们可以引用对应编辑器版本的Shader库,这些都是写好的内容,我们可以直接引用,避免反复造轮子
#include "UnityCG.cginc"
这里就引用了"UnityCG.cginc"这里面的东西
5.我们现在对shader里面的结构体进行分析
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
比如说,这里我们将原语POSITION,模型坐标赋值给参数vertex
将原语TEXCOORD0(第一个贴图)赋值给uv
6.Pass内部的变量
我们定义在Pass内部的变量
sampler2D _MainTex;
float4 _MainTex_ST;
7.顶点着色器
我们在前面定义了vert为顶点着色器的函数名
在这里我们将appdate这个结构体的变量作为参数传入
将v2f这个结构体的变量作为返回
在内部,我们实例化一个v2f结构体,对其的vertex值进行修改
也就是对原语POSITION进行修改
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
这里返回的v2f就是计算完成后的顶点信息
8.片元着色器
在这里,我们将v2f作为参数,返回一个fixed4颜色值
这个颜色值就是通过片元着色器计算出来的当前像素的颜色值
这里我们根据tex2D()对我们之前定义的变量_MainTex根据uv进行采样
由于,我们前面定义参数的时候,默认它是一张红色的贴图,
所以整个模型,都会是红色
因为每个像素点取样得到的颜色,都为红色
如果我们修改了_MainTex,那么采样结果肯定也会被修改
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
这是Unity自带的Shader库,每一个版本都不一样,我们可以在官网进行下载我们当前编辑器版本的Shader库
我们下载下来之后,就可以看到有很多写到的库函数,我们只需要引用就可以了
比如说之前代码里面引用的库
内部实际上定义了很多语句
可以类似理解为C#的命名空间,我们只有引入命名空间,才能使用里面的语句函数等
也可类似理解为C语言的头文件