摄像机与主角之间遮挡显示处理(Unity3D开发之二十八)
Posted Cocos2der
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了摄像机与主角之间遮挡显示处理(Unity3D开发之二十八)相关的知识,希望对你有一定的参考价值。
今天处理遮挡的时候,本来是想摄像机射线检测,设置建筑半透明效果用来显示被遮挡的角色(有很多游戏也是这样处理的),实现后发现效果实际上不太好。如果被遮挡角色还是敌人或者多个角色时候,不是特别好,比如敌人被遮挡我希望单独区分下。所以改成了现在的直接绘制2D填充色(也就是忽略自身的深度值)来显示。
主要代码
Properties
_NotVisibleColor ("NotVisibleColor (RGB)", Color) = (0.3,0.3,0.3,1)
Pass
ZTest Greater
ZWrite Off
Lighting Off
Color [_NotVisibleColor]
- _NotVisibleColor: 用来绘制挡住时候显示的颜色;
- ZTest Greater:表示大于深度缓存中的值的时候(也就是被遮挡的时候),将深度缓存中对应像素的颜色值改为自己的颜色(_NotVisibleColor)
- ZWrite Off:表示关闭深度缓存,也就是在上一步写入像素颜色的时候不写入自身深度值(等于遮挡树上绘制颜色,深度值使用树的)
- Lighting Off:取消光照,因为我效果希望是2D颜色块的效果。
PlayerDiffuse.shader
Shader "Custom/PlayerDiffuse"
Properties
_NotVisibleColor ("NotVisibleColor (RGB)", Color) = (0.3,0.3,0.3,1)
_Color ("Main Color", Color) = (1,1,1,1)
_MainTex ("Base (RGB)", 2D) = "white"
SubShader
Tags "RenderType"="Opaque"
LOD 200
Pass
ZTest Greater
Lighting Off
ZWrite Off
Color [_NotVisibleColor]
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
fixed4 _Color;
struct Input
float2 uv_MainTex;
;
void surf (Input IN, inout SurfaceOutput o)
fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Alpha = c.a;
ENDCG
Fallback "Legacy Shaders/VertexLit"
渲染深度解释:
参考文章:[UnityShader]渲染队列、ZWrite和ZTest
什么是深度?
深度其实就是该像素点在3d世界中距离摄像机的距离。离摄像机越远,则深度值(Z值)越大。什么是深度缓存?
深度缓存中存储着准备要绘制在屏幕上的像素点的深度值。如果启用了深度缓冲区,在绘制每个像素之前,OpenGL会把该像素的深度值和深度缓存的深度值进行比较。如果新像素深度值<深度缓存深度值,则新像素值会取代原先的;反之,新像素值被遮挡,其颜色值和深度将被丢弃。(深度主要起的是比较的作用)什么是深度测试?
在深度测试中,默认情况是将要绘制的新像素的z值与深度缓冲区中对应位置的z值进行比较,如果比深度缓存中的值小,那么用新像素的颜色值更新深度缓存中对应像素的颜色值。为什么需要深度?
在不使用深度测试的时候,如果我们先绘制一个距离较近的物体,再绘制距离较远的物体,则距离远的物体因为后绘制,会把距离近的物体覆盖掉,这样的效果并不是我们所希望的。而有了深度缓冲以后,绘制物体的顺序就不那么重要了,都能按照远近(Z值)正常显示,这很关键。
那么,在unity中,如果知道了渲染队列,ZWrite,ZTest,如何确定哪个物体先显示呢?
首先,unity先将渲染队列中较前的进行渲染,然后再执行ZWrite,ZTest
ZWrite可以取的值为:On/Off,默认值为On,代表是否要将像素的深度写入深度缓存中(同时还要看ZTest是否通过)。
ZTest可以取的值为:Greater/GEqual/Less/LEqual/Equal/NotEqual/Always/Never/Off,默认值为LEqual,代表通过比较深度来更改颜色缓存的值。例如当取默认值的情况下,如果将要绘制的新像素的z值小于等于深度缓存中的值,则将用新像素的颜色值更新深度缓存中对应像素的颜色值。
需要注意的是,当ZTest取值为Off时,表示的是关闭深度测试,等价于取值为Always,而不是Never!Always指的是直接将当前像素颜色(不是深度)写进颜色缓冲区中;而Never指的是不要将当前像素颜色写进颜色缓冲区中,相当于消失。
那么,重点来了:
1. 当ZWrite为On时,ZTest通过时,该像素的深度才能成功写入深度缓存,同时因为ZTest通过了,该像素的颜色值也会写入颜色缓存。
2. 当ZWrite为On时,ZTest不通过时,该像素的深度不能成功写入深度缓存,同时因为ZTest不通过,该像素的颜色值不会写入颜色缓存。
3. 当ZWrite为Off时,ZTest通过时,该像素的深度不能成功写入深度缓存,同时因为ZTest通过了,该像素的颜色值会写入颜色缓存。
4. 当ZWrite为Off时,ZTest不通过时,该像素的深度不能成功写入深度缓存,同时因为ZTest不通过,该像素的颜色值不会写入颜色缓存。
可以看到,像素的深度能否成功写入深度缓存,条件是ZWrite为On,ZTest通过;
写入深度缓存的作用就是为ZTest的比较做准备。
因为ZWrite默认值为On,ZTest默认值为LEqual,所以这很好地解释了为什么在unity中,距离相机近的东西会阻挡住距离相机远的东西。如果我们先绘制一个距离较近的物体,再绘制距离较远的物体,则距离远的物体因为后绘制,会把距离近的物体覆盖掉,这时我们可以通过修改ZWrite和ZTest来改变物体的遮挡关系!
参考链接:
1. [UnityShader]渲染队列、ZWrite和ZTest
2. 建物に遮蔽されたプレイヤーをシルエット表示する
以上是关于摄像机与主角之间遮挡显示处理(Unity3D开发之二十八)的主要内容,如果未能解决你的问题,请参考以下文章
Unity3D日常开发实现角色移动行走之CharacterController组件
[Unity3D 版本5.X]实现一个跟随摄像机,聚焦到客户端主角身上
Unity3D场景性能优化/渲染/卡顿/搭建优化 遮挡剔除/层消距离技术/LOD(多层次细节)