一 簡介
1.1 啥是深度圖
深度圖通過獲取觀察視角中,物體由近到遠的深度信息,來實現與其相關的特殊效果。
深度值是在像素信息中保存的[0,1]範圍的非線性值,這些深度值來自裁剪座標。Unity會自動利用Shader Replacement將RenderType爲Opaque、渲染隊列小於等於2500並且有ShadowCaster Pass的物體的深度值渲染到深度圖中。
1.2 深度圖可以實現的效果
- 垂直霧效
- 能量護盾
- 掃描線
- 卡通描邊
- 運動模糊
- 等等
二 深度圖的簡單實現
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"
}
就完成了