You can determine in which order your objects are drawn using the Queue tag. A Shader decides which render queue its objects belong to, this way any Transparent shaders make sure they are drawn after all opaque objects and so on.
There are four pre-defined render queues, but there can be more queues in between the predefined ones. The predefined queues are:
Background
- this render queue is rendered before any others. You’d typically use this for things that really need to be in the background.Geometry
(default) - this is used for most objects. Opaque geometry uses this queue.AlphaTest
- alpha tested geometry uses this queue. It’s a separate queue from Geometry
one since it’s more efficient to render alpha-tested objects after all solid ones are drawn.Transparent
- this render queue is rendered after Geometry and AlphaTest
, in back-to-front order. Anything alpha-blended (i.e. shaders that don’t write to depth buffer) should go here (glass, particle effects).Overlay
- this render queue is meant for overlay effects. Anything rendered last should go here (e.g. lens flares).Shader "Transparent Queue Example"
{
SubShader
{
Tags { "Queue" = "Transparent" }
Pass
{
// rest of the shader body...
}
}
}
An example illustrating how to render something in the transparent queue
For special uses in-between queues can be used. Internally each queue is represented by integer index; Background
is 1000, Geometry
is 2000, AlphaTest
is 2450, Transparent
is 3000 and Overlay
is 4000. If a shader uses a queue like this:
Tags { "Queue" = "Geometry+1" }
This will make the object be rendered after all opaque objects, but before transparent objects, as render queue index will be 2001 (geometry plus one). This is useful in situations where you want some objects be always drawn between other sets of objects. For example, in most cases transparent water should be drawn after opaque objects but before transparent objects.
Queues up to 2500 (“Geometry+500”) are consided “opaque” and optimize the drawing order of the objects for best performance. Higher rendering queues are considered for “transparent objects” and sort objects by distance, starting rendering from the furthest ones and ending with the closest ones. Skyboxes are drawn in between all opaque and all transparent objects.
理解:
由于之前看了鬼火引擎,其中就是对物体进行分类,分别将不透明物体,透明物体分别放入了不同的队列之中,然后先渲染不透明物体的队列,然后渲染透明物体,其中透明物体根据距离摄像机远近进行排序,从后往前渲染。
Unity我估计也是这样做的,根据shader中队列设置的不同,解析shader脚本内容后,将不同的物体放入相应的队列之中。
测试:
我们下面做以个小测试,这个测试也是项目中美术提出来要做的一个效果,就是弄一个透明的面片,可以遮住其它物体,当遮住一个人的时候,我们移动这个透明面片,就可以产生一种效果,让人从头部向脚部逐渐刷出来的感觉。
一开始我是这样写的:
Shader "LH/AlphaBlend"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags
{
"RenderType" = "Transparent"
"Queue" = "Transparent"
}
LOD 100
ZWrite On
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
return fixed4(0.0f, 0.0f, 0.0f, 0.0f);
}
ENDCG
}
}
}
就是很简单的alphablend效果,不过是要写入深度的,我想这样就可以既是透明,又可以通过深度来遮住后面的物体,但是运行效果如下:
我在面片的前面放了一个透明的cube,使用了上面的shader,但是可以看见并没有遮住这个面片。为什么呢? 我来一想,可以看到"Queue" = "Transparent" 为透明队列,由于面片使用的stander shader队列应该是geometry , 所以它会优先于Transparent队列渲染,然后轮到我们cube渲染的时候,这个面片已经被渲染到了颜色缓冲区中,又由于cube是透明的,所以没有遮挡住。
然后我修改了"Queue" = "Geometry"后,再次渲染,如下图:
遮挡住了,所以可以猜想到,当Queue都为Geometry的物体进行渲染时,应该是根据距离摄像机的远近,从近往远进行了渲染,所以我们成功遮住了物体。 这样做的目的是为了避免OverDraw,可以看unity的渲染流程如下:
在Vertex Shader之后就进行了Depth Test, 这叫做Early Depth Test, 这样可以在像素着色器之前就剔除掉一部分物体,避免overdraw