WinCNT

버텍스 ID 3개로 풀 스크린 쿼드를 대체할 수 있다고!! 본문

Unity/URP or Shader 관련

버텍스 ID 3개로 풀 스크린 쿼드를 대체할 수 있다고!!

WinCNT_SSS 2024. 2. 27. 10:05

서론

여태까지 필자는 포스트 프로세싱을 위해서는 최소 4개의 버텍스를 가진 쿼드가 있어야 한다는 고정관념에 빠져 살아왔다

하지만 매우 충격적이게도 단 3개의 버텍스, 즉 삼각형으로 풀 스크린의 쿼드를 대신할 수 있다는 것을 알아버리고 말았다

 

이름하여 Full Screen Triangle!!

 

이 글은 풀 스크린 트라이앵글에 대해서 알게 된 내용을 정리한 글이다

 

참고로 Full Screen Triangle이란 단어(유니티의 함수 이름에서 발췌)는 여태까지 알고 있던 Full Screen Quad와 구별하기 위해서 사용하고 있지만, 보통은 둘 다 Full Screen Quad라고 부르는 것 같다


Blit.hlsl

물론 이 방법을 필자가 스스로 생각해낸 건 아니고 아래의 소스 코드에서 사용되고 있었다

com.unity.render-pipelines.core\Runtime\Utilities\Blit.hlsl

 

버그 픽스를 위해 URP의 Blit를 보고 있었는데, 거기서 버텍스 셰이더가 쿼드가 아닌 삼각형을 그리고 있어서, 이게 왜 움직이는 거지…하고 한참을 보고 겨우 이해했다


대상 소스 코드

우선 어떠한 소스 코드인지 살펴보자

프래그먼트 셰이더는 그냥 샘플링을 할 뿐이니 생략하고 중요한 건 버텍스 셰이더이다

아래는 Blit.hlsl의 버텍스 셰이더에서 주요 부분들만 발췌한 소스 코드이다

Varyings Vert(Attributes input)
{
    Varyings output;
    UNITY_SETUP_INSTANCE_ID(input);
    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

    float4 pos = GetFullScreenTriangleVertexPosition(input.vertexID);
    float2 uv  = GetFullScreenTriangleTexCoord(input.vertexID);

    output.positionCS = pos;
    output.texcoord   = uv * _BlitScaleBias.xy + _BlitScaleBias.zw;
    return output;
}

 

함수들은 Common.hlsl에 정의되어 있었다

float4 GetFullScreenTriangleVertexPosition(uint vertexID, float z = UNITY_NEAR_CLIP_VALUE)
{
    // note: the triangle vertex position coordinates are x2 so the returned UV coordinates are in range -1, 1 on the screen.
    float2 uv = float2((vertexID << 1) & 2, vertexID & 2);
    float4 pos = float4(uv * 2.0 - 1.0, z, 1.0);
    return pos;
}

// Generates a triangle in homogeneous clip space, s.t.
// v0 = (-1, -1, 1), v1 = (3, -1, 1), v2 = (-1, 3, 1).
float2 GetFullScreenTriangleTexCoord(uint vertexID)
{
#if UNITY_UV_STARTS_AT_TOP
    return float2((vertexID << 1) & 2, 1.0 - (vertexID & 2));
#else
    return float2((vertexID << 1) & 2, vertexID & 2);
#endif
}

소스 코드 분석

위의 소스 코드의 결과를 그림으로 나타내면 다음과 같다

 

빨간색은 버텍스 ID이며 그에 따른 Position, UV 좌표 등을 표시했다

검은색 좌표는 Position 좌표(w는 전부 1이라 생략), 파란색 좌표는 UV 좌표이다

 

중요한 건 모두 homogenous clip space에서의 값이라는 것이다!

일반적인 쉐이더에서는 TransformObjectToHClip 등으로 계산하는 결과 값에 해당한다

 

계속해서 노란색은 클리핑 공간, 초록색은 그 좌표이다

(그런데 w가 1이니 결국 NDC 공간이기도 하지 않을까…? 아닌가…? 맞나…?)

 

아무튼 위의 그림에서 알 수 있듯이 동차 클립 공간(Homogenous clip space)에서의 삼각형이 클리핑 공간을 완전히 덮고 있음을 알 수 있다

이런 느낌!

 

클립 공간을 벗어나는 부분은 레스터라이저의 클리핑 단계에서 잘리게 되므로 결과적으로 사각형만 남게 된다!

 

참고로 많은 글들이 래스터라이저의 클리핑을 다음과 같은 피라미드 모양의 뷰 프러스텀을 가지고 설명하기도 한다

하지만 이는 이해하기 쉽도록 그랬을 뿐...

실제로는 이미 버텍스 셰이더에서 클립 공간(혹은 투영 공간, 아무튼 Projection 행렬 곱까지 한 그 공간)의 변환은 끝났기 때문에, 원근감을 나타내기 위한 피라미드 모양이 아니라 2x2x1의 직육면체 공간의 뷰 프러스텀이 정확하다 할 수 있다


마무리

일단 필자가 최대한 이해한 내용을 정리해봤다

물론 소스 코드를 통한 일종의 추론(?)이므로 일부 동작 원리에 대해서는 틀렸을 수도 있다(특히 래스터라이저의 클리핑 부분)

 

2024.1.11 추가) 우연히 아래의 사이트를 발견했다. 역시 클리핑이 맞는 것으로 보인다

Vulkan tutorial on rendering a fullscreen quad without buffers

 

Vulkan tutorial on rendering a fullscreen quad without buffers

Rendering a fullscreen quad* the easy way (*) Which is actually just a huge triangle Having to render a fullscreen quad (or something that fills the whole screen) is a common task in 3D real time graphics, as many effects rely on rendering a texture over t

www.saschawillems.de

어찌됐든 버텍스 ID(0, 1, 2)과 비트 연산만으로 풀 스크린 쿼드를 대체할 풀 스크린 트라이앵글을 만들 수 있는 건 사실이다

이걸 자체 엔진 제작할 때 알았으면 적용해봤을텐데 약간 아쉽긴 하다

약간만 아쉽다


참고 사이트

Vulkan tutorial on rendering a fullscreen quad without buffers

 

Vulkan tutorial on rendering a fullscreen quad without buffers

Rendering a fullscreen quad* the easy way (*) Which is actually just a huge triangle Having to render a fullscreen quad (or something that fills the whole screen) is a common task in 3D real time graphics, as many effects rely on rendering a texture over t

www.saschawillems.de

Homogeneous Coordinates, Clip Space, and NDC | WebGPU

 

Homogeneous Coordinates, Clip Space, and NDC | WebGPU

We dive into clip space and NDC, and take a closer look at the projection math involved to get there. We'll also learn more about homogeneous coordinates.

carmencincotti.com

래스터라이저(rasterizer)란?

 

래스터라이저(rasterizer)란?

래스터라이저가 하는 일과 장점을 알아보자.

sos0911.github.io

3 - 래스터화(Rasterization)

 

3 - 래스터화(Rasterization)

책을 보며 개인적으로 공부하는 내용이므로 틀린 부분이 있을 수 있습니다. 자료 및 내용 출처 래스터화(Rasterization) 렌더링 파이프라인의 2단계인 래스터화는 1단계인 정점 처리의 출력을 입력

woo-dev.tistory.com

Projection Matrixについて | shikihuiku – 色不異空 – Real-time rendering topics in Japanese.

 

Projection Matrixについて | shikihuiku – 色不異空 – Real-time rendering topics in Japanese.

何かとややこしいProjection Matrixに関する解説

shikihuiku.github.io

全屏三角形,HDUtils.DrawFullScreen 方法的理解_上午八点的博客-CSDN博客

 

全屏三角形,HDUtils.DrawFullScreen 方法的理解_hd-utils-CSDN博客

更新: Graphics.Blit文档 中说明了是通过画了一个全屏四边形的方式来实现blit的。 原文: 概述 在HDRP的后处理系统中,具体来说就是 PostProcessSystem 类中,在绘制全屏后效时调用了几次 HDUtils.DrawFullS

blog.csdn.net

스텐실 버퍼를 사용한 외곽선효과 및 삼각형으로 풀스크린 그리기

 

스텐실 버퍼를 사용한 외곽선효과 및 삼각형으로 풀스크린 그리기

3D 피킹을 구현하고 선택한 오브젝트가 메쉬가있을경우 시각적으로 선택되었다는 효과를 주고싶었습니다. 그래서 오브젝트에 외곽선효과를 주는 방법에 대해서 생각해보았는데요. 마침 LearnOpen

cutecatgame.tistory.com