Unity SurfaceShader遮挡处理(XRay)和处理XRay失效问题

本文Xray shader是在SurfaceShader基础上写

代码一般都想着复用,我把这个Xray写成一个pass

根据usepass来加Xray shader功能

首先理解一下深度和深度测试

(1)什么是深度?

 深度其实就是该像素点在3d世界中距离摄像机的距离。离摄像机越远,则深度值(Z值)越大。

(2)什么是深度缓存?

深度缓存中存储着准备要绘制在屏幕上的像素点的深度值。如果启用了深度缓冲区,在绘制每个像素之前,OpenGL会把该像素的深度值和深度缓存的深度值进行比较。如果新像素深度值<深度缓存深度值,则新像素值会取代原先的;反之,新像素值被遮挡,其颜色值和深度将被丢弃。(深度主要起的是比较的作用)

(3)什么是深度测试?

在深度测试中,默认情况是将要绘制的新像素的z值与深度缓冲区中对应位置的z值进行比较,如果比深度缓存中的值小,那么用新像素的颜色值更新深度缓存中对应像素的颜色值。

(4)为什么需要深度?

在不使用深度测试的时候,如果我们先绘制一个距离较近的物体,再绘制距离较远的物体,则距离远的物体因为后绘制,会把距离近的物体覆盖掉,这样的效果并不是我们所希望的。而有了深度缓冲以后,绘制物体的顺序就不那么重要了,都能按照远近(Z值)正常显示,这很关键。

 

很显然Xray Shader不需要深度缓存,只需要深度测试,比较像素,shader里面写上这两句

zwrite off 不开启深度

ztest greater 深度测试比较

效果图

下面完整的xray Pass

Shader "XRay/XRay" 
{
	Properties
	{
		_RayColor("RayColor", Color) = (1, 0, 0, 0.5)
		_RayIntensity("Intensity", Range(0, 2)) = 0
	}

	SubShader
	{
		pass
		{
			Name "XRAY"
			Blend SrcAlpha One
			zwrite off
			ztest greater

			Stencil
			{
				Ref 254
				Comp NotEqual
				Pass Keep
				ZFail Keep
			}

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag 
			#pragma target 3.0
			#include "UnityCG.cginc"

			fixed4 _RayColor;
			float _RayIntensity;

			struct v2f
			{
				float4 pos:POSITION;
				float4 color : COLOR;
			};


			v2f vert(appdata_base v) 
			{
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				float3 viewDir = normalize(ObjSpaceViewDir(v.vertex));//计算出顶点到相机的向量
				float val = 1 - saturate(dot(v.normal, viewDir));//计算点乘值
				o.color = _RayColor * val * (1 + _RayIntensity);//计算强度
				return o;
			}

			float4 frag(v2f IN) :color
			{
				float4 col = IN.color;
				return col;
			}
			ENDCG
		}
	}
	FallBack "Diffuse"
}

然后我们添加一个SurfaceShader

在属性那里添加

        _RayColor("RayColor", Color) = (1, 0, 0, 0.6)
        _RayIntensity("Intensity", Range(0, 2)) = 0

这个为了控制pass里面的变量

最后在SubShader添加UsePass "XRay/XRay/XRAY",这样子就可以使用xray

不过我在项目中遇到

Shader "Custom/NewSurfaceShader" {
	Properties {
		_Color ("Color", Color) = (1,1,1,1)
		_MainTex ("Albedo (RGB)", 2D) = "white" {}
		_Glossiness ("Smoothness", Range(0,1)) = 0.5
		_Metallic ("Metallic", Range(0,1)) = 0.0
		_RayColor("RayColor", Color) = (1, 0, 0, 0.6)
		_RayIntensity("Intensity", Range(0, 2)) = 0
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200

		UsePass "XRay/XRay/XRAY"

		CGPROGRAM
		// Physically based Standard lighting model, and enable shadows on all light types
		#pragma surface surf Standard fullforwardshadows

		// Use shader model 3.0 target, to get nicer looking lighting
		#pragma target 3.0

		sampler2D _MainTex;

		struct Input {
			float2 uv_MainTex;
		};

		half _Glossiness;
		half _Metallic;
		fixed4 _Color;

		// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
		// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
		// #pragma instancing_options assumeuniformscaling
		UNITY_INSTANCING_BUFFER_START(Props)
			// put more per-instance properties here
		UNITY_INSTANCING_BUFFER_END(Props)

		void surf (Input IN, inout SurfaceOutputStandard o) {
			// Albedo comes from a texture tinted by color
			fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
			o.Albedo = c.rgb;
			// Metallic and smoothness come from slider variables
			o.Metallic = _Metallic;
			o.Smoothness = _Glossiness;
			o.Alpha = c.a;
		}
		ENDCG
	}
	FallBack "Diffuse"
}

不过在项目中遇到过摄像机远的时候XRay生效,靠近障碍物的时候就失效

摄像机远的情况

看看FrameDebug里面的深度

摄像机近的情况

看看深度

然后看看镜头拉近之后遮挡物件和xray的深度

可以看出来还是深度不一致影响深度测试

 

引起这个问题因为美术那边把多个跨度大的场景物件合成一个引起,解决方案最好把xray物体的渲染队列提高

Shader修改

Tags { "RenderType"="Opaque" "Queue" = "Geometry+100" }

这样子就可以解决这个问题

猜你喜欢

转载自blog.csdn.net/SnoopyNa2Co3/article/details/81942805