일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 벡터
- 3d
- 메모리 누수
- C언어
- URP로 변경
- Cell Shader
- Cartoon Rendering
- VR
- Specular
- Three(Two) Tone Shading
- Virtual Byte
- 작업 집합
- AppSW
- Rim Light
- OculusMotionVectorPass
- Private Bytes
- 개인 바이트
- Cell Look
- URP
- 가상 바이트
- Windows Build
- Toon Shader
- ColorGradingLutPass
- working set
- 프로그래밍 기초
- 게임 수학
- ASW(Application SpaceWarp)
- Today
- Total
WinCNT
버텍스 ID 3개로 풀 스크린 쿼드를 대체할 수 있다고!! 본문
서론
여태까지 필자는 포스트 프로세싱을 위해서는 최소 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
어찌됐든 버텍스 ID(0, 1, 2)과 비트 연산만으로 풀 스크린 쿼드를 대체할 풀 스크린 트라이앵글을 만들 수 있는 건 사실이다
이걸 자체 엔진 제작할 때 알았으면 적용해봤을텐데 약간 아쉽긴 하다
약간만 아쉽다
참고 사이트
Vulkan tutorial on rendering a fullscreen quad without buffers
Homogeneous Coordinates, Clip Space, and NDC | WebGPU
Projection Matrixについて | shikihuiku – 色不異空 – Real-time rendering topics in Japanese.
全屏三角形,HDUtils.DrawFullScreen 方法的理解_上午八点的博客-CSDN博客
스텐실 버퍼를 사용한 외곽선효과 및 삼각형으로 풀스크린 그리기
'Unity > URP or Shader 관련' 카테고리의 다른 글
URP에서 Additional Lights(Point Light, Spot Light) 적용해보기! (0) | 2024.03.06 |
---|---|
Fog가 적용되는 Skybox의 셰이더 만들어보자! (0) | 2024.02.28 |
URP에서 팔레트 스왑(Palette Swap) 기능 구현하기 (0) | 2024.02.19 |
텍스처 샘플링의 부하 측정해보기(Oculus Quest2) (0) | 2024.02.07 |
카메라와 오브젝트가 가까울 때 Dithering해서 반투명처럼 보이게 하는 셰이더 구현해보기! (0) | 2024.02.01 |