• QQ
  • nahooten@sina.com
  • 常州市九洲新世界花苑15-2

游戏开发

U3D Shader之遮挡透明效果

原创内容,转载请注明原文网址:http://homeqin.cn/a/wenzhangboke/jishutiandi/youxikaifa/2019/0410/451.html

U3D Shader之遮挡透明效果

 
 
在常州网站开发建设3D游戏中,经常会呈现控制的角色被房子或者墙壁之类的挡住,一些游戏会把挡住角色的物体透明化显现(这个应该需求脚本配合shader完成,因而不在本文讨论范围),如藏地传奇;而一些游戏会做一些特殊效果把角色被挡住的局部显现出来,如火炬之光这样(如下图),下面就用Shader完成遮挡透明效果:
 
 
Shader完成原理:
 
剖析上图的效果,角色被前面墙体挡住的局部显现的相似xray效果(代码就直接从前面拿了,哈哈),没被挡住的局部显现贴图的正常效果,因而能够晓得这个shader需求两个pass来完成。其中一个pass正常显现贴图,另外一个pass完成xray效果。当然不止这么简单,要完成上图的效果还需求Ztest,Zwrite,以及渲染队列等学问。
 
准备学问:
 
Rendering Order渲染队列
 
渲染队列,从游戏开发运营字面的意义了解就是渲染的次第,即对象渲染谁先谁后,如图你画画的时分,假如画画的时分每一笔的次第一样,假如第一笔画红色,后面一笔画黑色,最终黑色会把红色掩盖掉。Unity里面我们能够经过SubShader Tags中的Queue Tag控制,unity提供了一些内置的渲染队列:
渲染队列 渲染队列描述 渲染队列值
Background 这个队列被最先渲染。它被用于skyboxes等。 1000
Geometry 这是默认的渲染队列。它被用于绝大多数对象。不透明几何体使用该队列。 2000
AlphaTest 通道检查的几何体运用该队列。它和Geometry队列不同,关于在一切平面物体绘制后渲染的通道检查的对象,它更有效。 2450
Transparent 该渲染队列在Geometry和AlphaTest队列后被渲染。任何通道混合的(也就是说,那些不写入深度缓存的Shaders)对象运用该队列,例如玻璃和粒子效果。 3000
Overlay 该渲染队列是为掩盖物效果效劳的。任何最后被渲染的对象运用该队列,例如镜头光晕。 4000

在关闭深度测的状况下,能够看出处于background队列的物领会最先被渲染,假如没有深度测试,他将理想画面的最后面,假如前面geometry队列的物体,就会优先显现geometry的物体,我想普通都会有这个问题:假如属于同一个渲染队列该怎样决议谁先谁后呢,所以unity还有其他的方式决议物体能依据实践深度正常显现,如深度测试。能够这么说,渲染队列相当于把物体停止了大致的排序,假如常州手游开发需求准确的话,还需求其他的操作。
 
Depth Testing深度测试
 
Depth Testing:深度测试,也叫深度缓冲。用来肯定物体的遮挡关系。只要最靠近察看者的物领会被绘制。深度即Z,该值越小表示离察看者越近,该值越大表示离察看者越远。
 
Shader里默许有如下代码
ZWrite On
ZTest LEqual
意义即便Shader里没有写任何关于Depth Testing的代码,Shader也会执行深度测试。
 
ZWrite:能否此物体的像素深度会被记载(默许记载),
ZWrite On  深度记载(默许On),此对象的深度会依据实践状况停止记载。
ZWrite Off  不记载此深度,通常用于半透明物体,
 
ZTest Less | Greater | LEqual | GEqual | Equal | NotEqual | Always
默许是 LEqual。 即当深度小于或者等于 深度最小值时,渲染物体,即渲染最近的物体。
 
依据上面的学问我们能够整理个思绪,在unity默许状况下物体深度缓存都是翻开的,除了半透明物体外,大局部物体都会依据实践状况渲染,显现正确的遮挡关系,即离察看者越近的物领会挡住离察看较远的物体。因而要完成本文的效果,使的被挡住的局部理想出来,我们需求关闭深度缓存(不是关闭ztest),本人控制渲染队列来使被遮挡物体的局部显现到遮挡物的前面来,详细就是在shader中,首先将subshader Tag改成如下方式:
Tags { "Queue" = "Geometry+500“ ”RenderType"="Opaque" }
这样物体将在不透明物体(墙壁)之后渲染,同时定义两个pass,一个输出xray效果,一个输出贴图颜色,将第一个pass设置成Zwitre off,关闭深度缓存,并将Ztest 参数设置成Greater,第二个pass运用默许设置 即Zwrite on , Ztest LEqual。
 
那么执行的时分,假如对象没有被墙壁挡住时,先执行的pass输出xray效果,后执行的pass输出了贴图颜色,最终xray被交换成正常贴图颜色。而假如对象被墙壁遮挡时,第一个pass不将它的深度值写入【深度缓存】,此时Ztest参数为Greater ,显然当前pass的深度值("Geometry+500")是大于墙壁深度值的,所以最终显现了当前pass的颜色,第二个pass是默许设置,并写入了【深度缓存】,深度值是小于墙壁深度值的,依据ztest LEqual第二个pass的贴图颜色被剔除,最终的颜色就会依据blend公式,显现第一个pass和墙壁颜色的混合结果:Blend  SrcAlpha   One
最终颜色=xray效果RGB*xray效果Alpha+墙壁RGB*1
 
关于常州游戏开发培训这个效果能够总结出个简单的代码形式:
Shader "…………"   
{  
    Properties   
    {   
        ……………………
    }  
    SubShader   
    {  
        LOD 300  
//更改渲染队列,调整绘制次第,使物体绘制到其他物体之前
    Tags { "Queue" = "Geometry+500" "RenderType"="Opaque" }
//第一个pass输出xray局部,两个pass的次第不能改动
Pass
    {
        Blend SrcAlpha One//设置颜色混合结果
        ZWrite off  //关闭深度缓存,重写对象的绘制次第
        ztest greater//当深度大于最小值时,渲染对象
        …………………………
    }
//第二个pass正常输出贴图颜色
        pass  
        {  
                ZTest LEqual//缺省值,能够不写,当深度小于或者等于深度最小值时,渲染对象,即渲染最近的物体。   
                ………………………… 
        }   
 
VF版本代码01:
Shader "PengLu/OccTransVF"   
{  
    Properties   
    {   
        _MainTex ("Base (RGB)", 2D) = "white" {}  
        _RimColor("RimColor",Color) = (0,1,1,1)
        _RimPower ("Rim Power", Range(0.1,8.0)) = 1.0
    }  
    SubShader   
    {  
        LOD 300  
        Tags { "Queue" = "Geometry+500" "RenderType"="Opaque" } 
        Pass
        {
            Blend SrcAlpha One
            ZWrite off
            Lighting off
            ztest greater
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            float4 _RimColor;
            float _RimPower;
            struct appdata_t {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
                float4 color:COLOR;
                float4 normal:NORMAL;
            };
            struct v2f {
                float4  pos : SV_POSITION;
                float4  color:COLOR;
            } ;
            v2f vert (appdata_t v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                float3 viewDir = normalize(ObjSpaceViewDir(v.vertex));
                float rim = 1 - saturate(dot(viewDir,v.normal ));
                o.color = _RimColor*pow(rim,_RimPower);
                return o;
            }
            float4 frag (v2f i) : COLOR
            {
                return i.color; 
            }
            ENDCG
        }
        pass  
        {  
            ZWrite on
            ZTest less 
            CGPROGRAM  
            #pragma vertex vert  
            #pragma fragment frag  
            sampler2D _MainTex;  
            float4 _MainTex_ST;
            struct appdata {  
                float4 vertex : POSITION;  
                float2 texcoord : TEXCOORD0;  
            };  
            struct v2f  {  
                float4 pos : POSITION;  
                float2 uv : TEXCOORD0;  
            };  
            v2f vert (appdata v) 
            {  
                v2f o;  
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);  
                o.uv = v.texcoord;  
                return o;  
            } 
            float4 frag (v2f i) : COLOR  
            {  
                float4 texCol = tex2D(_MainTex, i.uv);  
                return texCol;  
            }  
            ENDCG  
        }  
    } 
    FallBack "Diffuse" 
}  
 
手机App外包版本代码04效果
 


上篇:上一篇:Unity之IL2CPP解析
下篇:下一篇:DIOCP开源项目-定义本人要发送的数据构造(MyObje