Shader学习的基础知识(六)透明效果
透明效果
在渲染的时候,渲染的顺序是非常重要的,对于不透明物体我们不用不考虑是因为有的深度缓冲存在。在渲染时需要把片元中的值进行比较(如果开了深度测试),但一但关了尝试测试就没那么简单了。
透明度测试: 只要小于阈值就会被舍弃,完全不透明或完全透明。
透明度混合: 这种方法才能得到真正的透明效果,但是需要关掉深度测试,这时候就有很多问题要我们注意了.
深度测试 和 深度写入
下面一篇文章会详细的来讲这个问题,敬请关注。
渲染顺序
为什么要关闭深度写入呢?如果不关,一个半透明物体后内容是应该被看到的,但如果它离摄像机更近,则后面的物体会被剔除。所以一但关掉了深度写入渲染顺序就变得非常重要了。
思考:A是透明物体,B不透明。(A离摄像机近 B离摄像机远)
情况一:不透明物体B开了深度测试和写入,B会先把颜色缓冲和深度缓冲写入。A还是会深度测试,发现A比B离相机更近,因此会用A的透明度来和颜色和B混合得到正确的半透明效果。
情况二:先渲染A,深度缓冲区没有数据,A就直接写入了,由于半透明物体关了深度写入,因此不会修改深度缓冲。当B来渲染的时候发现没有写入过(因为A来过,没告诉别人他来过),就直接写入了(也就覆盖了)。
思考 :AB都是半透明的(A离摄像机近 B离摄像机远)
情况一:我们渲染B,再渲染A,那B会正深写入颜色缓冲,然后A会和缓冲中的B进行混合得正确结果。
情况二:先渲染A,则A会先写入缓冲区,B来的时候再和它相乘,得到相反的透明结果。
引擎是怎么做的
常用的方法是:
先渲染所有不透明的并开启他们的深度测试和深度写入。
把半透明物体按摄像机距离排序,然后从后往前渲染,开启深度测试,关闭深度写入。
思考但是怎么分前后呢?中心点?边缘点?这些都会有可能得出不正确的效果。所以解决方式只有尽可能让模型是凸面体或考虑做成多个子物体。
设置Unity Shader渲染顺序
可以用标签(Queue)来解决这个问题,索引号越小越早被渲染
SubShader{ Tags{"Queue"="AlphaTest"} Pass{ ... }
Bakground 索引号:1000 最先渲染,常用背景等。
Geometry 索引号:2000 默认值,大多数用这个或不透明的用这个。
AlphaTest 索引号:2450 透明度测试用这个,不透明物体用这个会更快。
Transparent 索引号:3000 透明混合
Overlay 索引号:4000 最后的叠加效果
关闭深度测试
SubShader{ ZWrite off Pass{ ... }
透明测试例子(不是透明混合)
Shader "Custom/TestShader13" { Properties{ _Color("Color Tint",Color)=(1,1,1,1) _MainTex("Main Tex",2D)="white"{} _Cutoff("Alpha Cotoff",Range(0,1))=0.5 } SubShader{ //"Queue"="AlphaTest" 队列为透明测试 //"IgnoreProjector"="True" 不接受投影 //"RenderType"="TransparentCutout"指明该Shader是一个用于透明测试的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; float _Cutoff; //Appction To Vertex struct a2v{ float4 vertex:POSITION; float3 normal:NORMAL; float4 texcoord:TEXCOORD0; }; //Vertex To Fragment struct v2f{ float4 pos:SV_POSITION; float3 worldNormal:TEXCOORD0; float3 worldPos:TEXCOORD1; float2 uv:TEXCOORD2; }; v2f vert(a2v v){ v2f o; o.pos=UnityObjectToClipPos(v.vertex); o.worldNormal=UnityObjectToWorldNormal(v.normal); o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz; o.uv=TRANSFORM_TEX(v.texcoord,_MainTex); return o; } float4 frag(v2f i):SV_TARGET{ fixed3 worldNormal=normalize(i.worldNormal); fixed3 worldLightDir=normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed4 texColor=tex2D(_MainTex,i.uv); //clip会判断a通道,如果小于0则舍弃该片原 clip(texColor.a-_Cutoff); fixed3 albedo = texColor.rgb*_Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo; fixed diffuse=_LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir)); return fixed4(ambient+diffuse,1.0); } ENDCG } } }
- Shader学习的基础知识(十三)镜面效果
- shader学习之基础纹理透明效果
- Shader学习的基础知识(十四)玻璃效果
- Shader学习的基础知识(二十)屏幕后处理效果
- Shader学习的基础知识(二十六)描边效果
- Shader学习的基础知识( 三十一)水波效果
- Shader学习的基础知识(十)复杂的灯光概念
- Shader学习的基础知识(二十一)边缘检查
- Shader学习的基础知识(二十五)动态模糊
- Shader学习的基础知识(二十二)高斯模糊
- Shader学习的基础知识(二十七)全局雾效
- Shader学习的基础知识(四)法线贴图
- Shader学习的基础知识( 三十二)渲染优化概括
- Shader学习的基础知识(十九)广告牌
- Shader学习的基础知识(五)渐变纹理
- Shader学习的基础知识(七)深度测试与深度写入
- Shader学习的基础知识( 三十三)渲染优化具体
- Shader学习的基础知识(十二)立方体纹理
- Shader学习的基础知识(二十三)卷积
- Shader学习的基础知识( 三十四)表面着色器上