我必须要宣布一个不幸的消息:我们得抛弃跟随我们许久的Sakura.shader,而创建一个新的shader了。它已经完成了自己的使命。
重新写一个shader吧,可以是一个在附加篇写的那种,这次我不会插嘴了。
写好之后再往下看。
/*
由于文件有些乱,所以我建了几个文件夹归了下类。这四个文件夹,除了Scenes是本来就有的,其余全是我建的。文件夹分类
*/
我给shader取名Translucent,意思是半透明的;同时也创建了材质,把shader赋到材质上。再创建个小球,把材质赋到小球上,这样我们可以直观看出效果。
我这里shader写完了,呐,效果是这样的:shader效果
别忘了,我们这节要学的是半透明。什么半透明?就是只狼里月隐糖的那种,
半透明的狼
显示一部分本身颜色,显示一部分被遮住景物的颜色。
黑体字部分就是半透明物体的本质,一部分后面的颜色,一部分当前的颜色。肯定不能直接相加,否则就那个都看不清,一定有个比例控制着。假设物体本身的颜色为s(Source源头的缩写),被遮住景色的颜色为d(Destination目的地的缩写),那么半透明物体返回的颜色为:
s*x + d*y
其中x和y是数值参数,表示颜色的比例。显然,当x越小,y越大,物体本身的颜色越少,背景的颜色越多,透明程度越高;当x=0,y=1时,物体完全透明:因为返回的颜色已经没有物体本身的份了,全是被遮住的颜色。反之亦然,当x越大,y越小,物体本身的颜色越多,被遮景物的颜色越少,物体越不透明。当x=1,y=0时物体完全不透明。
由是能看出x和y的关系:都为正数且和为1。
你可能早已想到,或者观察到,为什么shader每次返回的颜色,最后一个分量都是1?返回的颜色值a为1
你记得,这个分量表示颜色的透明度,越小越透明。可你对它进行修改,改成0.5,改成0.1,甚至改成0,物体都毫无透明效果?
(此处无图,自己去试)
那是因为,我们没有开透明开关。开启的方法跟使不删除背面一样,是一条语句:
Blend SrcAlpha OneMinusSrcAlphaBlend语句
也是写在CG代码之上。这种语句叫透明度混合,由混合(Blend)打头(为什么叫混合?经过上面的解释你很好理解,就是物体颜色和背景颜色按一定比例混合)。混合的比例在之后的两个词:SrcAlpha表示物体的透明度,OneMinusSrcAlpha表示1减去物体透明度的差。
这行语句会用第一个词代表的数(上面表达式的x)乘以物体的颜色,加上第二个词代表的数(上面表达式的y)乘以背景的颜色,返回最后的结果(为什么是“词代表的数”?因为这个数你不能自己瞎写)。同样可以表示数的词有:One,Zero,DstAlpha,OneMinusDstAlpha。意思就是英语字面意思。凡是含Src的就表示本物体的(使用本shader的物体),而含Dst的表示被遮住的景色的。
我们上面用的那个命令是最常用的:
Blend SrcAlpha OneMinusSrcAlpha
因为它完美切合了实际效果,正如我们上面叙述过的。
可以试试哦,在片元函数返回颜色的最后一个值那写个0.5:把a值改成0.5
咋一看好像还可以,但稍微转动下视角就会发现奇怪之处:透明了天空盒
物体透明的后面是天空盒?我那么大一个麻衣球呢?
原因是渲染顺序。是的,unity物体的渲染是讲顺序的。顺序分类型有数值,越小的越先渲染。在材质面板下可以看到其顺序(Render Queue,渲染序列),From Shader表示顺序来源,shader默认是不透明物体(在这叫几何体Geometry),顺序是2000。点击它可以看到三个类型,第一个是Geometry,第二个是AlphaTest,顺序2450;第三个是Transparent顺序3000。上节我们实现的那个透明效果严格来说是AlphaTest,透明度测试,也应该调整下顺序的;本节实现的半透明效果是应该在Tranparent顺序下的。切换到透明顺序
切换完后,你会发现,很amazing的效果吧!
/*
你也看到了,渲染顺序中有个From Shader,表明我们可以在shader中设置渲染顺序。使用的语句为:
Tags {“Queue”=”Transparent”}在shader里设置渲染顺序
记住是在SubShader下写而不是Pass。
会把shader的渲染顺序设为3000。同样你也可以更换Transparent为AlphaTest或Geometry,来变更渲染顺序。
*/
现在我们可以通过控制片元函数返回颜色的a值来控制物体的透明度了,来玩点更有意思的。比如,让a成为一个变数:
float a = max(0, dot(l, i.worldNormal));
return fixed4(diffuse + ambient + specular, a);计算特定数值来控制a值
代码意思嘛,你知道的,向光面显现,背光面透明。背光面透明
再来:
float a = max(0, dot(v, i.worldNormal));
(就是把上式的 l 改成 v ,光线方向改成视角方向)这个效果很梦幻:边缘隐去
朝向我们的面显现,边缘的面渐隐。来,求1减去它的差看效果:
float a = 1 - max(0, dot(v, i.worldNormal));中心掏空
这就成了中间透明,边缘显现的效果(像不像山吹的盾)!很amazing吧。联系之前学得的光线方向,法线方向,视角方向,你可以做出更多有趣的效果。
试试用纹理来控制:
_AlphaTex(“透明度纹理”, 2D)=“white”{}
sampler2D _AlphaTex;
这两个语句各该放哪你肯定知道。
取色赋值:
a = tex2D(_AlphaTex, i.uv).r;纹理取值
看效果:纹理透明
真·半隐半现的球。
真正的半透明效果很难实现,我们在这只是对它进行了模拟。一般情况下是够用了的,更高级的半透明效果(比如次表面散射)咱们以后细说。
下一节咱们开始对已知内容进行完善,这是必要的。