(一)渲染顺序
唔姆这一章,我们将学习到如何制作逼真的半透明效果。before复习如何实现的代码,再重复提一遍渲染顺序吧。
渲染的顺序对半透明物体的渲染很重要!随便想想就能想通啦,我就不多说了。
但不论如何调整渲染的顺序,总是会有效果很差的时候,就像上面的两种,感觉和以前学depthbuffer时遇到的问题差不多。毕竟很难说这样的几个模型谁先谁后嘛~
解决办法书里给了,但也比较粗暴。一种是选择把模型拆分再进行排序,另一种只能让透明通道更加柔和,使穿插看起来不那么明显。当然,也可以开启深入写入来近似模拟物体的半透明。这点在后面的代码有写到嗷。
下面就要进入到代码时间了,哈吉马路哟~
(二)透明度测试
听名字,还挺哈人的,在了解原理后,这确实是个非常实诚有粗暴的算法。
核心算法就是在frag的这么几行。
只要alpha通道的值没达标就直接吧整个变都剔除了。很基础的想法,让人觉得我上我也行,但很多算法都是这么一步步从笨蛋到巧妙的,我从来没期待过,我能一下子写出来一开始就很健壮又漂亮的代码。
但多改几次,总是会比上次好一点点,这样马马虎虎的代码我还是有自信的。多写几年,上面的想想也不是不可以,所以这半年要努力、奋斗!
总之,回到透明度测试来,在shader的最后记得设置好Fallback “Transparent/Cutout/VertexLit”。至于效果,有当然还是有啦,但是极端了点,透明效果的边缘往往会有锯齿,这是在边界处理纹理的透明度变化的精度问题。为了更好的透明效果,就要引出下面要讲的透明度混合啦!
(三)透明度混合
透明度混合之前,我们来看下Unity关于Blend的一些命令,非常重要!感觉我总是打完就完了(doge)
上面的混合因子,看不懂很正常~,毕竟他要一两个小节以后才正式讲解,真是不合理!我直接贴过来了。
唔姆,注意这里的OneMinus是1-的意思,后面我们用到Blend SrcAlpha OneMinusSrcAlpha,实际上就是Orgb=SrcAlpha*Srgb+(1-SrcAlpha)*Drgb的意思啦。具体的图片我就放到下面了,但原理还是一定要记住点的!
当然混合类型布置上面的一个举例,他给的实在是太多了,有机会都试一下,真得去试试,不然咋能学会呢?
效果如下:
混合真是博大精深呢~
哟西,回到shader的编写身上。在透明度混合中需要添加全新的tag。
这三个tag基本是所有要透明效果的shader都要加上的,第一个就不讲了,放到Transparent的队列里,第二个让shader不收到projectors的影响(虽然我还不知道啥事projectors),第三个用来指明该shader使用了透明度混合。
第二个要注意的就是这边!!!我这边尝试这个Tags{“LightMode”=”Forwardbase”}就不得行。这是怎么回事呢?我写到这的时候突然感觉可能是Forward打错字了,希望不要这样,这样就太笨蛋了。
后面两行很重要,要关了深度写入,并开始混合。
以上。下面我还是放个完整代码吧,混合还是要好好看看的。
Shader "Unity Study/Chapter8/AlphaBlend"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color("Color Tint",COLOR)=(1,1,1,1)
_AlphaScale("Alpha Scale",Range(0,1))=1 //控制整体透明度
}
SubShader
{
Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout" }
Pass
{
//下面三行重点,关闭深度写入,并将源颜色的混合因子改为SrcAlpha,目标的设为OneMinusSrcAlpha
//Tags{"LightMode"="ForwordBase"} //为何我这里加上这一行就不行,草还真是拼错了
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc" // for _LightColor0
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct v2f
{
float4 pos:SV_POSITION;
float3 worldNormal:TEXCOORD0;
float worldPos:TEXCOORD1;
float2 uv : TEXCOORD2;
};
float4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
float _AlphaScale;
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float3 worldNormal=normalize(i.worldNormal);
fixed3 worldLightDir=normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 albedo=tex2D(_MainTex,i.uv).rgb*_Color.rgb;
fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
fixed3 diffuse=_LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir));
fixed3 finalColor=ambient+diffuse;
return fixed4(finalColor,tex2D(_MainTex,i.uv).a,_AlphaScale);
}
ENDCG
}
}
//FallBack "Transparent/VertexLit" //这里的fallback跟之前的不一样,要记住!!!!!!!!!
}
(四)开深度写入的透明效果
为什么要开深度写入呢?毕竟世界上总有一些鬼畜的模型,只能进行逐像素的深度排序后才能好好地混合。
实现比想象的简单好多,快乐,但会消耗点性能,道理之中。
大体原理,就是真的另开了一个pass深度写入了一遍,但使用ColorMask不对颜色缓冲做任何操作,只写深度,之后一个pass就跟上面写的一模一样了。
(五)双面渲染的透明效果
核心就是这一句 Cull Back/Front,这一行管理剔除哪些
实在是没想到,但做完以后会有种理所当然的感觉,不可思议。
AlphaTest和AlphaBlend都能实现。
AlphaTest真的简单的有点夸张了,只要把背面剔除关掉就好了,真好。
到了AlphaBlend的双面渲染就没这么ez了,毕竟,你想啊~,AlphaBlend需要关闭深度写入并向保证从后向前渲染最好。要是现在把背面剔除一关,我们就无法保证一个物体的正背面图元的渲染顺序了。
解决方案就把原来的pass变两个就好了,一个只渲染背面,一个只渲染正面,代码如下,很简单吧~
就此,透明效果的章节到此结束,明天一定要写第九章呀!
本文地址: UNITY SHADER 入门精要——第8章
您必须 登录 才能发表评论