Unity에서 Depth Texture의 사용

반응형



1. 깊이값 : 뷰 공간에서 원점(카메라 위치)와 정점간의 거리

v2f vert (appdata_base v) 

{

v2f o;

o.pos = mul (UNITY_MATRIX_MVP, v.vertex);

// x is 1.0 (or –1.0 if currently rendering with a flipped projection matrix), 

// y is the camera’s near plane, z is the camera’s far plane and w is 1/FarPlane.

o.depth = length(mul(UNITY_MATRIX_MV, v.vertex))* _ProjectionParams.w;

return o;

}

half4 frag(v2f i) : SV_Target 

{

return fixed4(i.depth, i.depth, i.depth, 1);

}




2. 깊이값 : 투영공간에서 z 또는 w 값

o.depth = mul(UNITY_MATRIX_MVP, v.vertex).z * _ProjectionParams.w;



1번2번.zip



3. 유니티 에서는 깊이텍스처를 바로 접근하여 사용할 수 있다.

아래 링크 중 unity doc를 보면 사용방법을 알 수 있다.

ShaderTest.cs

void Start()

{

    this.GetComponent<Camera>().depthTextureMode = DepthTextureMode.Depth;

}


void OnRenderImage(RenderTexture source, RenderTexture destination)

{

    Graphics.Blit(source, destination, mat);

}


ShaderTesht.shader

sampler2D _CameraDepthTexture;

v2f vert (appdata_base v)

{

   v2f o;

   o.pos = mul (UNITY_MATRIX_MVP, v.vertex);

   o.scrPos=ComputeScreenPos(o.pos);   


   return o;

}


위에서 CumputeScreenPos이라는 빌트인 함수가 있다.


inline float4 ComputeScreenPos (float4 pos) {

float4 o = pos * 0.5f;

#if defined(UNITY_HALF_TEXEL_OFFSET)

o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w * _ScreenParams.zw;

#else

o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w;

#endif

o.zw = pos.zw;

return o;

}

여기서 _ProjectionParams의 x값은 부호에 따라 1 또는 -1이 된다.

그리고 _ScreenParams.zw는 각각 1+1/width 와 1+1/height가 된다.

이 값들에 대한 설명은 이곳을 보면 된다.

w는 1로 생각하고 오프셋을 설정하여 식을 간략화 하면

float4 o = pos * 0.5f;

o.xy = float2(o.x, o.y) + _ScreenParams.zw;

위 두 식을 하나로 합치면 아래와 같이 된다.

o.scrPos.xy = o.pos.xy * 0.5 + _ScreenParams.zw*0.5;

여기서 _ScreenParams에 값을 대입하자

o.scrPos.xy = o.pos.xy * 0.5 +  float2(1+1/width, 1+1/height)*0.5;


내가 만들어서 쓰던 함수는 아래와 같다.

inline float4 CustomScreenPos (float4 pos) 

{

float4 o = pos;

// x, y, z 값을 w로 나누어 w는 1이되게 하고 xyz는 -1~1의 범위를 갖게 한다. NDC 

        // _MainTex_TexelSize.xy = 1/width, 1/height 이다

o.xy = (o.xy+_MainTex_TexelSize.xy) / o.w;

o.xy = float2(o.x+1, o.y+1) * 0.5; // -1~1 범위를 0~1로 변경

return o;

}

위 식도 간략화 해 보면 위와 같다.

결론적으로 보자면 w로 나누어서 perspective division을 거쳐서 -1~1의 범위로 만들고

다시 텍스처 좌표를 위해 0~1의 범위로 만든다.

다만 중간에 픽셀과 텍셀의 오프셋을 좀 추가해 준 것이다.


half4 frag (v2f i) : COLOR

{

   float depthValue = Linear01Depth (tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.scrPos)).r);

   half4 depth;


   depth.r = depthValue;

   depth.g = depthValue;

   depth.b = depthValue;


   depth.a = 1;

   return depth;

}

_CameraDepthTextureShader Variables 대한 설명은 이곳을 참고하면 된다.

유니티에서는 깊이텍스쳐가 전역 변수 속성으로 셰이더에서 샘플링 할 수 있는데,

셰이더에서 sample로사용하기 위해 선언되어진 이름이 _CamDepthTexture이다.

_CameraDepthTexture는 항상 카메라의 첫번째 깊이 텍스처을 참조하지만,

그와 반대로 _LastDepthTexture는 어떤카메라에서든 렌더되어진

마지막 깊이 텍스처를 참조한다.

이는 절반해상도의 깊이 텍스처를 스크립트에서 만들어서 두번째 카메라에서

사용하여 후처리 셰이더가 가능하게 하도록 하는데 유용하다.


그리고 텍스처에서 읽어오 값(depth)를 0~1 값으로 보간하기 위해

Linear01Depth라는 함수를 사용한다.


3번.zip


위 코드는 이 링크에서 참고하였다.




4.


참고 링크 

Unity Doc, Depth Textures의 사용

- Unity Doc, 카메라의 깊이 텍스처

- Fun with Shaders and the Depth Buffer

- Unit Doc, built in shader variables

- http://mgun.tistory.com/1663

- z버퍼란?


'Unity > Unity Graphics' 카테고리의 다른 글

Depth and Normal Textures (Part 3)  (0) 2016.07.24
Depth and Normal Texture (Part 2)  (0) 2016.06.13
Depth and Normal Texture (Part 1)  (2) 2016.04.29
#pragma multi_compile  (0) 2016.04.23
Performance Tips when Writing Shaders  (0) 2016.04.15
TAGS.

Comments