博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UnityShader之遮挡透明
阅读量:5140 次
发布时间:2019-06-13

本文共 4513 字,大约阅读时间需要 15 分钟。

  好久没写博客了,最近在学shader,不得不说,shader真的非常美妙,我沉迷其中无法自拔= =

  之前做过一个遮挡透明的功能,当物体遮挡住主角时,该物体会变成半透明显示出主角。这次同样是遮挡透明的功能,不过,变透明的刚刚相反,是主角变成半透明,更严谨的说是主角被遮挡的那一部分变成半透明。

  先放出结果图:

 

  当被遮挡时,遮挡部分透明处理,那么需要涉及渲染深度的知识。引擎是如何判断哪个物体在前面哪个物体在后面呢?

  深度:每个像素有自己的深度值,离摄像机近的深度小,远的深度大

  深度缓冲区:存储每个像素的深度

  颜色缓冲区:存储每个像素的颜色

  过程:首先比较像素的深度与深度缓冲区同一位置的深度,如果前者小于后者,则未通过深度测试;否则,通过深度测试,将前者写入后者,将该像素的颜色写入到颜色缓冲区。将颜色缓冲区像素颜色显示到屏幕上。

  通过这个过程即可把深度小的像素剔除掉,将深度大的显示到屏幕上,从而实现物体的前后顺序。

 

  UnityShader提供了ZWrite 和 ZTest对应深度写入和深度测试。

  调整ZWrite可以控制是否将深度写入到深度缓冲区,当然,前提是深度测试通过,如果没通过测试,那么肯定是无法写入的

 

  调整ZTest可以定义上述中前者与后者的比较关系,默认为LEqual即小于等于时通过测试

 

   那么可以得到一种实现思路,用两个PASS:

  第一个PASS:ZTest 为 Greater,ZWrite 为 Off,当该像素被遮挡即深度大于深度缓冲区对应位置深度时执行该PASS,那么就可以在该PASS中实现被遮挡像素的效果。

  第二个PASS:ZTest为LEqual,ZWrite 为 On,这个PASS与上述PASS是互斥的,在这个PASS中实现未被遮挡像素的效果。

  设置ZWrite 是为了防止两个PASS都执行,如果第一个PASS的ZWrite为On,某一像素未被遮挡时,执行第一个PASS,将像素深度写入深度缓冲区,然后轮到第二个PASS进行深度测试时也会通过,因为小于等于嘛。

  

  被遮挡像素透明实现用了边缘光使得更炫酷。边缘光公式大概如下:

  fixed   rim=1-saturate(dot(worldNormalDir,worldViewDir));

  fixed3 finalCol=_RimColor.xyz*pow(rim,_RimPower)*_RimIntensity  

  通过第一个式子可以得到一个参数rim,顶点法线方向与视角方向契合度越高则rim越小,否则rim越大,即越靠近边缘rim越大

  第二个式子中pow是为了提高边缘光硬度

 

  代码:

1 // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'  2   3 Shader "MyShader/Rim/RimShader" {  4     Properties{  5         _RimColor("Rim Color",Color)=(1.0,1.0,1.0,1.0)//边缘光颜色  6         _RimPower("Rim Power",Range(0.1,10))=3.0//Pow参数  7         _RimIntensity("Rim Intensity",Range(0,100))=10//边缘光强度  8   9         _MainTex("Base (RGB)",2D)="white"{} 10     } 11     SubShader{ 12         //当所有不透明物体渲染后开始渲染此物体 13         Tags{
"Queue"="Geometry+50" "RenderType"="Opaque"} 14 15 Pass{ 16 Blend SrcAlpha OneMinusSrcAlpha 17 Cull Off 18 ZWrite Off 19 ZTest Greater 20 21 CGPROGRAM 22 #pragma vertex vert 23 #pragma fragment frag 24 #include "UnityCG.cginc" 25 26 fixed4 _RimColor; 27 float _RimPower; 28 float _RimIntensity; 29 30 struct a2v{ 31 float4 vertex:POSITION; 32 float3 normal:NORMAL; 33 }; 34 35 struct v2f{ 36 float4 pos:SV_POSITION; 37 float4 worldPos:TEXCOORD0; 38 float3 worldNormal:TEXCOORD1; 39 }; 40 41 v2f vert(a2v v){ 42 v2f o; 43 o.pos=mul(UNITY_MATRIX_MVP,v.vertex); 44 o.worldPos=mul(unity_ObjectToWorld,v.vertex); 45 o.worldNormal=UnityObjectToWorldNormal(v.normal); 46 return o; 47 } 48 49 fixed4 frag(v2f i):SV_TARGET{ 50 fixed3 worldNormalDir=normalize(i.worldNormal); 51 fixed3 worldViewDir=normalize(UnityWorldSpaceViewDir(i.worldPos)); 52 fixed rim=1-saturate(dot(worldNormalDir,worldViewDir)); 53 54 fixed3 col=_RimColor.xyz*pow(rim,_RimPower)*_RimIntensity; 55 return fixed4(col,0.3); 56 } 57 ENDCG 58 } 59 60 Pass{ 61 Tags{
"LightMode"="ForwardBase"} 62 ZWrite On 63 ZTest LEqual 64 CGPROGRAM 65 #pragma vertex vert 66 #pragma fragment frag 67 #include "UnityCG.cginc" 68 #include "Lighting.cginc" 69 #include "AutoLight.cginc" 70 71 sampler2D _MainTex; 72 float4 _MainTex_ST; 73 74 75 struct a2v{ 76 float4 vertex:POSITION; 77 float2 texcoord:TEXCOORD0; 78 }; 79 80 struct v2f{ 81 float4 pos:SV_POSITION; 82 float2 uv:TEXCOORD0; 83 }; 84 85 v2f vert(a2v v){ 86 v2f o; 87 o.pos=mul(UNITY_MATRIX_MVP,v.vertex); 88 o.uv=v.texcoord*_MainTex_ST.xy+_MainTex_ST.zw; 89 return o; 90 } 91 92 fixed4 frag(v2f i):SV_TARGET{ 93 fixed3 col=tex2D(_MainTex,i.uv).rgb; 94 95 return fixed4(col,1); 96 } 97 98 ENDCG 99 }100 101 102 }103 FallBack "Diffuse"104 }
View Code

 

转载于:https://www.cnblogs.com/McYY/p/7277401.html

你可能感兴趣的文章
pair的例子
查看>>
uva 387 A Puzzling Problem (回溯)
查看>>
Oracle中包的创建
查看>>
django高级应用(分页功能)
查看>>
【转】Linux之printf命令
查看>>
关于PHP会话:session和cookie
查看>>
C#double转化成字符串 保留小数位数, 不以科学计数法的形式出现。
查看>>
利用IP地址查询接口来查询IP归属地
查看>>
构造者模式
查看>>
Hbuild在线云ios打包失败,提示BuildConfigure Failed 31013 App Store 图标 未找到 解决方法...
查看>>
找到树中指定id的所有父节点
查看>>
jQuery on(),live(),trigger()
查看>>
【架构】Linux的架构(architecture)
查看>>
ASM 图解
查看>>
Date Picker控件:
查看>>
你的第一个Django程序
查看>>
treegrid.bootstrap使用说明
查看>>
[Docker]Docker拉取,上传镜像到Harbor仓库
查看>>
javascript 浏览器类型检测
查看>>
nginx 不带www到www域名的重定向
查看>>