在渲染模型中控制透明通道。透明度为1,完全不透明;透明度为0,完全不会显示。
两种方法:
(1)透明度测试
(2)透明度混合
深度缓冲(z-buffer)用于解决可见性问题。可以决定哪个物体的哪些部分被渲染到前面,哪些部分会被其他物体遮掩。根据深度缓存中的值来判断该片元距离摄像机的距离,当渲染一个片元时,需要把它的深度值和已经存在于深度缓冲中的值进行比较,如果它的值距离摄像机更远,那么说明这个片元不应被渲染到屏幕上;否则,这个片元应该覆盖掉此时颜色缓冲中的像素值,并把它的深度值更新到深度缓冲中(如果开启了深度写入)。可以不关心物体渲染顺序。
基本原理
(1)透明度测试
只要一个片元的透明度不满足条件,那么它对应的片元就会被舍弃。被舍弃的片元不会再进行任何处理,也不会对颜色缓冲产生任何影响;否则,就会按照普通的不透明物体来处理,即深度测试、深度写入。透明度测试不需要关闭深度写入,它会根据透明度来舍弃一些片元,效果极端,要么完全透明,要么完全不透明。
(2)透明度混合
可以得到真正的半透明效果。它会使用当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色。透明度混合需要关闭深度写入,要小心物体的渲染顺序。透明度混合只关闭了深度写入,没有关闭深度测试。当使用透明度混合渲染一个片元时,还是会比较它的深度值和当前深度缓冲中的深度值。如果它的深度值距离摄像机更远,那么就不会再进行混合操作。当一个不透明物体出现在一个透明物体前面,而我们先渲染了不透明物体,它仍然可以正常地遮挡住透明物体。对于透明度混合来说,深度缓冲是只读的。
为什么渲染顺序很重要
应该在不透明物体渲染完之后再渲染半透明物体。半透明物体之间也要符合渲染顺序。
渲染引擎一般都会对物体先排序再渲染,常用方法是
(1)先渲染所有不透明物体,并开启它们的深度测试和深度写入
(2)把半透明按它们距离摄像机的远近进行排序,然后按照从后往前的顺序渲染这些半透明物体,并开启它们的深度测试,但关闭深度写入。
为了减少错误排序,我们尽可能让模型是凸面体,并考虑将复杂模型拆分成可以独立排序的多个子模型。
Unity Shader的渲染顺序
Unity提供了渲染队列来解决渲染顺序问题。可以使用SubShader的Queue标签来决定我们的模型将归于哪个渲染队列。Unity在内部使用一系列整数索引来表示每个渲染队列,且索引号越小越早被渲染。
透明度测试
透明度测试:只要一个片元的透明度不满足条件,那么它对应的片元就会被舍弃。被舍弃的片元将不会再进行任何处理,也不会对颜色缓冲产生任何影响;否则,就会按照普通的不透明方式去处理。
通常,在片元着色器中使用clip函数进行透明度测试。clip是一个Cg函数
函数:void clip(float4 x); void clip(float3 x); void clip(float2 x); void clip(float1 x); void clip(float x);
参数:裁剪时使用的标量或矢量条件
描述:如果给定参数的任何一个分量是负数,就会舍弃当前像素的颜色。它等同于下面的代码
void clip(float4 x)
{if (any(x < 0))discard;
}
Shader "Unity Shaders Book/Chapter 8/Alpha Test"{Properties {_Color ("Main Tint", Color) = (1, 1, 1, 1)_MainTex ("Main Tex", 2D) = "white"{}//_Cutoff用于决定我们调用clip进行透明度测试时使用的判断条件。范围是[0,1]_Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5}SubShader{//透明度测试使用的渲染队列是AlphaTest//把IgnoreProjector设为True,不受投影器的影响//RenderType可以让Unity把Shader归入提前定义的组TransparentCutout//指明该Shader是一个使用了透明度测试的Shader,RenderType通常被用于着色器的替换功能//使用了透明度测试的Shader都应该设置这三个标签Tags{ "Queue"="AlphaTest""IgnoreProjector"="True""RenderType"="TransparentCutout"}Pass{Tags{"LightMode"="ForwardBase"}CGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"fixed4 _Color;sampler2D _MainTex; float4 _MainTex_ST;fixed _Cutoff;struct a2v{float4 vertex : POSITION;float3 normal : NORMAL;float4 texcoord : TEXCOORD0;};struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCO