写在前面
最近要实现一个透明的特效,所以更仔细的去学了一下。但是网上更多的是用文字讲解,实验做的相对较少,因此我在这里会更多的附上实验效果展示和结论。若有理解错误的地方,欢迎讨论。
实验场景
摄像头看向两个Cube,红Cube在前,蓝Cube在后
实验1:红(不透明)+蓝(不透明)+默认渲染顺序(先渲染红Cube)
效果:
解析: 红蓝Cube使用相同的Shader,只是颜色不一样。可以看到红色挡住了颜色。这很好理解。因为Unity对于不透明物体默认从离摄像机近的地方开始渲染。那红Cube会先进行深度测试,发现深度缓冲区里面是空的,所以将红Cube的深度写入深度缓冲区,并将自己的颜色Red写入颜色缓冲区。之后蓝Cube深度测试,发现自己的深度值比深度缓冲区里的蓝Cube值要大,所以没通过深度测试,所以不会将自己的深度值写入深度缓冲区中覆盖掉以前红Cube的深度缓冲区,也不将自己的颜色Blue写入颜色缓冲区。
结论:
1、Unity对于不透明物体默认渲染顺序是从离摄像机近的地方开始渲染。
2、通过深度测试,进行深度写入时,颜色写入颜色缓冲区也会同时进行。
Shader代码:
Shader "My/Blue"
{
Properties
{
_Color("Color", Color) = (0,0,1,1)
}
SubShader
{
Tags { "Queue"="Geometry" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
fixed4 _Color;
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(_Color.r,_Color.g,_Color.b,_Color.a);
}
ENDCG
}
}
}
实验2:红(不透明)+蓝(不透明+优先渲染)
效果:
解析:
把红色Cube的渲染队列值调到2001大于蓝色Cube的渲染队列值。从而使得蓝色Cube优先渲染。但是结果并没有发生改变。这是因为先渲染蓝色时,蓝色的深度值被写入深度缓冲区,再渲染红色时,红色深度值比红色小,因此写入深度缓冲区。
结论:
1、改变渲染队列值能改变Unity对物体的渲染顺序。
2、对于不透明物体来说,因为深度测试的存在,所以不用关心渲染顺序。
实验3:红(透明+关闭深度写入)+蓝(不透明)+默认渲染顺序(先渲染蓝Cube)
效果:
解析:
我们仅在红Cube的Shader中加入透明度混合代码、把红色Cube的渲染队列改为3000、关闭深度写入,并且把红Cube的透明度改为150。此时可以看到红色Cube呈现透明效果。原因也很简单。因为先渲染蓝色,所以当红色Cube进行深度测试通过时本应该把深度值写入深度缓冲区但是由于我们关闭了深度写入,所以深度值还是蓝色Cube的深度值。但是混合的颜色依然写入颜色缓冲区。
在本场景Blend SrcAlpha OneMinusSrcAlpha
表示红色红色透明度+蓝色(1-红色透明度)
//红CubeShaer加
Tags {"Queue"="Transparent" }
Blend SrcAlpha OneMinusSrcAlpha
结论:
1、关闭深度写入,只是代表如果深度测试通过时不会将深度值写入深度缓冲,但是颜色写入依然会进行。
实验4:红(透明+关闭深度写入+优先渲染)+蓝(不透明)
效果:
解析:
我们将蓝色Cube的渲染队列值调到3001大于红色的300。因此先渲染红色Cube,但是由于红色Cube关闭了深度写入,所以深度值不会写入深度缓冲区,所以深度缓冲区依然为空,但是颜色依然会写入颜色缓冲区。然后渲染蓝Cube时,发现深度缓冲区为空,这时就会误以为蓝Cube是第一个渲染的,所以将蓝Cube深度值写入深度缓冲区,颜色值写入颜色缓冲区,从而导致了蓝Cube在红Cube前的效果。
结论:
1、对于半透明物体来说,渲染顺序是相当重要的,不同的渲染顺序会出现不同的效果。
实验5:红(透明+开启深度写入)+蓝(不透明)+默认渲染顺序(先渲染蓝Cube)
效果:
解析:
将蓝Cube渲染队列值调回2000,使得蓝Cube优先渲染,但开启红Shader的深度写入。所以在渲染红Cube时,深度测试通过后会将红色Cube的深度值写入深度缓冲区,混合颜色会写入颜色缓冲区。
结论:
1、显示结果和实验3红色Cube关闭深度写入是一样的,有人会觉得,开不开启深度写入好像效果都一样,只是最终存到深度缓冲区里面的值不一样罢了,实验3中深度缓冲区离得值是蓝Cube得深度值,而实验5深度缓冲区里得值是红Cube的值。那为什么还要关闭红Shader的深度写入呢?这不多此一举吗?这是因为此时还没考虑当蓝色Cube也是透明的情况,请看实验6、7
实验5.5:红(透明+开启深度写入+优先渲染)+蓝(不透明)
效果:
解析: 调大蓝色的渲染队列值(3001)使其大于红色的渲染队列值(3000),让红色先渲染。红色深度值和颜色被写入。然后渲染蓝色,因为蓝色在后面,深度值小于红色所以不写入深度缓冲区,因此即便红色半透明,也看不到蓝色。
实验6:红(透明+开启深度写入)+蓝(透明+开启深度写入)+默认渲染顺序(先渲染蓝Cube)
效果:
解析:
把蓝色也变为透明,可以看到红蓝重叠的地方,完全看不到红色。为什么呢?见https://blog.csdn.net/a1047120490/article/details/106744930/
写得很详细,解释了为什么。
大概意思是。开启ZWrite的,可以看到重合部分红色Cube没有被混合渲染出来。
因为unity渲染顺序是按照物体中心点排序的,也就是objectlevel。所以重合部分的像素的深度缓存会先存入蓝色cube在重合部分的深度。然后渲染的红色Cube时,由于重叠部分红色Cube的像素深度>蓝色Cube(因为重叠部分红色被蓝色包裹),因此根本没办法通过深度测试,自然没办法深度写入,所以只显示的是蓝Cube的颜色。
也就是说导致问题的原因是渲染顺序是按照物体中心点到摄像机距离排序的(objcet level),而像素深度测试是按被渲染物体的那个渲染点到像素的距离决定的(piexel level)从而导致问题的发送。所以要解决这个问题可以将渲染顺序改为piexel level
结论:
当两个透明物体发生重叠时如果开启深度写入,那么重叠的部分显示会出错。
实验7:红(透明+关闭深度写入)+蓝(透明+关闭深度写入)+默认渲染顺序(先渲染蓝Cube)
解析:
可以看到红蓝重叠的地方,得出了透明的效果,但感觉红色是在蓝色前面的。为什么呢?同样见
https://blog.csdn.net/a1047120490/article/details/106744930/
大概意思是红Cube和蓝Cube重合的地方,应该先渲染红Cube再渲染蓝Cube,因为重合的地方是蓝Cube包裹了红Cube,而实际渲染顺序为先蓝Cube再红Cube,所以看起来有点怪。
结论:
当两个透明物体发生重叠时如果不开启深度写入,那么重叠的部分显示照样会出错,但总比开启深度写入强。
总结
1、对于不透明物体的,因为深度缓冲区的原因,渲染顺序不太重要(实验1、2)。
2、对于透明物体,渲染顺序会直接影响渲染结果,所以要设置渲染队列 Tags { "Queue"="Transparent" }
(实验3、4)
3、对于透明物体,如果开启深度写入,当两个透明物体重合时,会出现渲染错误,如果关闭深度写入,也会出现渲染错误,但比开启时错误要少。所以还是关闭深度写入的好。
4、因此对于半透明物体的默认写法为设置渲染队列为"Queue"="Transparent"
,设置透明混合Blend SrcAlpha OneMinusSrcAlpha
,关闭深度写入ZWrite Off
//设置渲染队列和渲染类型
Tags {"Queue"="Transparent" "RenderType"="Transparent" }
//设置透明混合
Blend SrcAlpha OneMinusSrcAlpha
//关闭深度写入
ZWrite Off
5、Unity在进行渲染时一般会对物体进行排序,再渲染,渲染顺序为:
(1)先渲染所以不透明物体("Queue"="Geometry"
的物体),从到相机的距离,由远到近渲染,并且开启深度测试和深度写入。
(2)再渲染半透明物体("Queue"="Transparent"
的物体),从到相机的距离,由远到近渲染,并且开启深度测试但关闭深度写入。
(3)但由于Unity对物体距离相机距离排序是基于object level的(基于物体中心的排序),所以当两个透明物体出现重合时,会出现渲染的错误,这是应该以像素为单位排序渲染(用顺序无关透明(order independent transparency, OIT)技术)。文章来源:https://www.toymoban.com/news/detail-462035.html
写在后面
今天2023/02/21是出考研成绩的日子,虽然博主已经走过了考研的独木桥,但回望过去考研的经历还是不禁感叹,考研这条路注定是孤独的,注定是几家欢喜几家愁。愿,星光不问赶路人,时光不负有心人。文章来源地址https://www.toymoban.com/news/detail-462035.html
到了这里,关于Unity半透明特效原理讲解(为什么半透明设置渲染顺序和深度写入这么重要)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!