一、unity shader和材质的关系在上节中我们了解了shader的相关知识点unity shader与shader是不同的概念shader是运行在GPU的算法unity shader相当于是 Unity 搞出来的一个“开箱即用套件”它用ShaderLab 语法把“UI界面、渲染设置、跨平台翻译”和“Shader算法本身”全打包在了一起。unity shader的使用离不开材质通俗来讲Unity shader像图纸上面记载着渲染所需的公式比如光照顶点数据等等而材质就是实现图纸内容的实物负责存储具体的颜色、贴图图片、金属度参数等等。它必须挂载一个指定的 Shader然后把这些参数填进去。总结来说Shader 决定了材质“能调什么参数”以及“怎么画出来”材质Material决定了这些参数“具体是多少”二、初识shaderLabunity shader是通过shaderLab语法进行编写的shaderLab主要由名字属性properties子着色器Subshader备用着色器Fallback组成。在unity中创建一个shader文件打开就能看见相应的结构三、shaderlab的组件刨析1.名字该部分通常在创建文件名时就已经设置好了sahder的名字决定在材质面板的选择路径不能用中文表示否则在材质面板上不会显示2.属性该部分会在材质面板上展现可在材质面板上进行编辑所输入的变量也会提供给后面的子着色器使用属性中的类型主要分为数值向量和颜色纹理贴图三大类。通用的语法结构是properties{ _Name(DisplayName,type){} }_ Name就是该属性名字displayname就是在控制面板上展现的名称type即为三大类类型数值类型通常为Int,Float,Range(min,max)语法结构_MyInt(MyInt,Int)number _MyFloat(MyFloat,Float)number _MyRange(MyRange,Range(min,max))number颜色和向量类型颜色为RGBA数值范围为0-1向量为XYZW(范围无限制)_MyColor(MyColor,Color)(0.5,0.2,0.6,0.3) _MyVector(MyVector,Vector)(200,50,90,60)纹理贴图纹理贴图类型主要分为四种2D(常用贴图适用漫反射法线贴图等)2DArray纹理数组允许在纹理中存储多层图像数据,cube立方体纹理由前后左右上下6张有联系的2D贴图比如天空和反射探针,3D3D纹理语法结构 “颜色”有black、gray、bump等等可选_MyTexture(MyTexture,2D)white{} _MyTexture(MyTexture,3D)white{} _MyTexture(MyTexture,2DArray)white{} _MyTexture(MyTexture,cube)white{}以下是实践效果在属性块内进行编写可以在材质面板上编辑看到3.子着色器子着色器由渲染标签、渲染状态、渲染通道三部分组成1渲染标签通过标签来确定什么时候以及如何对物体进行渲染通用的语法结构以键值对方式进行表示Tags{ 标签名1“标签值1” 标签名2“标签值2” }以下是标签类型Queue控制渲染顺序指定物体所属的渲染队列。通过这种方式可以确保透明物体在所有不透明物体后面被渲染从而得到正确的混合效果。常用渲染队列及其用途队列名称队列值说明典型用途Background1000最早被渲染的队列用于渲染天空盒、背景等天空盒、背景图Geometry2000默认队列用于不透明几何体墙壁、地面、不透明物体AlphaTest2450用于需要进行 Alpha 测试的几何体有透明通道但需要硬边缘栅栏、树叶、带透明通道的贴图Transparent3000用于半透明物体按从远到近的顺序绘制玻璃、水、粒子特效Overlay4000最后渲染的队列用于叠加效果UI、镜头光晕、屏幕后处理使用示例Tags { Queue Background Queue Geometry100 // 在 Geometry 队列基础上偏移 100 // 或直接使用队列值 Queue 2450 // AlphaTest 队列 }注意事项队列值越小越先渲染值越大越后渲染透明物体Transparent必须放在不透明物体Geometry之后渲染可以通过 数值 的方式在基础队列上进行微调Overlay 队列通常用于全屏叠加效果应放在所有其他队列之后RenderType渲染类型可以对着色器进行分类可被用于着色其替换功能DisableBatching 禁用批处理上节我们说过批处理是多合一的过程有时批处理可能会导致空间坐标混乱等问题Shader 逻辑强依赖物体的局部空间数据或逐物体独立属性时才需要禁用。否则保持默认让 Unity 自动批处理以优化性能。ForceNoShadowCasting物体是否投射会有阴影PreviewType材质预览在材质面板上默认是球型可把标签值设为Plane,SkyBoxIgnoreProject忽略投影机通常用于半透明物体2渲染状态通过状态来确定渲染时的剔除方式、深度测试方式、混合方式1.剔除方式设置多边形的剔除方式有背面剔除、正面剔除、不剔除默认背面剔除Cull Back-----背面剔除 Cull Front----正面剔除 Cull off ----不剔除2.深度测试决定当前片元像素是否应该写入深度缓冲区。当开启深度测试时GPU会比较当前片元的深度值与深度缓冲区中对应位置的深度值根据设定的比较函数决定是否通过测试。ZTest Less // 默认值当前深度小于缓冲区深度时通过近处物体遮挡远处 ZTest Greater // 当前深度大于缓冲区深度时通过 ZTest LEqual // 当前深度小于等于缓冲区深度时通过 ZTest GEqual // 当前深度大于等于缓冲区深度时通过 ZTest Equal // 当前深度等于缓冲区深度时通过 ZTest NotEqual // 当前深度不等于缓冲区深度时通过 ZTest Always // 总是通过关闭深度测试 ZTest Off // 等同于 Always3.深度写入控制是否更新深度缓冲区的值。即使深度测试通过也可以选择不写入新的深度值。只要过了深度测试即使没写入深度写入图元最终也会被渲染ZWrite On // 默认值通过深度测试后写入深度缓冲区 ZWrite Off // 不写入深度缓冲区深度测试常见组合ZWrite On ZTest LEqual标准不透明物体近处遮挡远处ZWrite Off ZTest LEqual半透明物体参与深度比较但不写入深度避免后续半透明物体被错误遮挡ZWrite On ZTest Always总是写入深度如天空盒但会遮挡后续物体ZWrite Off ZTest Always完全忽略深度如全屏后处理效果4.模板测试使用模板缓冲区进行更精细的像素级控制常用于特殊效果如镜子、轮廓、区域遮罩。Stencil { Ref 1 // 参考值0-255 Comp Always // 比较函数Always, Never, Equal, NotEqual, Less, LessEqual, Greater, GreaterEqual Pass Keep // 测试通过时的操作Keep, Zero, Replace, IncrSat, DecrSat, Invert, IncrWrap, DecrWrap Fail Keep // 测试失败时的操作 ZFail Keep // 深度测试失败时的操作 ReadMask 255 // 读取掩码 WriteMask 255 // 写入掩码 }模板测试应用示例镜子效果先绘制镜子区域到模板缓冲区然后只在该区域内绘制反射内容轮廓描边先正常绘制物体然后放大模型并只在模板缓冲区未标记的区域绘制轮廓区域限制限制某些特效只在特定屏幕区域显示5.颜色掩码控制哪些颜色通道R/G/B/A可以写入颜色缓冲区。ColorMask R // 只写入红色通道 ColorMask RG // 只写入红绿通道 ColorMask RGB // 只写入RGB通道不写入Alpha ColorMask 0 // 不写入任何颜色通道但深度/模板测试仍可进行 ColorMask RGBA // 写入所有通道默认颜色掩码应用场景特殊效果中只修改特定颜色通道深度预渲染时禁用颜色写入以提高性能创建自定义G缓冲区布局6.混合模式控制当前片元颜色如何与颜色缓冲区中已有颜色进行混合主要用于透明效果。Blend SrcAlpha OneMinusSrcAlpha // 标准Alpha混合最常用 Blend One One // 加法混合发光效果 Blend OneMinusDstColor One // 软加法混合 Blend DstColor Zero // 乘法混合 Blend SrcAlpha OneMinusSrcAlpha, One One // 分别指定RGB和Alpha的混合深度测试与缓冲测试的关系深度测试和模板测试可以同时启用执行顺序通常是模板测试 → 深度测试 → 混合模板测试失败会直接丢弃片元不进行深度测试和混合深度测试失败会丢弃片元但模板测试可能已经更新了模板缓冲区取决于ZFail设置颜色掩码影响最终哪些通道被写入但不影响测试结果总结来说剔除方式决定模型正反面是否能被渲染深度缓冲方式和深度测试方式 决定了景深关系的确定以及透明效果的正确表达混合方式 决定了透明半透明颜色的正确表现以及一些特殊颜色效果的表现3渲染通道渲染通道Pass是子着色器中的核心执行单元每个通道定义了一次完整的渲染绘制过程。一个子着色器可以包含多个通道用于实现多遍渲染效果。基本结构Pass { Name PassName // 通道名称可选 Tags { ... } // 通道专用标签 Cull Back // 渲染状态 ZTest LEqual ZWrite On Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM // 开始CG/HLSL代码 #pragma vertex vert #pragma fragment frag // 着色器代码... ENDCG }通道标签Tags通道标签用于控制通道的渲染顺序、光照模式等行为subshasder中渲染标签与渲染通道标签是两个不同的东西渲染通道标签有自己的标签属性subshader的标签不能再pass中使用常见标签包括LightMode指定光照模式如 ForwardBase前向渲染基础通道、ForwardAdd前向渲染附加光照、ShadowCaster阴影投射等。RequireOptions指定通道所需的渲染选项。PassFlags通道标志如 OnlyDirectional仅定向光。通道渲染状态每个通道可以独立设置渲染状态如剔除、深度测试、混合等这些状态会覆盖子着色器级别的设置。状态设置方式与子着色器中的渲染状态相同。主要作用多遍渲染一个物体可以渲染多次每遍使用不同的着色器逻辑如先绘制漫反射再叠加高光特殊效果实现描边、阴影、反射等需要多次绘制的效果性能优化通过多通道实现LOD细节层次或平台适配常见通道类型常规通道Regular Pass执行一次完整的顶点-片段着色器计算阴影投射通道ShadowCaster Pass专门用于生成阴影贴图前向渲染通道ForwardBase/ForwardAdd前向渲染中的基础光照和附加光照通道延迟渲染通道Deferred Pass用于延迟渲染管线抓取通道GrabPass特殊通道用于抓取屏幕内容到纹理GrabPass GrabPass 是一个特殊的渲染通道用于抓取当前屏幕内容到一张纹理中常用于实现折射、扭曲等屏幕后处理效果。基本语法GrabPass { // 可选指定纹理名称 _GrabTexture }使用方式无名 GrabPass抓取的屏幕内容会自动存储到名为 _GrabTexture 的纹理中可在后续通道中采样使用。命名 GrabPass通过指定纹理名称如 _ScreenTex可以更精确地控制抓取纹理的命名和使用。注意事项GrabPass 会带来性能开销因为它需要将当前帧缓冲区内容复制到纹理。通常用于透明物体或需要基于屏幕内容计算的效果。在后续通道中可以通过sampler2D _GrabTexture;声明并采样抓取的纹理。通道执行顺序通道按定义顺序从上到下执行每个通道都会重新设置渲染状态除非使用UsePass复用后一个通道的绘制结果会与前一个通道的结果混合取决于混合设置通道复用UsePass ShaderName/PASSNAME // 复用其他着色器的指定通道通过UsePass可以避免重复编写相同代码提高着色器复用性。shader路径要写大写4、备用着色器当当前设备对上面所定义的subshader都无法执行实现时FallBack作为程序的“救命稻草”确保低端设备也能够被渲染语法结构为Fallback 低级shader路径或者程序自带的低级shader名字四、总结概要通过本文的学习我们对 Unity Shader 和 ShaderLab 有了系统的认识Unity Shader 与材质的关系Shader 是渲染的“图纸”定义了材质可调节的参数和渲染算法材质则是“实物”存储具体的参数值。两者结合才能完成最终的渲染效果。ShaderLab 的基本结构一个完整的 ShaderLab 文件由名称、属性Properties、子着色器SubShader和备用着色器Fallback四部分组成为跨平台渲染提供了统一的配置界面。属性系统支持数值、颜色/向量、纹理贴图三大类属性通过 Properties 块定义后在材质面板中暴露供美术或程序调节。子着色器的三大核心渲染标签Tags控制渲染时机和分类如 Queue渲染队列、RenderType渲染类型等。渲染状态Render States包括剔除Cull、深度测试ZTest、深度写入ZWrite、模板测试Stencil、颜色掩码ColorMask和混合Blend共同决定像素的可见性、测试规则和颜色混合方式。渲染通道Pass子着色器的执行单元可包含多个通道实现多遍渲染。每个通道可独立设置标签和状态支持常规通道、阴影投射、前向/延迟渲染通道以及特殊的 GrabPass用于抓取屏幕内容。备用着色器Fallback当主 SubShader 无法在当前设备运行时提供降级方案确保基础渲染效果。核心要点回顾渲染管线控制通过标签、状态和通道的灵活组合可以精确控制物体在渲染管线中的行为。性能与效果平衡深度测试/写入、模板测试等状态直接影响渲染性能和正确性需根据物体特性不透明/透明、是否需要特殊效果合理配置。多遍渲染与复用利用多个 Pass 可实现复杂效果如描边、折射而 UsePass 则能提高代码复用率。