UnityShader实例04:遮挡透明材质

开发者福利!热门AI工具限时免费用 购周边即赠Coding Plan Lite,Claude Code、Cursor等20+工具畅享,效率翻倍! 阅读详情

遮挡透明材质

在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


对于这个效果可以总结出个简单的代码模式:

[csharp]  view plain  copy
 print ?
  1. Shader "…………"     
  2. {    
  3.     Properties     
  4.     {     
  5.         ……………………  
  6.     }    
  7.         
  8.     SubShader     
  9.     {    
  10.           
  11.         LOD 300    
  12. //更改渲染队列,调整绘制顺序,使物体绘制到其他物体之前  
  13.     Tags { "Queue" = "Geometry+500" "RenderType"="Opaque" }  
  14. //第一个pass输出xray部分,两个pass的顺序不能改变  
  15. Pass  
  16.     {  
  17.         Blend SrcAlpha One//设置颜色混合结果  
  18.         ZWrite off  //关闭深度缓存,重写对象的绘制顺序  
  19.         ztest greater//当深度大于最小值时,渲染对象  
  20.         …………………………  
  21.     }  
  22. //第二个pass正常输出贴图颜色  
  23.         pass    
  24.         {    
  25.                 ZTest LEqual//缺省值,可以不写,当深度小于或者等于深度最小值时,渲染对象,即渲染最近的物体。     
  26.                 …………………………   
  27.         }     
  28. }  





VF版本代码01:

[csharp]  view plain  copy
 print ?
  1. Shader "PengLu/OccTransVF"     
  2. {    
  3.     Properties     
  4.     {     
  5.         _MainTex ("Base (RGB)", 2D) = "white" {}    
  6.         _RimColor("RimColor",Color) = (0,1,1,1)  
  7.         _RimPower ("Rim Power", Range(0.1,8.0)) = 1.0  
  8.     }    
  9.         
  10.     SubShader     
  11.     {    
  12.           
  13.         LOD 300    
  14.         Tags { "Queue" = "Geometry+500" "RenderType"="Opaque" }   
  15.         Pass  
  16.         {  
  17.             Blend SrcAlpha One  
  18.             ZWrite off  
  19.             Lighting off  
  20.   
  21.             ztest greater  
  22.   
  23.             CGPROGRAM  
  24.             #pragma vertex vert  
  25.             #pragma fragment frag  
  26.             #include "UnityCG.cginc"  
  27.   
  28.             float4 _RimColor;  
  29.             float _RimPower;  
  30.               
  31.             struct appdata_t {  
  32.                 float4 vertex : POSITION;  
  33.                 float2 texcoord : TEXCOORD0;  
  34.                 float4 color:COLOR;  
  35.                 float4 normal:NORMAL;  
  36.             };  
  37.   
  38.             struct v2f {  
  39.                 float4  pos : SV_POSITION;  
  40.                 float4  color:COLOR;  
  41.             } ;  
  42.             v2f vert (appdata_t v)  
  43.             {  
  44.                 v2f o;  
  45.                 o.pos = mul(UNITY_MATRIX_MVP,v.vertex);  
  46.                 float3 viewDir = normalize(ObjSpaceViewDir(v.vertex));  
  47.                 float rim = 1 - saturate(dot(viewDir,v.normal ));  
  48.                 o.color = _RimColor*pow(rim,_RimPower);  
  49.                 return o;  
  50.             }  
  51.             float4 frag (v2f i) : COLOR  
  52.             {  
  53.                 return i.color;   
  54.             }  
  55.             ENDCG  
  56.         }  
  57.         pass    
  58.         {    
  59.             ZWrite on  
  60.             ZTest less   
  61.   
  62.             CGPROGRAM    
  63.             #pragma vertex vert    
  64.             #pragma fragment frag    
  65.             sampler2D _MainTex;    
  66.             float4 _MainTex_ST;  
  67.                 
  68.             struct appdata {    
  69.                 float4 vertex : POSITION;    
  70.                 float2 texcoord : TEXCOORD0;    
  71.             };    
  72.               
  73.             struct v2f  {    
  74.                 float4 pos : POSITION;    
  75.                 float2 uv : TEXCOORD0;    
  76.             };    
  77.               
  78.             v2f vert (appdata v)   
  79.             {    
  80.                 v2f o;    
  81.                 o.pos = mul(UNITY_MATRIX_MVP,v.vertex);    
  82.                 o.uv = v.texcoord;    
  83.                 return o;    
  84.             }   
  85.                
  86.             float4 frag (v2f i) : COLOR    
  87.             {    
  88.                 float4 texCol = tex2D(_MainTex, i.uv);    
  89.                 return texCol;    
  90.             }    
  91.             ENDCG    
  92.         }    
  93.     }   
  94.     FallBack "Diffuse"   
  95. }    


VF版本代码01效果

Unity Shader透明遮罩效果 先展示一下效果: 原理: 透明遮罩位于被遮住物体(图中红色)和显示物体(绿色和白色)前面,优先渲染遮罩,第一个Pass记录透明遮罩的深度之后在绘制透明颜色,这样到绘制被遮住物体时,只要开启ZTest就可以使其深度测试失败,透明遮罩罩住的位置不绘制. ... 阅读详情

相关推荐

[Unity]透明材质

主要研究透明材质的生成方式,但资料用的是比较老的《unity shader入门精要》,可能有些落后

hoxidohanabi的博客 2576

Unity Shader遮挡透明

Unity Shader遮挡透明

unity透明遮罩动画与Tiling和Offset的关系

最近我们的游戏要实现这样一个效果。即死亡之后,出现一个圆圈,圆圈之外都是黑色的,这个圆圈从屏幕外慢慢减小到人物大小。复活之后,这个圆圈慢慢变大到人物外面。一开始想了好多方案最后都pass掉了。留下了最后的方案,使用Shader完成。首先准备两张图片。一张纯黑背景。一张白色圆圈。→←首先是新建一个shader,将shader拖入Material,将Material拖入纯黑背景。Shader代码如下。...

q378992971的博客 943

Unity3D 游戏开发:实现景观物体遮挡透明

如果在视锥体内,则将其材质设置为半透明材质,并将透明度设置为指定的半透明值。在游戏开发中,有时候需要在景观物体遮挡视线的时候,将被遮挡的对象设置为半透明状态,这样玩家就可以看到被遮挡对象的轮廓,从而提高游戏的可玩性。需要注意的是,在使用该脚本时,需要将需要变为半透明的对象的材质设置为可修改的材质,否则会出现错误。在需要进行遮挡透明处理的地方,使用Unity遮挡剔除功能,判断被遮挡的对象是否在摄像机的视锥体内。如果被遮挡对象在视锥体内,将其材质透明度设置为半透明的值,否则设置为不透明的值。

QscFramework的博客 967

Unity实现遮挡人物的障碍物体设为透明,并在不遮挡时恢复的个人解决方法

通过摄像机向人物发射射线,检测第一个碰到的物体是否为人物。如果不是人物,那么就判断为障碍,将其透明度设为0.2,并将其添加入一个GameObject数组中。当射线检测到第一个物体是人物时,将这个GameObject数组中的所有物体透明度恢复为1,并清空这个数组。

qianhang120的博客 3994

Unity Shader入门精要 --- 阅读笔记 18.07.19

01.模版测试(Stencil Test):与之相关的是模版缓冲(Stencil Buffer). 02.模版测试更高级的用法:渲染阴影,轮廓渲染等 03.深度测试(Depth Test):这个测试同样是可以高度配置的.比较函数是小于等于的关系,即如果这个片元的深度值大于等于当前深度缓冲区中的值,那么就会舍弃它.透明效果和深度测试以及深度写入的关系非常密切. 04.合并需要解决的问题:是使用...

不积跬步,无以至千里;不积小流,无以成江海。 571

Unity3d】火炬之光的X射线效果

http://www.cnblogs.com/dosomething/archive/2012/04/03/2431149.html 人物和摄像机之间存在例如墙壁等的阻挡时  可以修改阻挡材质的alpha呈现半透明状    using UnityEngine; using System.Collections;   public class exampl...

weixin_33751566的博客 236

Unity Shader透明并具有遮挡效果

1、 Shader "MASK/PortalMaskShader" { SubShader { Tags{ "RenderType" = "Opaque" "Queue" = "Geometry-3" } ColorMask 0 ZWrite on CGINCLUDE #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; }; struct v2f { float4 pos :

龙胖胖的博客 5124

Unity】用Shader实现图片的区域遮罩,支持半透明,实现地图动态上色功能

一个项目,做世界地图时,希望未开启的地块是线稿,新地块开启时,做一个上色处理。 想到的方案就是:上了色的彩图盖在线稿上,然后用mask 控制彩图的局部显隐。 网上找了一个,可以半透明遮罩shader: https://www.jianshu.com/p/1d9d439c28fa 要控制不同区块显示或不显示,要怎么处理呢?  mask图其实只用到了 alpha,还有rgb2

zhenmu的专栏 1万+

unity遮挡人物的模型透明化_笔记

使用射线检测将挡住人物的模型透明化(未考虑性能问题)原理: 从相机向人物发射一条射线,将碰到的tag为"障碍"的模型mesh材质全换为透明贴图,并将当前透明化的材质存储,每帧刷新时复原。前置条件: 1. 将需要透明化的模型tag设置为"障碍" 2. 将"BuildSetFasle()"函数放在update中执行...

huojiweigb的博客 1560

Unity实用Shader遮罩

unity中很多时候会用到遮罩层,如Minnmap、钮等  这里贴上相关的Shader代码和注释 Shader "ShaderDemo/MaskLayer" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} //目标图片,即需要被遮罩的图片 _MaskLayer("Culling Mask",2D) = "white"{}

编程小生的专栏 2万+

Unity遮挡边缘光透明xray效果(RimShader

一. 前言 在3D游戏中,经常会出现控制的角色被房子或者墙壁之类的挡住,一些游戏会做一些特殊效果把角色被挡住的部分用xray边缘光显示出来,如下图,下面就用Shader实现遮挡透明效果。 二. 制作 1 创建Shader shader需要两个pass来实现。其中一个pass正常显示贴图,另外一个pass实现xray效果。 创建一个Shader文件,Shader代码见文章末尾 2 创建材质球 创建材质球 使用刚刚的shader,设置RimColor 把材质球赋值给模型 3 测试 创建一个Cub

tt58521的博客 1242

Unity中UI Shader遮罩RectMask2D

Unity中UI Shader遮罩RectMask2D

楠溪泽岸的博客 3973

使用透明度实现Mask遮罩Unity Shader

原创文章,转载请注明出处使用透明度实现Mask遮罩Unity Shader 你好,用你的shader后在pc编辑器上是没有问题的,在5.4环境下打包到手机上也没问题,但是升级到5.5后打包到手机(ios,android的还没试)上就显示为粉红色,不知道博主有没有解决方案 感谢提醒,有时间我会修正一下 关于遮罩的需求 将矩形的图片做成圆角矩形、圆形 常用实现方

qq_14939027的博客 5561

Unity 利用 Stencil(模版测试) 实现mask的遮挡效果 可遮挡粒子和自定义遮挡形状

先看最终的效果图: 美术提了一个在按钮上加粒子特效的需求,因此需要做下裁剪的功能,防止粒子特效超框(如上图)。一开始想的是用之前的方法,给shader一个按钮位置以及长宽的Vector,计算按钮区域来计算遮挡。但是发现那个按钮的图片是一个梯形的(如图),空白的部分也不能出现粒子,这就麻烦了。 后来查了下发现shader有一个Stencil的功能,叫做模板缓存,可以实现我们想要的需求(不过似...

王王王渣渣的博客 1万+

[UnityShader3]遮罩效果

学习shader也有一段时间了,但由于只注重理论,而不注重实践,所以当想要写一个shader时,往往无从下手。眼看着大神们写出了各种华丽的shader,本人的心中真是百感交集啊!于是近段时间终于下定决心,重新学习了shader。关于shader的基础教程,个人认为比较好的是《猫都能学会的Unity3D Shader入门指南》系列、浅墨的shader教程以及《unity4.x从入门到精通》中shad

宏哥的博客 4512

unity 3d 实现遮挡剔除效果

本教程学习均来自U3D中文课堂麦扣老师

zslpk的博客 1953

unity3d 摄像机跟随角色时被物体遮挡解决方案

参考文章:http://www.xuanyusong.com/archives/1991 在看此文章时请先看上面的参考文章 看完以上文章后,你也许会想人家都已经给出所有代码了,你还写个毛啊 别急,现在进入主题 在我的项目中,我采用的是物体遮挡作半透明处理,如果按照上述文章中的思路来写代码的话,那么结果就是当多个物体遮挡角色时,只有第一个物体会半透明,如图: 角色被墙...

weixin_30349597的博客 809
上一篇: 理解A*寻路算法具体过程
下一篇: [UnityShader2]顶点片段着色器实例
血月笙歌
博客等级 码龄17年 44粉丝 25原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值