每一个Shader至少包含一个SubShader
SubShader中包含最终渲染效果的代码,决定最终渲染效果 1. 渲染标签
决定什么时候渲染以及如何对物体进行渲染 2. 渲染状态
决定渲染时候的剔除方式、深度测试方式、混合方式等内容 3. 渲染通道
具体实现着色器代码的地方
1 2 3 4 5 6 7 8 9 SubShader { Tags{“标签名1 ”=“标签值1 ”,“标签名2 ” = “标签值2 ”} Pass { 第一个渲染通道 } 每一个Pass都会让物体执行一次渲染 }
渲染标签
语法结构
1 Tags{“标签名1 ”=“标签值1 ”,“标签名2 ” = “标签值2 ”}
## 渲染队列 > [!INFO] > 确定物体的渲染顺序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 主要作用: 确定物体的渲染顺序 Tags{ "Queue" = "标签值" } 常用Unity预先定义好的渲染队列标签值: 1.B ackground(背景)(队列号: 1000 ) 最早被渲染的物体的队列,一般用来渲染天空盒或者背景 Tags{ "Queue" = "Background" } 2. Geometry(几何)(队列号: 2000 ) 不透明的几何体通常使用该队列,当没有声明渲染队列时,Unity会默认使用这个队列 Tags{ "Queue" = "Geometry" } 3. AlphaTest(透明测试)(队列号: 2450 ) 有透明通道的,需要进行Alpha测试的几何体会使用该队列 当所有Geometry队列实体绘制完后再绘制AlphaTest队列,效率更高 Tags{ "Queue" = "AlphaTest" } 4. Transparent(透明的)(队列号: 3000 ) 该队列中几何体按照由远到近的顺序进行绘制,半透明物体的渲染队列,所有进行透明混合的几何体都应该使用该队列 比如:玻璃材质,粒子特效等 Tags{ "Queue" = "Transparent" } 5. Overlay(覆盖)(队列号: 4000 ) 用是放在最后渲染的队列,于叠加渲染的效果,比如镜头光晕等 Tags{ "Queue" = "Overlay" } 6. 自定义队列 基于Unity预先定义好的这些渲染队列标签来进行加减运算来定义自己的渲染队列 比如: Tags{ "Queue" = "Geometry+1" } 代表的队列号就是 2001 Tags{ "Queue" = "Transparent-1" } 代表的队列号就是 2999 自定义队列在一些特殊情况下,特别有用 比如 一些水的渲染 想要在不透明物体之后,半透明物体之前进行渲染,就可以自定义 注意:自定义队列只能基于预先定义好的各类型进行计算,不能在Shader中直接赋值数字 如果实在想要直接赋值数字,可以在材质面板中进行设置
## 渲染类型
[!INFO] >主要作用 对着色器进行分类,之后可以用于着色器替换功能
摄像机上有对应的API,可以指定这个渲染类型来替换成别的着色器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Tags{ "RenderType" = "标签值" } 常用Unity预先定义好的渲染类型标签值: 1. Opaque(不透明的) 用于普通Shader,比如:不透明、自发光、反射等 2. Transparent(透明的) 用于半透明Shader,比如:透明、粒子 3. TransparentCutout(透明切割) 用于透明测试Shader,比如:植物叶子 4.B ackground(背景) 用于天空盒Shader 5. Overlay(覆盖) 用于GUI纹理、Halo(光环)、Flare(光晕) 了解即可 6. TreeOpaque 用于地形系统中的树干 7. TreeTransparentCutout 用于地形系统中的树叶 8. TreeBillboard 用于地形系统中的Billboarded树 9. Grass 用于地形系统中的草 10. GrassBillboard 用于地形系统中的Billboarded草
禁用批处理
主要作用:
当使用批处理时,模型会被变换到世界空间中,模型空间会被丢弃
这可能会导致某些使用模型空间顶点数据的Shader最终无法实现想要的结果
可以通过开启禁用批处理来解决该问题
总是禁用批处理
Tags{ "DisableBatching" = "True" }
不禁用批处理(默认值)
Tags{ "DisableBatching" = "False" }
了解即可
LOD效果激活时才会禁用批处理,主要用于地形系统上的树
Tags{ "DisableBatching" = "LODFading" }
禁用阴影投影
主要作用:
控制该SubShader的物体是否会投射阴影
不投射阴影
Tags{ "ForceNoShadowCasting" = "True" }
投射阴影(默认值)
Tags{ "ForceNoShadowCasting" = "False" }
忽略投影机
主要作用:
物体是否受到Projector(投影机)的投射
Projector是Unity中的一个功能(以后讲解)
忽略Projector(一般半透明Shader需要开启该标签)
Tags{ "IgnoreProjector" = "True" }
不忽略Projector(默认值)
Tags{ "IgnoreProjector" = "False" }
其他标签
1.是否用于精灵
想要将该SubShader用于Sprite时,将该标签设置为False
Tags{ "CanUseSpriteAtlas" = "False" }
2.预览类型
材质在预览窗口默认为球形,如果想要改变为平面或天空盒
只需要改变预览标签即可
平面
Tags{ "PreviewType" = "Panel" }
天空盒
Tags{ "PreviewType" = "SkyBox" }
[!WARNING] > 以上这些标签只能在SubShader语句块中声明
之后讲解的Pass渲染通道语句块中也可以声明渲染标签
但是今天讲解的内容都不能在Pass中声明
Pass中有自己专门的标签类型,我们会在之后讲解
渲染状态
语法结构
1 2 渲染状态 状态类型 若有多个渲染状态,可以用空行隔开
剔除方式
1 2 3 4 5 6 Cull Back 背面剔除 Cull Front 正面剔除 Cull Off 不剔除 不设置的话,默认为背面剔除 一般情况下,我们需要两面渲染时,会设置为不剔除
深度缓存
[!TIP] > 保证互相遮挡的物体公共区域优先渲染挡在前面的片元
![[Pasted image 20250209230433.png]]
如果没有开启深度写入,则只要通过深度测试一定会被渲染
每一个屏幕上的像素点都有一个内存区域记录深度信息 1 2 3 4 5 6 7 8 9 10 11 主要作用: 是否写入深度缓冲 深度缓冲(Depth Buffer): 深度缓冲是一个与屏幕像素对应的缓冲区,用于存储每个像素的深度值(距离相机的距离)。 在渲染场景之前,深度缓冲被初始化为最大深度值,表示所有像素都在相机之外。 最后留在深度缓冲中的信息会被渲染 ZWrite On 写入深度缓冲 ZWrite Off 不写入深度缓冲 不设置的话,默认为写入 一般情况下,我们在做透明等特殊效果时,会设置为不写入
##
深度测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 主要作用: 设置深度测试的对比方式 深度测试的主要目的是确保在渲染时,像素按照正确的深度(距离相机的距离)顺序进行绘制, 从而创建正确的遮挡关系和透视效果 在渲染场景之前,深度缓冲被初始化为最大深度值,表示所有像素都在相机之外。 在渲染过程中,对于每个像素,深度测试会将当前像素的深度值与深度缓冲中对应位置的值进行比较。 一般情况下 1. 如果当前像素的深度值小于深度缓冲中的值,说明当前像素在其他物体之前,它会被绘制,并更新深度缓冲。2. 如果当前像素的深度值大于等于深度缓冲中的值,说明当前像素在其他物体之后,它会被丢弃,不会被绘制,并保持深度缓冲不变。ZTest Less 小于当前深度缓冲中的值,就通过测试,写入到深度缓冲中 ZTest Greater 大于当前深度缓冲中的值,就通过测试,写入到深度缓冲中 ZTest LEqual 小于等于当前深度缓冲中的值,就通过测试,写入到深度缓冲中 ZTest GEqual 大于等于当前深度缓冲中的值,就通过测试,写入到深度缓冲中 ZTest Equal 等于当前深度缓冲中的值,就通过测试,写入到深度缓冲中 ZTest NotEqual 不等于当前深度缓冲中的值,就通过测试,写入到深度缓冲中 ZTest Always 始终通过深度测试写入深度缓冲中 不设置的话,默认为LEqual 小于等于 一般情况下,我们只有在实现一些特殊效果时才会区修改深度测试方式,比如透明物体渲染会修改为Less,描边效果会修改为Greater等
混合方式
在深度测试之后进行
![[混合流程图.png]] 1 2 3 4 5 6 7 8 9 10 11 12 主要作用: 设置渲染图像的混合方式(多种颜色叠加混合,比如透明、半透明效果和遮挡的物体进行颜色混合) Blend One One 线性减淡 Blend SrcAlpha OneMinusSrcAlpha 正常透明混合 Blend OneMinusDstColor One 滤色 Blend DstColor Zero 正片叠底 Blend DstColor SrcColor X光片效果 Blend One OneMinusSrcAlpha 透明度混合 等等 不设置的话,默认不会进行混合 一般情况下,我们需要多种颜色叠加渲染时,就需要设置混合方式,具体情况具体处理
其他渲染状态
1 2 3 4 5 1.L OD 控制LOD级别,在不同距离下使用不同的渲染方式处理2. ColorMask 设置颜色通道的写入蒙版,默认蒙版为RGBA等等 我们目前主要掌握剔除方式、深度缓冲、深度测试、混合方式即可
渲染状态的注意事项
[!NOTE]
>以上这些状态不仅可以在SubShader语句块中声明之后讲解的Pass渲染通道语句块中也可以声明这些渲染状态,如果在SubShader语句块中使用会影响之后的所有渲染通道Pass,如果在Pass语句块中使用只会影响当前Pass渲染通道,不会影响其他的Pass
总结
1 2 3 4 5 6 7 8 9 渲染状态对于我们来说很重要 它可以影响最终我们看到的渲染效果 其中 剔除方式决定了 模型正面背面是否能够被渲染 深度缓冲和深度测试 决定了景深关系的确定以及透明效果的正确表达等 混合方式 决定了透明半透明颜色的正确表现,以及一些特殊颜色效果的表现 这些内容,大家可以将其记入自己的笔记当中 之后在使用他们时,翻看笔记进行复习
渲染通道
渲染通道的语法结构
1 2 3 4 5 6 Pass{ 1. Name 名称 2. 渲染标签 3. 渲染状态 4. 其他着色器代码 }
渲染通道的名字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 主要作用: 我们对Pass命名的主要目的 可以利用UsePass命令在其他Shader当中复用该Pass的代码, 只需要在其他Shader当中使用 UsePass "Shader路径/Pass名" 注意: Unity内部会把Pass名称转换为大写字母 因此在使用UsePass命令时必须使用大写形式的名字 Pass{ Name MyPass } 在其他Shader中复用该Pass代码时 UsePass "TeachShader/Lesson4/MYPASS"
渲染通道中的渲染标签
1 2 3 4 Pass中的渲染标签语法和SubShader中相同 Tags{ "标签名1" = "标签值1" "标签名2" = "标签值2" "标签名2" = "标签值2" .......} 但是我们之前讲解过的SubShader语句块中的渲染标签不能够在Pass中使用 Pass当中有自己专门的渲染标签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 主要作用: 指定了该Pass应该在哪个阶段执行 可以将着色器代码分配给适当的渲染阶段,以实现所需的效果 1 - 1. Always 始终渲染;不应用光照 1 - 2.F orwardBase 在前向渲染中使用;应用环境光、主方向光、顶点 / SH 光源和光照贴图 1 - 3.F orwardAdd 在前向渲染中使用;应用附加的每像素光源(每个光源有一个通道) 1 - 4. Deferred 在延迟渲染中使用;渲染 G 缓冲区 1 - 5. ShadowCaster 将对象深度渲染到阴影贴图或深度纹理中 1 - 6. MotionVectors 用于计算每对象运动矢量 1 - 7. PrepassBase 在旧版延迟光照中使用;渲染法线和镜面反射指数 1 - 8. PrepassFinal 在旧版延迟光照中使用;通过组合纹理、光照和反光来渲染最终颜色 1 - 9. Vertex 当对象不进行光照贴图时在旧版顶点光照渲染中使用;应用所有顶点光源 1 - 10. VertexLMRGBM 当对象不进行光照贴图时在旧版顶点光照渲染中使用;在光照贴图为 RGBM 编码的平台上(PC 和游戏主机) 1 - 11. VertexLM 当对象不进行光照贴图时在旧版顶点光照渲染中使用;在光照贴图为双 LDR 编码的平台上(移动平台) 关于向前渲染、延迟渲染、旧版光照等概念了解 https:
1 2 3 4 5 6 主要作用: 用于指定当满足某些条件时才渲染该Pass 目前Unity仅支持 Tags{ "RequireOptions" = "SoftVegetation" } 仅当Quality窗口中开启了SoftVegetation时才渲染此通道
1 2 3 4 5 6 7 主要作用: 一个渲染通道Pass可指示一些标志来更改渲染管线向Pass传递数据的方式 目前Unity仅支持 Tags{ "PassFlags" = "OnlyDirectional" } 在 ForwardBase 向前渲染的通道类型中使用时,此标志的作用是仅允许主方向光和环境光 / 光照探针数据传递到着色器 这意味着非重要光源的数据将不会传递到顶点光源或球谐函数着色器变量
Pass中的渲染状态
我们上节课在SubShader语句块中学习的渲染状态同样适用于Pass
比如
剔除方式决定了 模型正面背面是否能够被渲染
深度缓冲和深度测试 决定了景深关系的确定以及透明效果的正确表达等
混合方式 决定了透明半透明颜色的正确表现,以及一些特殊颜色效果的表现
这些渲染状态都可以在单个Pass中进行设置
需要注意的是
如果在SubShader语句块中使用会影响之后的所有渲染通道Pass
如果在Pass语句块中使用只会影响当前Pass渲染通道,不会影响其他的Pass
不仅如此,Pass中还可以使用固定管线着色器的命令
其他着色器代码
1 2 3 其他代码部分就是实现着色器的核心代码部分 我们可能会用到CG或HLSL等着色器语言来进行逻辑书写 我们之后会详细讲解
GrabPass命令
1 2 3 4 5 6 7 8 9 10 11 我们可以利用GrabPass命令把即将绘制对象时的屏幕内容抓取到纹理中 在后续通道中即可使用此纹理,从而执行基于图像的高级效果。 举例: 将绘制该对象之前的屏幕抓取到 _BackgroundTexture 中 GrabPass { "_BackgroundTexture" } 注意: 该命令一般写在某个Pass前,在之后的Pass代码中可以利用_BackgroundTexture变量进行处理
总结
1 2 3 4 5 6 7 Pass渲染通道语句块中 主要包含了 1. 名字:可以帮助我们复用Pass代码2. 渲染标签:不能使用SubShader中的渲染标签,有自己独有的渲染标签3. 渲染状态:SubShader当中的渲染状态同样可以在Pass中使用,影响的区域不同4. 着色器语言逻辑:我们之后会详细学习的部分四个部分