zoukankan      html  css  js  c++  java
  • UnityShader之遮挡透明

      好久没写博客了,最近在学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
  • 相关阅读:
    .net Monitor产生SynchronizationLockException异常的原因
    .net 表达式返回值和等号赋值的区别
    .net core WebApi Interlocked配合ManualResetEventSlim实现并发同步
    .net core 使用log4net日志组件
    .net core Kestrel宿主服务器自定义监听端口配置
    .net core IIS/Kestrel上传大文件的解决方法
    .net 在同步方法中使用拉姆达表达式执行async/await异步操作
    ASP.NET MVC ValidationAttribute 服务器端自定义验证
    自定义TempData跨平台思路
    ValueProvider核心的值提供系统
  • 原文地址:https://www.cnblogs.com/McYY/p/7277401.html
Copyright © 2011-2022 走看看