渲染状态

CGPROGRAM 前面可以放许多关键字,还没系统总结下,顺便写写笔记。

面剔除

shaderLab语句 说明
Cull Off 不剔除
Cull Back(默认) 剔除背面(内表面),即背对着摄像机的图元不会被渲染
Cull Front 剔除正面(外表面),即朝向摄像机的渲染图元不会被渲染

当一个mesh组件的信息被传递后,我们可以通过代码决定哪些部分渲染(render)出来,而哪些部分不要,这个过程就像把那些不要的部分剔除了,我们看不到他,虽然他的mesh信息还在,但是我们的GPU不会去处理它,肯定比剔除前GPU的性能消耗要低。
这个过程就好比我们的mesh组件是一个透明的膜,我们假设这个胶纸我们根本看不到,而片段着色器在着色的时候像毛笔选择性地上色,最后的效果是我们可能看到膜的一部分是可见的,但是不见的地方,膜还是存在的,只是我们没有给他上色,我们既看不看他们,也不需要再他们上面画宝贵的墨水(GPU并行处理能力)

举个例子,入门精要的 8_7_1 里面场景:

1
Cull Off

Cull Off

1
Cull Back //(默认就是这个,相当于把上面的 Cull Off 注释掉)

Cull Off

通过两张图片的对比,你可以明白什么是正对着摄像机,什么是背对着摄像机了,第二张图片少的部分就是背对着摄像机了。

最后再来个对比看下

1
Cull Front

Cull Off

Render Queue

最常见的 Render Queue 如下:

名称 队列索引号 描述
Background 1000 这个渲染队列会在任何其他队列之前被渲染,我们通常使用该队列来渲染那些需要绘制在背景上的物体
Geometry 2000 默认的渲染队列,大多数物体都是用这个队列,不透明物体使用这个队列。
AlphaTest 2450 需要透明度测试的物体都使用这个队列。
Transparent 3000 这个队列中的物体会在所有 Geometry 和 AlphaTest 物体渲染后,再按照从后往前的顺序进行渲染。任何使用了透明度混合(例如关闭了深度写入的 Shader)的物体都应该使用该队列。
Overlay 4000 该队列用于实现一些叠加效果。任何需要在最后渲染的物体都应该使用该队列。

最后一个 Overlay 我在 Unity 文档里面也找到了,不过在 Material 的设置里面没有出来,即使在 Shader 中写了如下的设置也不会显示,而是显示 FromShader = 4000。不知道有没有大佬知道怎么回事儿。

1
"Queue" = "Overlay"

最后总结一下使用 Render Queue 的作用:

  • 排序渲染顺序:Render Queue 决定了不同对象在场景中渲染的先后顺序。具有较低的 Render Queue 值的对象会在具有较高值的对象之前被渲染。

  • 解决透明度问题:透明对象通常需要在不透明对象之后渲染,以确保正确的视觉效果。通过设置 Render Queue 值,可以控制透明对象的绘制顺序,避免出现深度排序问题。

  • 分组渲染:Render Queue 允许开发者将对象分组,以便在渲染时使用相同的材质或 Shader,优化性能。

  • 自定义渲染流程:通过自定义 Render Queue 值,开发者可以实现特定的渲染效果,例如在某些情况下需要特殊处理的对象(如后处理效果)。

Blend

Blend 会使当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色。注意,Blend 需要开启深度写入关闭。

语义 描述
Blend Off 关闭混合
Blend SrcFactor DstFactor 开启混合并设置混合因子。源颜色(该片元产生的颜色)会乘以 SrcFactor,而目标颜色(已经存在于颜色缓存的颜色)会乘以 Dstfactor,然后把两者相加再存入颜色缓存中。
Blend SrcFactor DstFactor
SrcFatorA DstFactor A
和上面一样,只是使用不同的混合因子来混合透明通道。
BlendOp BlendOperation 并非是把源颜色和目标颜色简单相加后混合,而是使用 BlendOperation 对它们进行其他操作。

第二种混合模式根据不同的混合因子有多种表达方式,下面列举一下混合因子。

因子 描述
Zero 0
One 1
SrcColor 源颜色
OneMinusSrcColor 1 - 源颜色
DstColor 目标颜色
OneMinusDstColor 1 - 目标颜色
SrcAlpha 源颜色的 Alpha 值
OneMinusSrcAlpha 1 - 源颜色的 Alpha 值
DstAlpha 目标颜色Alpha 值
OneMinusDstAlpha 1 - 目标颜色Alpha 值

看到这里可能有点懵逼了,举个例子讲解一下,下面这张图是入门精要里面 8-4 的图,重要混合代码也在下面。
8-4

1
2
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha

那么这里的意思就是:

  • 深度写入关闭
  • 源颜色乘以该片元的 Alpha,目标颜色(已经存在于颜色缓存的颜色)会乘以(1-源颜色的 Alpha 值),然后相加。

最后得到了上图的不透明渲染的 Cube,也是最常见的透明度混合因子。

第三种常见的混合操作如下:

操作 描述
Add 将混合后的源颜色和目的颜色相加。默认的混合操作。使用的混合等式是:
$O_{r g b}=\text { SrcFactor } \times S_{r g b}+\text { DstFactor } \times D_{r g b}$
$O_{a}=\operatorname{SrcFactor} A \times S_{a}+\text { DstFactor } A \times D_{a}$
Sub 用混合后的源颜色减去混合后的目的颜色。使用的混合等式是:
$O_{r g b}=\text { SrcFactor } \times S_{r g b}-\text { DstFactor } \times D_{r g b}$
$O_{a}=\text { SrcFactor } A \times S_{a}-\text { DstFactor } A \times D_{a}$
RevSub 用混合后的目的颜色减去混合后的源颜色。使用的混合等式是:
$O_{r g b}=\text { DstFactor } \times D_{r g b}-\text { SrcFactor } \times S_{r g b}$
$O_{a}=\text { DstFactor } A \times D_{a}-\text { SrcFactor } A \times S_{a}$
Min 使用源颜色和目的颜色中较小的值比较,是逐分量比较多。使用的混合等式是:
$O_{r g b a}=\left(\min \left(S_{r}, D_{r}\right), \min \left(S_{g}, D_{g}\right), \min \left(S_{b}, D_{b}\right), \min \left(S_{a}, D_{a}\right)\right)$
Max 使用源颜色和目的颜色中较大的值比较,是逐分量比较多。使用的混合等式是:
$O_{r g b a}=\left(\max \left(S_{r}, D_{r}\right), \max \left(S_{g}, D_{g}\right), \max \left(S_{b}, D_{b}\right), \max \left(S_{a}, D_{a}\right)\right)$

ZWrite 和 ZTest

ZWrite可以取的值为:On/Off,默认值为On,代表是否要将像素的深度写入深度缓存中(同时还要看ZTest是否通过)。
ZTest可以取的值为:Greater/GEqual/Less/LEqual/Equal/NotEqual/Always/Never/Off,默认值为LEqual,代表通过比较深度来更改颜色缓存的值。

结论:

  • 当ZWrite为On时,ZTest通过时,该像素的深度才能成功写入深度缓存,同时因为ZTest通过了,该像素的颜色值也会写入颜色缓存。

  • 当ZWrite为On时,ZTest不通过时,该像素的深度不能成功写入深度缓存,同时因为ZTest不通过,该像素的颜色值不会写入颜色缓存。

  • 当ZWrite为Off时,ZTest通过时,该像素的深度不能成功写入深度缓存,同时因为ZTest通过了,该像素的颜色值会写入颜色缓存。

  • 当ZWrite为Off时,ZTest不通过时,该像素的深度不能成功写入深度缓存,同时因为ZTest不通过,该像素的颜色值不会写入颜色缓存。

因为ZWrite默认值为On,ZTest默认值为LEqual,所以这很好地解释了为什么在unity中,距离相机近的东西会阻挡住距离相机远的东西。

获取深度值可以用 Unity 自带的方式,不过 DC 会翻倍就是了,了解到有大佬写了自定义深度图的方法,不会翻倍 DC,虽然有所限制,但是感觉可以一试。

暂时搁置,等有空来回来补档。

ColorMask

设置颜色掩码,允许或禁止写入特定的颜色通道,例如 ColorMask 0 禁止写入所有颜色通道。

1
ColorMask RGB //表示写入 RGB 通道,A 通道不写入。

AlphaToMask

Enables or disables alpha-to-coverage mode on the GPU.

Alpha-to-coverage mode can reduce the excessive aliasing that occurs when you use multisample anti-aliasing (MSAA) with shaders
that use alpha testing, such as vegetation shaders. To do this, it modifies the multisample coverage mask proportionally to the alpha value in the output of the fragment shader result.

This command is intended for use with MSAA. If you enable alpha-to-coverage mode when you are not using MSAA, the results can be unpredictable; different graphics APIs and GPUs handle this differently.

启用或禁用 GPU 上的 alpha-to-coverage 模式。

Alpha-to-coverage 模式可以减少将多样本抗锯齿 (MSAA) 与使用 Alpha 测试的着色器(如植被着色器)一起使用时出现的过度锯齿。为此,它根据片元着色器结果输出中的 Alpha 值按比例修改多样本覆盖率遮罩。

此命令旨在与 MSAA 一起使用。如果在不使用 MSAA 时启用 alpha-to-coverage 模式,结果无法预测;不同的图形 API 和 GPU 对此有不同的处理方式

Offset

Offset 用于控制深度偏移,它影响的是物体的深度值,这在处理一些特殊情况下非常有用,比如解决深度冲突和增强渲染效果。

作用
深度偏移: Offset 可以调整物体的深度值,在 Z 测试中创建一个额外的深度偏移。这在某些情况下有助于避免物体间的深度冲突。

解决表面渲染问题: 在一些透明或重叠的表面渲染时,深度冲突可能导致视觉 artifacts(例如,表面穿透或渲染错误),通过 Offset 可以在渲染时调整物体的深度,使其更加明显或不被错误渲染。

使用方法
在 Shader 中使用 Offset 时,可以在 Pass 中添加以下代码:

1
2
3
Offset <factor>, <units>
factor: 控制偏移的程度,通常为一个整数,值越大,偏移越明显。
units: 控制相对于当前物体的深度偏移,通常也为整数

注意事项
使用场景: Offset 通常在处理阴影、透明物体、重叠表面时非常有用。
性能影响: 过度使用深度偏移可能会影响性能,建议谨慎使用。

Stencil

用于设置模板测试和模板操作,包含 Stencil Ref、Stencil Comp 和 Stencil Pass 等。

参考链接