Unity Shader学习笔记(5)基于摄像机深度和法线的后处理描边效果

本文档详细介绍了使用Unity中的Shader实现边缘检测和深度感知的步骤,包括摄像机脚本和Shader代码。通过调整参数,可以控制边缘颜色、背景颜色、采样距离等,以达到理想的效果。该技术可用于游戏开发中的视觉效果增强。
摘要由CSDN通过智能技术生成
文章目标 :

主要参考书籍为《Unity Shader入门精要》,本文主要注重于整理,方便后续直接调用。

渲染效果图:

后处理渲染边缘

主要相关代码:
摄像机脚本文件:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace UnityShaderLearnPostImageEffects
{
    class EdgeDetectNormalsAndDepth : PostEffectsBase
    {
        public Shader edgeDectectShader = null;
        private Material edgeDectectMaterial = null;

        [Range(0, 1)]
        public float edgesOnly = 0f;
        public Color edgeColor = Color.black;
        public Color backgroundColor = Color.white;
        [Range(0f, 0.004f)]
        public float sampleDistance = 0.001f;
        public float sensitivityDepth = 1.0f;
        public float sensitivityNormals = 1.0f;

        private void OnEnable()
        {
            GetComponent<Camera>().depthTextureMode |= DepthTextureMode.DepthNormals;
        }

        public Material material
        {
            get
            {
                edgeDectectMaterial = CheckShaderAndCreateMaterial(edgeDectectShader, edgeDectectMaterial);
                return edgeDectectMaterial;
            }
        }

        //[ImageEffectOpaque] //仅对不透明物体产生作用,在透明物体渲染之前执行 OnRenderImage 函数;
        private void OnRenderImage(RenderTexture src, RenderTexture dest)
        {
            if (material != null)
            {
                material.SetFloat("_EdgeOnly", edgesOnly);
                material.SetColor("_EdgeColor", edgeColor);
                material.SetColor("_BackgroundColor", backgroundColor);
                material.SetFloat("_SampleDistance", sampleDistance);
                material.SetVector("_Sensitivity", new Vector4(sensitivityNormals, sensitivityDepth, 0, 0));
                Graphics.Blit(src, dest, material);
            }
            else
            { 
                Graphics.Blit(src, dest);
            }

        }
    }
}

Shader 文件代码:
//参考文件:《Unity Shader 入门精要》
//整理制作:嘿皮土豆
//渲染管线:默认渲染管线
Shader "UnityShaderLearn/EdgeDetectNormalsAndDepth"
{
    Properties
    {
        _MainTex("MainTex", 2D) = ""{}
        _EdgeOnly("EdgeOnly", float) = 1
        _EdgeColor("EdgeColor", color) = (0,0,0,1)
        _BackgroundColor("BackgroundColor", Color) = (1,1,1,1)
        _SampleDistance("SampleDistance", Range(0,0.004)) = 0.001
        _Sensitivity("Sensitivity", vector) = (1,1,1,1)
    }
    Subshader
    {
        CGINCLUDE
            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed _EdgeOnly;
            fixed4 _EdgeColor;
            fixed4 _BackgroundColor;
            float _SampleDistance;
            float4 _Sensitivity;
            sampler2D _CameraDepthNormalsTexture;

            struct v2f
            {
                float4 pos : SV_POSITION;
                half2 uv[5] : TEXCOORD0;
            };

            half CheckSame(half4 center, half4 sample)
            {
                float2 centerNormal = center.xy;
                float2 centerDepth = DecodeFloatRG(center.zw);
                float2 sampleNormal = sample.xy;
                float2 sampleDepth = DecodeFloatRG(sample.zw);

                float2 diffNormal = abs(centerNormal - sampleNormal) * _Sensitivity.x;
                int isSameNormal = (diffNormal.x + diffNormal.y) < 0.1;

                float2 diffDepth = abs(centerDepth - sampleDepth) * _Sensitivity;
                int isSameDepth = diffDepth < 0.1 * centerDepth;

                return isSameDepth * isSameNormal ? 1 : 0;

            }

            v2f vert (appdata_img v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                half2 uv = v.texcoord;
                o.uv[0] = uv;

                #if UNITY_UV_STARTS_AT_TOP
                if(_MainTex_ST.y < 0)
                uv.y = 1-uv.y;
                #endif

                o.uv[1] = uv+_MainTex_ST.xy* half2(1,1) * _SampleDistance;
                o.uv[2] = uv+_MainTex_ST.xy* half2(-1,-1) * _SampleDistance;
                o.uv[3] = uv+_MainTex_ST.xy* half2(-1,1) * _SampleDistance;
                o.uv[4] = uv+_MainTex_ST.xy* half2(1,-1) * _SampleDistance;

                return o;
            }

            fixed4 frag (v2f i) : SV_TARGET
            {
                half4 sample1 = tex2D(_CameraDepthNormalsTexture, i.uv[1]);
                half4 sample2 = tex2D(_CameraDepthNormalsTexture, i.uv[2]);
                half4 sample3 = tex2D(_CameraDepthNormalsTexture, i.uv[3]);
                half4 sample4 = tex2D(_CameraDepthNormalsTexture, i.uv[4]);

                half edge = 1;

                edge *= CheckSame(sample1, sample2);
                edge *= CheckSame(sample3, sample4);

                fixed4 withEdgeColor = lerp(_EdgeColor, tex2D(_MainTex,i.uv[0]), edge);
                fixed4 onlyEdgeColor = lerp(_EdgeColor, _BackgroundColor, edge);

                return lerp(withEdgeColor, onlyEdgeColor, _EdgeOnly);
            }
        ENDCG

        pass
        {
            ZTest Always
            Cull Off
            ZWrite Off

            CGPROGRAM
                
                #pragma vertex vert
                #pragma fragment frag

            ENDCG
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘿皮土豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值