您的位置:首页 > 其它

Shader学习的基础知识(六)透明效果

2019-03-08 10:48 41 查看
版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ww1351646544/article/details/88324849

透明效果

在渲染的时候,渲染的顺序是非常重要的,对于不透明物体我们不用不考虑是因为有的深度缓冲存在。在渲染时需要把片元中的值进行比较(如果开了深度测试),但一但关了尝试测试就没那么简单了。
透明度测试: 只要小于阈值就会被舍弃,完全不透明或完全透明。
透明度混合: 这种方法才能得到真正的透明效果,但是需要关掉深度测试,这时候就有很多问题要我们注意了.

深度测试 和 深度写入

下面一篇文章会详细的来讲这个问题,敬请关注。

渲染顺序

为什么要关闭深度写入呢?如果不关,一个半透明物体后内容是应该被看到的,但如果它离摄像机更近,则后面的物体会被剔除。所以一但关掉了深度写入渲染顺序就变得非常重要了。

思考: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
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: