Depth and Normal Texture (Part 2)

반응형

이전 글 : Depth and Normal Texture (Part 1)

원문 : Depth and Normal Texture (Part 2)


이 글은 이전 글에 연속되는 글이다.

이 글은 총 세개의 글로 이루어져 있고 depth 와 normal 텍스쳐들을 다룬다.


Depth Texture 작업

이제 우리는 어떻게 깊이텍스처를 얻는지 배웠고, 그 값을 흑백 이미지로 출력했으니,

이걸로 좀 더 재미있는걸 해 보자.

Quanturm Conundrum의 차원 이동 효과에서 환경을 거쳐가는 빛의 링을 

간단한 버전으로 만들어 볼 예정이다.

어디서든 내가 바라보는곳의 중간지점에서 시작하는 것 대신에 내가 볼 수 있는

가장 먼 곳에서 시작해서 연속적으로 증가해서 카메라를 지나가게 만들거다.

추가로, 링이 오브젝트들을 지나가면 살짝 컬러색을 넣는다.


아래 이미지가 결과 화면이다.




Post Processing 전의 렌더된 이미지 얻기

우리가 만들려는 이미지는 카메라에서 그려진 이미지 위에 덮여질 것이다.

그래서 어떤 특수효과가 적용되기 전에 카메라에서 렌더링 된 직후의 이미지를 

얻어와야 할 필요가 있다.

이를 위해, shader에서 Properties 구문을 사용할 거다.

카메라로부터 그려진 이미지는 _MainTex라는 이름으로 들어온다.

Properties {
   _MainTex ("", 2D) = "white" {}
}


또한 shader에서 pass에서 변수이름을 알기 위해 아래와 같이 써 준다.

sampler2D _MainTex;

Time

효과가 움직일려면 시간값이 필요하다.

다행히도 유니티에 빌트인된 float4 _Time : Time(t/20, t, t*2, t*3) 값을 사용할 수 있다.

4개의 float형을 가진 float4를 사용하는 _Time 이라는 이름의 프로퍼티이다.

x는 t/20을 가지며 이는 보이는 것 그대로 time값을 20으로 나눈 것이다.

그 다음은 차례대로 time값, time값을 2로 곱한값, time값을 3으로 곱한값이다.


지금의 경우에는 0에서 1로 진행되는 값이 필요하다.

아래의 코드에서, _RingPassTimeLength 는 화면을 가로지르는 시간이다.

_StartingTime 는 처음으로 링이 움직일 때의 시간이고 _Time.y는 현재 순간의 시간이다.

float _RingPassTimeLength = 2;
float t = 1 - ((_Time.y - _StartingTime)/_RingPassTimeLength );

링이 처음으로 움직일 때, 시작 시간이 현재시간이므로 

_Time.y-StartingTime = 0이 되서 최종 t=1 이 된다.

그리고, _Time.y 값이 증가하면서 t의 값은 감소한다.

그래서 t값을 우리가 보고 있는 깊이값으로 적용할 때 화면을 통과할 수 있다.


User-Specified Uniforms

코드를 고치는 것 대신에 사용자가 에디터를 통해 조절할 수 값을 조절할 수 있게 할수 있다.

이를 위해, 우리는 User-Specified Uniforms를 사용할 것이다.

우리의 경우, 링이 화면을 통과하는 시간(_RingPassTimeLength)와 

링 자체의 너비(_RingWidth)를 아래와 같이 에디터 상에 노출 시킬 수 있다.


이 속성들은 셰이더 코드에서 선언해 줘야 하며 사용하기 위해

같은 이름으로 정의해 줘야 한다.

그래서, DepthRingPass.shader를 새로하나 만들어서 아래와같이 작성한다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
Shader "Custom/DepthRingPass" {

Properties {
   _MainTex ("", 2D) = "white" {} //this texture will have the rendered image before post-processing
   _RingWidth("ring width", Float) = 0.01
   _RingPassTimeLength("ring pass time", Float) = 2.0
}

SubShader {
Tags { "RenderType"="Opaque" }
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

sampler2D _CameraDepthTexture;
float _StartingTime;
uniform float _RingPassTimeLength; //the length of time it takes the ring to traverse all depth values
uniform float _RingWidth; //width of the ring
float _RunRingPass = 0; //use this as a boolean value, to trigger the ring pass. It is called from the script attached to the camera.

struct v2f {
   float4 pos : SV_POSITION;
   float4 scrPos:TEXCOORD1;
};

//Our Vertex Shader
v2f vert (appdata_base v){
   v2f o;
   o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
   o.scrPos=ComputeScreenPos(o.pos);
   o.scrPos.y = 1 - o.scrPos.y;
   return o;
}

sampler2D _MainTex; //Reference in Pass is necessary to let us use this variable in shaders

//Our Fragment Shader
half4 frag (v2f i) : COLOR{

   //extract the value of depth for each screen position from _CameraDepthExture
   float depthValue = Linear01Depth (tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.scrPos)).r);

   fixed4 orgColor = tex2Dproj(_MainTex, i.scrPos); //Get the orginal rendered color
   float4 newColor; //the color after the ring has passed
   half4 lightRing; //the ring of light that will pass through the dpeth

   float t = 1 - ((_Time.y - _StartingTime)/_RingPassTimeLength );

   //the script attached to the camera will set _RunRingPass to 1 and then will start the ring pass
   if (_RunRingPass == 1){
      //this part draws the light ring
      if (depthValue < t && depthValue > t - _RingWidth){
         lightRing.r = 1;
         lightRing.g = 0;
         lightRing.b = 0;
         lightRing.a = 1;
         return lightRing;
      } else {
          if (depthValue < t) {
             //this part the ring hasn't pass through yet
             return orgColor;
          } else {
             //this part the ring has passed through
             //basically taking the original colors and adding a slight red tint to it.
             newColor.r = (orgColor.r + 1)*0.5;
             newColor.g = orgColor.g*0.5;
             newColor.b = orgColor.b*0.5;
             newColor.a = 1;
             return newColor;
         }
      }
    } else {
        return orgColor;
    }
}
ENDCG
}
}
FallBack "Diffuse"
}


그리고 아래의 스크립트는 카메라에 붙인다.

이 스크립트를 DepthRingPass.cs라고 부르자.

DepthRingPass.cs 은 깊이 텍스처처와 카메라에서 렌더링된 화면을 이미지로 

셰이더로 전달 하는 거 뿐만 아니라,  링의 시작점이 된다.

사용자가 "E"키를 누를 경우 _StartingTime값이 현재시간으로 설정되고 _RunRingPass가

1로 설정된다.

여기서 SetFloat 함수로 1을 전달하는 이유는 SetBool 같은 함수가 없기때문이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class DepthRingPass : MonoBehaviour {

public Material mat;

void Start () {
    camera.depthTextureMode = DepthTextureMode.Depth;
}

void Update (){
   if (Input.GetKeyDown(KeyCode.E)){
      //set _StartingTime to current time
      mat.SetFloat("_StartingTime", Time.time);
      //set _RunRingPass to 1 to start the ring
      mat.SetFloat("_RunRingPass"1);
  }
}

// Called by the camera to apply the image effect
void OnRenderImage (RenderTexture source, RenderTexture destination){
   //mat is the material containing your shader
   Graphics.Blit(source,destination,mat);
}
}


머티리얼을 만들어서 우리가 만든 shader를 설정하고 이를 다시

위에 우리가 작성한 DepthRingPass.cs에 추가해 줘야 한다는 것을 기억하자.


part3 글에서는 셰이더에서 깊이와 노멀을  DepthTextureMode, DepthNormal들이

어떻게 동작하지는 살펴볼 것이다.


part2.unitypackage

DepthGrayscale.shader

DepthRingPass.shader

DepthRingPass.cs

PostProcessDepthGrayscale.cs



Reference Link

- unity doc : built-in shader variables

- tex2DProj

-





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

hdr texture를 위한 bc6h  (0) 2016.09.05
Depth and Normal Textures (Part 3)  (0) 2016.07.24
Unity에서 Depth Texture의 사용  (0) 2016.04.29
Depth and Normal Texture (Part 1)  (2) 2016.04.29
#pragma multi_compile  (0) 2016.04.23
TAGS.

Comments