刚好在demo中测试了一下深度图实现的扫描效果,就把这篇当笔记记录一下了,免得集成到我的游戏那会赶时间来不及写,csdn博客已经变成了我的有道云笔记,嘿巴扎黑。

      场景扫描这个效果其实很实用,塞尔达传说荒野之息就将三大技能的前置效果都用上了深度图扫描。

      原理也比较好理解,特别是了解了深度图以后。首先我们手上有一张camera主纹理渲染图,一张camera深度图,它们出自同一个camera所以uv映射匹配,那么我们可以得到深度图中每个像素的深度(当然要经过Linear01Depth处理成线性深度值),同时我们使用一个_Scan扫描深度值,对每个像素深度进行“扫描查询”,也就是进行约等于判断,当约等于时,就混合一个_ScanColor,那么就实现了我们想要的深度扫描效果,shader代码如下:

      

Shader "Unlit/DepthScanShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
		_Scan("Scan",Range(0,1)) = 0
		_Appro("Scan Approximate",Range(0,0.05)) = 0.01
		_ScanColor("Scan Color",Color) = (0,1,0,1)
		_Weight("Scan Color Weight",Range(0,1)) = 0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

			uniform sampler2D _CameraDepthTexture;

            sampler2D _MainTex;		/*接受camera的渲染主纹理*/
            float4 _MainTex_ST;

			float _Scan;			/*扫描的当前深度值*/
			float _Appro;			/*我们不能直接用值相等判断,要用约等于近似判断,这里是近似值*/
			float4 _ScanColor;		/*扫描到的深度的混合颜色*/
			float _Weight;			/*混合权重*/

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

			//约等于判断
			bool isScanApproximate(float depth, float scan, float appro)
			{
				if (depth<scan + appro && depth>scan - appro)
					return true;
				return false;
			}

			//颜色权重混合
			fixed4 blendColor(fixed4 col, fixed4 scol, float wei)
			{
				return col * (1 - wei) + wei * scol;
			}

            fixed4 frag (v2f i) : SV_Target
            {
				//采样camera渲染主纹理
                fixed4 col = tex2D(_MainTex, i.uv);
				//获取线性0-1的depth值
				float depth = Linear01Depth(tex2D(_CameraDepthTexture, i.uv));
				//判断当前片段的depth值约等于_Scan值,则给当前颜色叠加一个_ScanColor
				if (isScanApproximate(depth, _Scan, _Appro))
				{
					col = blendColor(col, _ScanColor, _Weight);
				}
                return col;
            }
            ENDCG
        }
    }
}

      c#代码则和上一篇博客中深度图渲染使用一样,我就不贴了。shader中_MainTex和_CameraDepthTexture的贴图unity都会帮我们自动传递camera渲染出来的主纹理和深度纹理,且uv匹配,直接使用即可,然后在片段函数中进行“深度判断”,约等于当前_Scan的深度区域则混合我们设置的_ScanColor。简单明了,效果如下:

      C for Graphic:深度图应用(扫描)

     接下来我实现一下塞尔达的效果简版,因为塞尔达的那种扫描效果本身是很多效果的叠加,我这里只针对深度图的扫描应用实现,如下:

     

Shader "Unlit/DepthZeldaShader"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white" {}
		_Scan("Scan",Range(0,1)) = 0
		_Appro("Scan Approximate",Range(0,0.3)) = 0.01
		_ScanColor("Scan Color",Color) = (0,1,0,1)
		_Weight("Scan Color Weight",Range(0,1)) = 0
	}
		SubShader
		{
			Tags { "RenderType" = "Opaque" }
			LOD 100

			Pass
			{
				CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag

				#include "UnityCG.cginc"

				struct appdata
				{
					float4 vertex : POSITION;
					float2 uv : TEXCOORD0;
				};

				struct v2f
				{
					float2 uv : TEXCOORD0;
					float4 vertex : SV_POSITION;
				};

				uniform sampler2D _CameraDepthTexture;

				sampler2D _MainTex;
				float4 _MainTex_ST;

				float _Scan;
				float _Appro;
				float4 _ScanColor;
				float _Weight;

				v2f vert(appdata v)
				{
					v2f o;
					o.vertex = UnityObjectToClipPos(v.vertex);
					o.uv = TRANSFORM_TEX(v.uv, _MainTex);
					return o;
				}

				bool isScanApproximate(float depth, float scan, float appro)
				{
					if (depth <= scan && depth > (scan - appro))
						return true;
					return false;
				}

				fixed4 blendColor(fixed4 col, fixed4 scol, float wei)
				{
					return col * (1 - wei) + wei * scol;
				}

				fixed4 frag(v2f i) : SV_Target
				{
					fixed4 col = tex2D(_MainTex, i.uv);
					float depth = Linear01Depth(tex2D(_CameraDepthTexture, i.uv));
					if (depth < 1)
					{
						col = blendColor(col, _ScanColor, _Weight);
					}
					if (isScanApproximate(depth, _Scan, _Appro))
					{
						col = blendColor(col, _ScanColor, _Weight * (1 - (_Scan - depth) / _Appro));
					}
					return col;
				}
			ENDCG
			}
		}
}

   效果如下:

   C for Graphic:深度图应用(扫描)

    当然了,深度图还可以实现很多种其他的实用效果,后面我再写几篇深度图的应用。

相关文章:

  • 2021-04-22
  • 2021-06-16
  • 2022-12-23
  • 2022-12-23
  • 2021-12-26
  • 2021-12-26
  • 2021-05-28
猜你喜欢
  • 2021-06-10
  • 2021-05-25
  • 2022-02-12
  • 2021-10-06
  • 2021-12-03
  • 2021-04-05
  • 2022-12-23
相关资源
相似解决方案