Depth Buffer. Z-Buffer라고도 하며 카메라 기준으로 픽셀의 깊이 정보를 뜻합니다, 

위 사진은 해당 정보를 시각화 하여 출력한 결과입니다.

 

Depth Buffer를 이용해 Soft Particle이나 Depth of Field효과 만들 수 있습니다.

 

 

 


Depth Buffer 후처리 쉐이더

Shader "Hidden/PP_DepthBuffer"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
		_DepthDistance("DepthDistance", float) = 25
    }
    SubShader
    {
        Cull Off 
		ZWrite Off 
		ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

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

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

            sampler2D _MainTex;
			float4 _MainTex_TexelSize;

			sampler2D_float _CameraDepthTexture;	//! 카메라로부터 뎁스텍스처를 받아옴
			half _DepthDistance;

            fixed4 frag (v2f i) : SV_Target
            {
				float fDepthData = tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(float4(i.uv, 1, 1))).r;	//! 텝스텍스처 샘플러에서 텍셀정보를 가져옴
				float fSceneZ = LinearEyeDepth(fDepthData);		//! DepthData를 0~1 Linear데이터로 변환(0 = 카메라, 1 = 먼거리)
				float fCalc_Depth = 1 - saturate(fSceneZ / _DepthDistance);		//! 거리 값 조절용 계산
				return fCalc_Depth;
            }
            ENDCG
        }
    }
}

 

뎁스버퍼 후처리 쉐이더입니다.

해당 쉐이더 적용 방법은 이전 포스팅을 참고해 주시길 바랍니다.

 

https://darkcatgame.tistory.com/78?category=814684

 

Custom PostProcess 쉐이더 제작 & 적용

PostProcess는 한글로 후처리라고 하며 기본 렌더링 과정이 다 끝나고 UI렌더링 이전 까지의 렌더된 버퍼 데이터를 이용해 이펙트를 적용시키는 기술입니다. 유니티의 Postprocess v2 에셋을 이용해 기본 효과들..

darkcatgame.tistory.com

 

 

sampler2D_float _CameraDepthTexture;에는 뎁스 버퍼 정보가 들어오는데 이게 가능하기 위해서는 

렌더링 패쓰가 Deffered로 되어있거나 DepthTextureMode를 활성화 시켜야합니다.

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

[ExecuteInEditMode]
public class CameraDepthOn : MonoBehaviour
{
    void OnEnable()
    {
        Camera pCamera = GetComponent<Camera>();
        if (pCamera == null) return;
        Debug.Log("Depth On");
        pCamera.depthTextureMode = DepthTextureMode.DepthNormals;

    }

    void OnDisable()
    {
        Camera pCamera = GetComponent<Camera>();
        if (pCamera == null) return;
        Debug.Log("Depth Off");
        pCamera.depthTextureMode = DepthTextureMode.None;
    }
}

해당 C#코드를 카메라에 적용시키면 됩니다.

 

 


간단한 Depth of Field 구현하기

Shader "Hidden/PP_DepthBuffer"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white" {}
		_DepthDistance("DepthDistance", float) = 25
		_BlurIntensity("_BlurIntensity", Range(2, 10)) = 4
	}
		SubShader
		{
			Cull Off
			ZWrite Off
			ZTest Always

			Pass
			{
				CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag

				#include "UnityCG.cginc"

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

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

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

				sampler2D _MainTex;
				float4 _MainTex_TexelSize;

				sampler2D_float _CameraDepthTexture; //! 카메라로부터 뎁스텍스처를 받아옴
				half _DepthDistance;
				half _BlurIntensity;

				fixed4 frag(v2f i) : SV_Target
				{
					float4 fMainTex = tex2D(_MainTex, i.uv);

					_BlurIntensity = ceil(_BlurIntensity);				//! 텍스처 블러
					float4 fBlurTex = 0;
					for (int u = -_BlurIntensity; u <= _BlurIntensity; u++)
					{
						for (int v = -_BlurIntensity; v <= _BlurIntensity; v++)
						{
							float2 o = float2(u, v) * _MainTex_TexelSize.xy;
							fBlurTex += tex2D(_MainTex, i.uv + o);
						}
					}
					fBlurTex *= 1.0f / pow((_BlurIntensity * 2.0f), 2);

					float fDepthData = tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(float4(i.uv, 1, 1))).r;	//! 텝스텍스처 샘플러에서 텍셀정보를 가져옴
					float fSceneZ = LinearEyeDepth(fDepthData);		//! DepthData를 0~1 Linear데이터로 변환(0 = 카메라, 1 = 먼거리)
					float fCalc_Depth = 1 - saturate(fSceneZ / _DepthDistance);		//! 거리 값 조절용 계산
					//return fCalc_Depth;
					return lerp(fBlurTex, fMainTex, saturate(fCalc_Depth));		//! 뎁스데이터를 이용해 일반 텍스처랑 블러 텍스처 lerp
				}
				ENDCG
			}
		}
}

 

뎁스 버퍼를 이용해 간단하게 DOF효과를 구현했습니다.

 

원리는 간단합니다.

이전에 구현한 뎁스버퍼를 통해 0~1로 뎁스 데이터를 얻었습니다.

 

일반 텍스처와 블러텍스처를 뎁스값으로 lerp 계산하여 구현했습니다.

 

 

 


추가 정보 & 의문

 

float fDepthData = tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(float4(i.uv, 1, 1))).r;

위 코드는 뎁스텍스처 샘플링할때 사용했던 코드입니다, 구글링하면 대부분 자료가 해당 코드를 이용하는데

분석해보면 후처리 단계에서는 어차피 화면이미지 자체를 이용하는데 프로젝션 계산이 무슨 의미가 있나 싶어서

 

float fDepthData = tex2D(_CameraDepthTexture, i.uv).r;

위 코드로 변경했더니 결과는 같았습니다.

 

추측상 tex2Dproj를 사용해야 될 때는 일반 오브젝트 픽셀 쉐이더에서 Soft Particle이나 데칼을 구현 할 때 뎁스버퍼가 필요한데 해당 뎁스 버퍼의 텍셀정보를 가져오기 위해서는 스크린UV로 프로젝션 행렬로 텍셀정보를 가져오기 위해 사용하는 것으로 생각됩니다.

 


WRITTEN BY
CatDarkGame
Technical Artist dhwlgn12@gmail.com

,