Unity/Rendering&Shader

[RENDERING] Screen Pos UV

김성인 2024. 1. 9. 23:44

[RENDERING] Screen Pos UV

 

 

 Post-Processing 용 Shader를 만들다 보니, 항상 Screen Position을 이용하게 되는데, 셰이더 그래프를 보면 이것 또한 하나의 UV 임을 알 수 있다.  

 모든 오브젝트는 UV를 이용하여 맵핑을 진행하는데, 우리들이 모니터를 통하여 그래픽을 볼 수 있는 이유 또한 모니터에도 UV가 존재하기 때문이다.

 

 유니티나 언리얼에서도 화면의 UV를 시각화하면 위와 같이 보이게 된다. (물론 유니티와 언리얼은 좌표계가 다르기 때문에, 위의 이미지와 다르게 빨간색이 위쪽에 존재한다.)

 

 화면의 사이즈를 이리저리 변경하면 그에 맞춰서 색 또한 늘어질 뿐이다. 즉, 이것은 화면은 항상 (0, 0) ~ (1, 1)로 존재한다는 것을 뜻한다.

 

 만약 여느 Shader와 같이 Tiling, Offset 역시 똑같이 적용되는 것 같다.

 여기까지 이해하였다면 Screen Position,  Screen의 UV가 보통의 오브젝트에 이용되는 UV와 성질이 같다는 것을 알 수 있다.  

 그리고 이것을 이용하면 하단의 GIF 같은 이런 UV를 이용할 수 있게 된다.

 

 하지만 이것을 3D 공간의 오브젝트에 넣게 되면 어떻게 될까?

 보통 오브젝트가 화면에 그려지는 범위 내에서 화면의 UV에 맞춰서 픽셀에 색이 정해질 것이다.  하지만 이것은 렌더링 되는 화면에 한해서이지, 3D 공간에서의 이야기는 달라진다.  정확히 이야기하면 2D와 3D 공간을 렌더링 할 때, 투영(Projection)의 차이에 따라서 달라지게 된다.

 

 2D 게임에서는 보통 투영(Projection)을 Orthographic으로 사용하여, Scene(언리얼의 Level, 월드)의 앞쪽과 뒤쪽에 오브젝트를 배치하여도 원근이 적용되지 않지만, 3D 게임에서는 보통 Perspective의 프로젝션을 이용하기 때문에 원근이 적용된다. 그리고 이것을 오브젝트에 적용하게 되면, 카메라 앞의 Screen Position을 이용하는 것이 아닌, 오브젝트가 존재하는 위치의 Screen Position을 이용하기 때문에, 생각했던 것과 다른 결과물이 나오게 된다.

 

 이것을 하단의 그림으로 보자. 투영 방법으로 분류하여 2D 게임(Orthographic)과 3D 게임(Perspective)를 비교해 보면, 2D 게임에서 사용하는 투영 방법의 경우 A, B, C 지점 모두 동일한 UV를 유지하지만, 3D 게임에서 사용하는 투영 방법의 경우 A, B, C 지점 모두 다른 UV를 가지게 된다.

 

 렌더링 과정을 알고 있다면, 3D 게임에서 A, B, C 지점의 이미지는 모두 같은 사이즈의 화면에 그려야 하기 때문에 카메라에서 멀어질수록 화면을 작게 욱여넣어야 한다는 것을 알고 있을 것이다.

 그럼 이렇게 된다.

 

 만약 3D 공간의 오브젝트에도 Screen Position을 그대로 이용하고자 한다면, 쉽게 해결할 수 있다. 바로 카메라의 깊이 값으로 Screen Position의 값을 나눠주면 된다. 유니티에서는 보통 Position을 float4의 형태(x, y, z, w)로 coordinate를 자리하고 있는데, xy 값에 UV를 그리고 w에 깊이 값을 가지고 있다. 그렇기 때문에 Position.xy / Position.w의 형식의 수식을 이용하면 해결된다.

 

 Shader Graph에 보면 Screen Position이라는 노드가 존재하는데, Mode에서 Default를 사용하는 경우 위와 같은 결과물을 얻을 수 있다. 하지만 이것은 위와 정확히 같은 방법으로 구현된 것이 아니다. 잠시 후에 이 부분에 대해서 다시 이야기하겠다.

 위와 같이 코드에서 Position.xy / Position.w를 Shader Graph에서 얻기 위해서는 Screen Position 노드의 Mode를 Raw로 해야 한다.

 

 다시 Screen Position의 Default Mode에 대한 유니티 매뉴얼을 확인해 보면 내가 xy / w와 조금 다르게 설명되어 있음을 알 수 있다.

 

Screen Position에 대한 Unity 메뉴얼 : https://docs.unity3d.com/Packages/com.unity.shadergraph@14.0/manual/Screen-Position-Node.html

 

Default : float4 Out = float4(IN.NDCPosition.xy, 0, 0);

Raw : float4 Out = IN.ScreenPosition;

Center : float4 Out = float4(IN.NDCPosition.xy * 2 - 1, 0, 0);

Tiled : float4 Out = frac(float4((IN.NDCPosition.x * 2 - 1) * _ScreenParams.x / _ScreenParams.y, IN.{0}.y * 2 - 1, 0, 0));

Pixel : float4 Out = float4(IN.PixelPosition.xy, 0, 0);

 

 NDCPosition은 무엇인지 궁금한데, NDC는 Normalized Device Coordinate의 약자이다. 그리고 이것을 Open GL의 매뉴얼을 확인해 보면 이렇게 적어져 있었다.

 

 위에서 NDCPosition과 Position.xy / Position.w 와 다르다고 말을 꺼냈는데, 이것을 보면 같은 이야기였다.

 그렇다면 이 Screen Position은 어디에 쓰이느냐?라는 질문에 화면 전체에 효과를 가하는 Post-Processing에 대부분 쓰이며, 그 외에도 이질적인 공간이나 이미지를 첨가할 때 자주 사용된다. 참고로 나는 UI의 배경에도 자주 사용하였다.

 

 추가적으로 Normalize(정규화)라는 단어 때문에, Screen Position.xy 값을 정규화 시켰더니, 재미있는 결과물을 얻을 수 있었는데, 하단의 이미지와 같이 (1, 1)의 위치로 갈수록 왜곡되어가는 UV를 확인했다.