0.지난주차 보충
0-1. Geometry Node의 기초
Geometry에서 꼭 알고 넘어가야할 노드는 아래와 같다.
Position
픽셀의 위치 값을 출력한다.
Object, View, World, Tangent 등의 공간을 선택할 수 있다.
World와 Absolute World의 차이는 Absolute World는 모든 SRP에서 절대적인 월드값을 의미한다.
World는 렌더 파이프라인에 따라서 의미가 달라지는데
HDRP에서는 Camera Relative가 되고 URP에서는 Absolute World가 된다.
Screen Position
Mesh Vertex 나 Fragment의 Screen Position에 접근할수 있도록 하는 노드이다.
출력값은 Mode 파라메터에 따라 다른데 Default, Raw, Center, Tiled중 선택할 수 있다.
Default
Raw
Default와 달리 Screen Position을 space position W 컴포넨트(?)로 나누지 않는다고 한다.
Center
스크린의 중심의 위치 값이 float2(0,0)으로 출력된다.
Tiled
Center 처럼 화면의 중심이 float2(0,0)이 되고 Fraction노드를 사용한것 같이 타일링 된다.
UV
UV값을 출력하는 노드이다. 사용된 셰이더 그래프는 최상단예시에서 Position노드만 UV로 변경하였다.
Vertex Color
Mesh Vertex나 Fragment의 Vertex Color에 관여할수 있도록 하는 노드이다.
사용된 셰이더 그래프는 Position 예시에서 Position노드를 Vertex Color노드로 변경하였다.
다음과 같은 버텍스 페인팅으로 제작된 폴리곤이 아래와 같이 존재한다 가정하자.
이를 각각 R,G,B,A 값만 출력한 형태이다.
Normal Vector
Mesh Vertex나 Fragment의 노멀 벡터에 관여할수 있도록 하는 노드이다.
사용된 셰이더 그래프는 최상단예시에서 Position노드만 Normal Vector 노드로 변경하였다.
모든 픽셀에 노멀방향이 존재한다.
0-2 Z-test, Z-write?
Z-test (= Z-Read)
현재 그리려는 픽셀을 기존의 Z-Buffer 내용과 비교하는 것
Z-Write
그려도 되는 픽셀이면 Z-Buffer에 현재 거리 내용을 기록하는 것
1-1 반투명 오브젝트의 Sorting
유니티(레거시)방식 - 2Pass로 첫 패스에는 Z-Buffer만 기록, 2번째 패스에서 최종 렌더링_참고링크
언리얼 방식 - 2Pass로 안되다보니 안보이는 메시를 스폰해서 겹쳐서 depth만 처리하는 식으로 처리
Sorting이 중요한 이유
아래는 투명과 반투명이 섞인 모델링을 가져와 단순히 Surface Type을 trasparent로 설정했을때 생길수 있는 모습
z-test만 진행하고 버퍼에는 기록을 안해서 생긴 문제이다.

1-2. Early-Z
그래픽 파이프라인을 보면 Fragment Shader (Pixel-Shader)이후 Output-Merger에서 Depth Test를 수행한다.
Fragment Shader 연산 이후 그릴지 말지 검사하므로 오버드로우가 발생한다.
이런 비효율을 개선하기 위해 Fragment shader 이전에 미리 Depth Test를 위해 가려진 Fragment는 Fragment Shader를
수행하지 않는다. (실제 작동은 다양한 하드웨어 특성에 따라 달라질 수 있다.)
요즘 대부분의 GPU는 early depth testing이라는 하드웨어 기능을 지원하는데,
Early depth testing은 FS이전에 뎁스 테스트를 수행한다.
제한사항 - FS에서는 깊이 갚에 쓰기를 하지 말아야 Early Depth Testing이 유효함
Unity URP 12.0.0이상 버젼 부터는 Unity Depth Prepass( Depth Priming Mode)라는게있다.
Asset > Rendering > Rendering Path, Forward > Depth Priming Mode
보이는 모든 Opaque 메시들은 FS 비용없이 Depth Buffer에 그려넣어지는 패스로
이후 모든 컬러 패스들은 이 버퍼를 재활용한다.
URP 12 이전에는 URP 렌더 파이프라인 세팅의 Depth Texture 옵션에 의해 간접적으로 활성화 되던 기능이다.
다양한 하드웨어 상황들이 있는만큼 여러 예외처리들이 있고 최적화를 할수있도록 URP엔진이 최선을 다하고 있다고
이런 기능들을 예시로 이해하면 좋을것 같다.
쨋튼, Early-Z와 SRP의 Depth Prepass는 같은 목적의 기능이다.
1-3. Render Queue
반투명이 그려진뒤에 불투명이 그려지면 반투명에는 z-buffer가 존재하지 않아 문제가 발생한다.
따라서 유니티에서는 불투명의 기본 렌더 큐 값을 2000으로 먼저 그려지고, 반투명의 기본 렌더 큐 값은 3000으로
나중에 그려지도록 되어있다.
즉 렌더큐는 언제그려질지 정해주는 번호이고, 적은 수일수록 빨리 그려진다.
유니티 Material의 Advance Option에서 Sorting Priority(Render Queue)를 통해서
기본으로 정해진 렌더큐 값에 ± x하여 렌더링될 순서를 조정할 수 있다.
커스텀 셰이더에서는 수동으로 설정할 수 있다.
Background - 1000
Geometry - 2000. Default
AlphaTest - 2450
Transparent - 3000
Overlay - 4000 (GUI나 렌즈 플레어 등에 사용)
커스텀 셰이더에서의 사용 예는 아래와 같다.
Tags { "Queue" = "Transparent" }
Tags { "Queue" = "Geometry+1" }
Tags { "Queue" = "2001" }
렌더 큐를 제어하는 방법은 아래와 같다.
다만 커스텀 셰이더 재질의 렌더큐를 수동으로 변경(직접 숫자로 입력)하는 것은 비추천한다.
재질에서 셰이더를 변경하는 순간 렌더큐는 셰이더 디폴트값으로 리셋되는데,
이를 인지하기도 어렵고 리셋되기 전의 번호도 알기 어렵다.
셰이더별 렌더큐를 정하면 프로젝트에서 일괄적으로 해당 셰이더의 렌더큐를 변경하기 좋다.
"Queue" = "Transparent+1" (덧셈 좌우로 띄어쓰기 X )
게임 지면에 그려지는 반투명 UI같은 경우 강제로 렌더큐를 지정해야하는 경우가 있다.
게임 시스템의 복잡한 사정에 의해 강제로 그리는 순서를 지정하는 경우가 있다.
개발하는 도중 혹은 서비스 중에 특정 요소의 렌더 큐 번호를 일괄 변경해야할 경우 셰이더에 의해 렌더큐 번호가
결정되는 구조는 셰이더 코드 변경으로 일관 세팅이 가능하여 관리 이슈를 피할 수 있다.
2-1 알파 sorting
Blending Mode가 Add나 Multiply가 되는 반투명 오브젝트라면 렌더되는 순서가 상관없지만 Alpha라면 문제가 된다.
유니티는 알파 선택시 듬성듬성 소팅(거리에 따라 그리는 순서를 변경) 해주는 것으로 보인다.
반투명 오브젝트는 불투명 오브젝트와 다르게 멀리 있는 것부터 그려지는데, 이를 알파 소팅(Alpha Sorting)이라 한다.
이 때 거리값을 판별하는 기준은 "카메라에서 오브젝트 피벗까지의 거리를" 이용한다.
다만 이러한 방법은 한계점이 확실하다.
카메라 시점이 회전함에 따라 뒤에 있던 오브젝트의 피벗이 더 가깝다고 판정되면 불쑥 튀어나와 앞에 있는 오브젝트를
가리게 될수있다.
빌보드 플랜이 아닌 복잡한 평태의 반투명 폴리곤은 오브젝트 거리에 의한 소팅으로도 해결 불가능하다.
빌보드 평면도 오브젝트의 중심에 의한 거리 순서와 버텍스의 거리 순서에 오차가 발생하기도 한다.
그리고 소팅 비용도 만만치 않다!
2-2. Alpha Clipping
알파 테스트, 컷아웃, 알파 클리핑 등 다양한 용어로 불린다.
Alpha Clipping은 알파 텍스쳐의 모양대로 Z버퍼에 그려지게 할 수 있는 기능이다.
(Opaque에 사용해야 Z-Buffer에 기록된다.)
Alpha Clipping을 적용하고 그림자를 그리게 될 경우 알파에 들어간 텍스쳐의 형태대로 그려진다.
Z-Buffer에 기록하므로 소팅 이슈도 없다.
풀이나 나뭇잎에 주로 사용하게 된다.
알파 클리핑은 Transparent Alpha와 함께 사용이 가능하지만 클리핑과 블렌딩이 동시에 작동하며 Z버퍼에
기록되지 않는다. (유니티 기본 재질의 경우)
Transparent Alpha + 클리핑이 Z-Buffer에 기록하려면 커스텀 셰이더에서 직접 제어해야한다.
모바일기기에서 느린 기술들
3-1. 변수
변하는 수, 변하는 값을 담는 저장공간이다.
변수는 선언 후 사용한다.
(HLSL임을 가정하여 설명한다.)
float a; // 값 지정 없이 선언. 후에 값을 지정해야함
float a = 1.0; // 값 지정과 함께 선언
선언은 이렇게 두 가지 경우가 있을 수 있는데, a를 두 번 선언하면 에러가 발생하니 둘 중 하나만 사용해야한다.
일단 선언된 변수는 float 없이 그냥 a만 사용한다.
a = a + 1.0; // 기존 a 값에 1.0을 더한다. 선언시 값 지정이 없었다면 에러가 난다.
변수명을 지을시 주의사항은 아래와 같다.
1. 특수문자나 공백을 사용할 수 없음 / #Test 불가
2. 영문자로 시작해야함. 숫자로 시작하면 안됨 / 123Test 불가
3. 대문자와 소문자를 구분함 / teST와 TEST는 다른 변수다.
4. 예약어를 변수명으로 사용할 수 없음 / float, int 이런 것들
3-2. 상수 (Constant)
변하지 않는 언제나 같은 값
ex) const float threshold = 0.2f
변수를 상수처럼 쓸수는 있지만 내부적으로 비효율적으로 작동한다.
참고한 글
유니티 반투명, 스텐실 개념 익히기 - 링크
소중한 교수님의 수업자료