unity shaderlab 深度圖的實現過程 代碼+詳細註釋

一 簡介

1.1 啥是深度圖

深度圖通過獲取觀察視角中,物體由近到遠的深度信息,來實現與其相關的特殊效果。
深度值是在像素信息中保存的[0,1]範圍的非線性值,這些深度值來自裁剪座標。Unity會自動利用Shader Replacement將RenderType爲Opaque、渲染隊列小於等於2500並且有ShadowCaster Pass的物體的深度值渲染到深度圖中。

1.2 深度圖可以實現的效果
  1. 垂直霧效
  2. 能量護盾
  3. 掃描線
  4. 卡通描邊
  5. 運動模糊
  6. 等等

二 深度圖的簡單實現

2.1 獲取像素深度信息

向前渲染和延遲渲染中獲取深度信息的方式各有不同。

2.1.1【延遲渲染獲取深度信息】

由於延遲渲染是先經過深度測試再處理燈光,所以像素緩衝區中已經有了深度信息。除了延遲渲染的相關設置外,無需任何多餘設置即可直接在shader中使用

2.1.2【正向渲染獲取深度信息】

在向前渲染中,必須先通過以下步驟用攝像機獲取圖像的像素與深度信息,才能在shader中使用

【步驟】新建c#腳本,將以下代碼放置到腳本中,並將腳本賦給攝像機。
相機渲染圖像後會調用腳本中的OnRenderImage方法。通過調用Graphics.Blit方法將已經渲染的RenderTexture source用指定或默認的shader pass處理並通過RenderTexture destination輸出

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//需要Camera組件
[RequireComponent(typeof (Camera))]
public class cameraDepth : MonoBehaviour
{
    public Material cameraMaterial;  
    void Start () {  
        Camera camera = gameObject.GetComponent<Camera> ();
        //設置Camera的depthTextureMode,生成深度圖
        camera.depthTextureMode = DepthTextureMode.Depth;  
    }  

    //OnRenderImage在所有的渲染完成後調用
    //該函數允許我們處理渲染後的圖像,輸入原圖像source,輸出的圖像desitination
    void OnRenderImage (RenderTexture source, RenderTexture destination){  
        //如果指定了cameraMaterial  就用cameraMaterial處理輸出的圖像,否則就用輸入的原圖像用作輸出
        if (cameraMaterial != null)
        {
            //該方法用於將輸入的圖像指定material和shader pass 後輸出
            Graphics.Blit(source, destination, cameraMaterial);
        }
        else
        {
            Graphics.Blit(source, destination);
        }
    } 
}

2.2 Shader中使用深度信息

新建Shader腳本,將以下代碼放置到腳本中。新建Material並指定好剛剛新建的Shader,賦給物體


Shader "Custom/Depth" {  
    SubShader {  
        Tags { "RenderType"="Opaque" }  
          
        Pass{  
            CGPROGRAM  
            // 定義頂點、片片渲染器,並引入shader相關的宏
            #pragma vertex vert  
            #pragma fragment frag  
            #include "UnityCG.cginc"  
            // 聲明貼圖變量,用於接受攝像機的貼圖
            sampler2D _CameraDepthTexture;  
            // 片元渲染器的輸入結構 
            struct v2f {  
                // 像素的座標
                float4 pos : SV_POSITION;  
                float3 uv:TEXCOORD0;
                // 屏幕座標
                float4 screenPos:TEXCOORD1;  
            };  
              
            //頂點渲染器
            v2f vert (appdata_base v){  
               v2f o;  
               // 將頂點座標模型空間轉爲裁剪空間
               o.pos = UnityObjectToClipPos (v.vertex);  
               // 使用ComputeScreenPos計算出屏幕座標
               // 輸入裁剪空間的位置,獲取齊次空間的屏幕座標。(不是最終輸出的屏幕座標)
               o.screenPos = ComputeScreenPos(o.pos);  
               o.uv = v.texcoord;
               return o;  
            }  
              
            //片元渲染器
            half4 frag (v2f i) : COLOR{  
                // 計算出投影紋理座標
                half4 proj =UNITY_PROJ_COORD(i.screenPos);
                //tex2D和tex2Dproj的區別在於:tex2Dproj會先將第二個參數除以它的最後一個分量。 
                //要想進行深度值對比,只有先存儲深度值。在生成ShadowMap時存儲深度值,然後無論用tex2D還是tex2Dproj都可以得到深度值。
                half4 _tex2Dproj = tex2Dproj(_CameraDepthTexture, proj);
                //LinearEyeDepth負責把深度紋理的採樣結果轉換到視角空間下的深度值
                //Linear01Depth則返回一個範圍在[0,1]的線性深度值
                half depthValue = Linear01Depth(_tex2Dproj.r);  

                // float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
	            // float depthValue = Linear01Depth(depth);

                return half4(depthValue, depthValue, depthValue, 1);   
            }  
            ENDCG  
        }  
    }  
    // 這個必須要有。失敗的時候嘗試調用Diffuse subshader
    FallBack "Diffuse" 
}  

就完成了
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章