✅ 오늘 한 일
- 대마왕의 유니티 URP 셰이더 그래프 읽기 : Part 19
- 헤드 퍼스트 디자인 패턴 : Chapter 2
- Random Study : Animation Rigging in Unity
📖 대마왕의 유니티 URP 셰이더 그래프
Part 19 알파와 뎁스 버퍼 (Alpha & Depth buffer)
01 Z버퍼(Depth buffer)와 불투명(Opaque)
Z 버퍼(깊이 버퍼)?
앞뒤 판정을 위해, 각 픽셀마다 카메라를 기준으로 가장 가까운 오브젝트의 깊이 값이 저장되어 있는 데이터 시트
불투명(Opaque) 오브젝트들이 앞에 있으면 Z 버퍼로 앞뒤 판정 가능
02 반투명 : 알파 블렌딩 (Alpha Blending)
반투명일 때 Z버퍼만 고려하면 투명한 부분들까지 뒤의 오브젝트가 그려지지 않기 때문에
- 불투명(Opaque) 오브젝트는 먼저 그린다
- 반투명(Transparent) 오브젝트는 나중에 그린다
- 반투명 오브젝트들끼리는 멀리 있는 것부터 차례대로 그린다 (Alpha Sorting)
이를 위해 이러한 연산들이 필요하다
- 셰이더가 Transparent인 오브젝트들은 Opaque 오브젝트들이 다 그려질 때까지 대기하고 있어야 한다
- 반투명 오브젝트들끼리 그려질 때, 각각 카메라와의 거리를 체크하는 연산을 추가해야 한다
- Opaque 오브젝트는 뒤 오브젝트들을 가리면 연산이 줄어드는데, Transparent 오브젝트는 연산이 무거워진다
- 디퍼드 렌더링(Deffered Rendering)에서는 아예 반투명을 처리할 수 없어서, 포워드 렌더링(Forward Rendering)으로 반투명을 따로 그려줘야 한다.

- Quad를 만들고, Unlit Shader Graph, 머테리얼, 나뭇잎 텍스쳐 준비
- Shader Graph > Graph Settings > Transparent : 알파 블렌딩 사용 가능하게 하기
- Graph Settings > Depth write > Force Enable : 강제로 Z버퍼에 쓰게 만든다
- 나뭇잎 텍스쳐를 연결하고, RGB와 A를 모두 연결한다
뒷 나뭇잎을 앞 나뭇잎보다 살짝 옆으로 빼보면, 앞 나뭇잎의 투명 부분이 뒷 나뭇잎을 가려버린다.
카메라의 위치에서부터 각 오브젝트의 피봇점까지의 거리로 알파 소팅을 하기 때문이다. 즉,
알파 소팅을 써 봤자 완벽하게 앞뒤를 제대로 판정할 수가 없으니,
알파 블렌딩을 사용하였을 때 앞뒤 문제는 늘 일어날 수밖에 없다. 포기해라.
하지만 Z 값에 의해 사각으로 뚫리는 현상까지는 막을 수 있다.
Transparent 계열의 셰이더로 작성하면, Z버퍼에 자신의 위치 값을 입력하지 않는다.
(Zwrite를 off, 혹은 Depth에 Write 하지 않는다고 표현)

Depth Write를 Force Disable로 바꾸면 앞뒤 문제는 해결되지 않지만,
매쉬 모양으로 잘리는 문제까지는 사라진다.
03 알파 테스팅 / 클리핑 (Alpha Testing / Clipping)
이처럼 알파 블렌딩은 사용이 한정적이다. 앞뒤 판정은 명확하지 않으며 무겁다.
그래서 알파 테스팅(클리핑)이라는 걸 사용한다.
- Surface Type은 Opaque
- Alpha Clipping 체크
- Fragment에 생긴 Alpha Clip Threshold는 0.5 유지

알파 클리핑 : threshold 기준으로 완전히 투명하거나 완전히 불투명하게 그려진다.
부드러운 외곽선을 만들 수는 없지만, Opaque처럼 자유롭게 쓸 수 있다.
알파 블렌딩의 부드러운 외곽과 알파 테스팅의 기능을 동시에 원하면, 알파 블렌딩과 클리핑을 동시에 켜는 방법도 있다.
하지만 알파 블렌딩만큼 무거우면서 알파 블렌딩만큼 부드럽게 표현해주는 것도 아니라 애매하긴 하다.
또는 MSAA(Multisample Anti Aliasing)을 이용해서 알파테스트의 경계를 부드럽게 해주는 Alpha to Coverage라는 기법도 있다.
04 Depth Test
Depth Test : 내가 그려질 때 이미 있는 Z버퍼를 읽어서 그 값으로 어떻게 할 거냐를 결정. 그다지 많이 사용하진 않는다.
- Never : 절대로 그리지 않는다.
- Less : 내 Z 값이 이미 그려진 값 보다 더 가까울 때만 그린다
- Equal : 내 Z 값이 이미 그려진 값과 같을 때만 그린다.
- L Equal : Less and Equal. 내 Z 값이 이미 그려진 값 보다 더 가깝거나 같을 때만 그린다.
- Greater : 내 Z 값이 이미 그려진 값 보다 더 멀 때만 그린다.
- Not Equal : 내 Z 값이 이미 그려진 값과 다를 때만 그린다.
- G Equal : Greater and Equal. 내 Z 값이 이미 그려진 값 보다 더 멀거나 같을 때만 그린다.
- Always : 이미 그려진 Z 값과 상관 없이 언제나 그린다. (스텐실 기능과 함께 사용하여 벽 뒤에 가려졌을 때의 외곽선에 사용)
05 Blending Mode
이펙트는 반투명이 필수적이다. 알파 블렌딩에서 발생하는 앞뒤 문제를 피해가야 한다.

이펙트가 들어 있는 아틀라스 이미지에

Time을 곱하고 XY를 각각 5,5로 해준 Flipbook 노드를 연결하면 이미지가 애니메이션화 된다.
이펙트 팁

알파 블렌딩 이펙트로도 이펙트의 Bloom을 가동시키려면, 10제곱으로 밝은 부분만 추출해서 30배쯤 곱해주면 된다.
이렇게 하면 밝은 폭발과 어두운 연기를 모두 표현 가능하다.
Blending Mode 옵션 종류
- Alpha : 알파 채널의 강도에 의해 투명도가 결정
- Premultiply : 알파 채널을 RGB 채널에 미리 곱해놓고 투명도를 떨어뜨려 보다 정상적으로 연산 (원래는 외곽선에 검은색이 안 묻어나오게 바꿔주는데, 2D에서만 티가 난다고 함)

- Additive : 배경 이미지와 더해지면서 밝아진다.
- 알파 채널 없이 배경이 검은색인 이미지에 Additive를 적용시키면 검은색이 투명해지면서 뒤의 이미지와 밝게 합성된다.
- 알파도 추가로 연산되고 있기 때문에, 알파를 0으로 바꾸면 완전히 투명해진다.
- 앞뒤 문제는 발생하고 있지만, 어차피 결과가 같기 때문에 상관 없다.
- RGB에 10 정도를 곱해서 HDR Bloom을 만들면 잘 어울리기도 한다.

- Multiply : 배경에 곱해준다.
- 배경과 겹쳐지면 어두워지고, 겹치면 겹칠수록 점점 어두워진다.
- 알파를 전혀 연산하지 않기 때문에, Alpha를 0으로 만들어 주어도 투명해지지 않는다.
- 앞뒤 문제가 발생하지만, 역시 결과가 같아서 상관 없다.
이처럼 블렌딩 모드가 같다면 큰 티가 나지 않거나 문제가 일어나지 않는다.
하지만 서로 다른 블렌딩끼리 겹치면 문제가 발생한다.
앞뒤면에 따라 서로 다른 결과가 나올 수 있다.
알아서 잘 숨기거나, 피봇점 같은 트릭을 이용하거나, Render Queue로 그리는 순서를 조절한다.
06 Graph Settings
Precision(정밀도)
셰이더 코드 전체의 기본 정밀도를 제어한다.
Single은 32비트로, 셰이더에서 사용 가능한 가장 정밀한 부동 소수점 값이다.
Half는 16비트다.
Target Settings
Built-in, URP, Custom Shader들 중 대상 파이프라인 설정
Material
셰이더 그래프의 재질 기본 설정을 바꾼다. Unlit, Lit, Decal, Sprite 등.
Allow Material Override
Graph Settings의 옵션들을 머테리얼에서 덮어쓰기가 가능해진다.
셰이더 하나만으로도 다양한 속성을 가진 셰이더로 사용할 수 있기 때문에 셰이더 개수가 줄어들고 작업 효율 증가한다.
Blend Mode
Surface Type이 Transparent가 돼야만 나온다.
Render Face
앞면 뒷면 어디를 그릴지
Depth Write
Z buffer에 쓸지 안 쓸지.
Opaque일 땐 기본 Enable, Transparet일 땐 기본 Disable
Cast Shadow
그림자 켜고 끄기.
Transparent 옵션에선 기본적으로 작동하지 않는다.
이걸 끄면 Shadow Pass를 생성하지 않아서 좀 더 가벼운 셰이더가 된다.
Custom Editor GUI
C#으로 Custom Editor를 작성하고 Custom Editor GUI의 이름을 입력하여
Shader Properties를 커스텀할 수 있게 한다.
📖 헤드 퍼스트 디자인 패턴
Chapter 02 | 객체들에게 연락 돌리기, 옵저버 패턴
옵저버 패턴
- 신문사와 구독자로 이루어지는 신문 구독 서비스
- 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체에게 연락이 가고, 자동으로 내용이 갱신되는 방식으로 일대다 의존성을 정의
Subject 인터페이스 : 객체에서 옵저버로 등록하거나, 옵저버 목록에서 탈퇴하고 싶을 땐 이 인터페이스에 있는 메소드를 사용한다.
Observer 인터페이스 : 옵저버가 되고 싶은 객체는 반드시 Observer 인터페이스를 구현해야 한다. 이 인터페이스에는 주제의 상태가 바뀌었을 때 호출되는 update() 메소드밖에 없다.
느슨한 결합 : 객체들이 상호작용할 수는 있지만, 서로를 잘 모르는 관계. 이를 활용하면 코드의 유연성이 좋아진다.
디자인 원칙
상호작용하는 객체 사이에는 가능하면 느슨한 결합을 사용해야 한다.
주제가 옵저버에게 상태를 알리는 푸시보다
옵저버가 주제로부터 상태를 끌어오는 풀이 대체로 더 좋다.
observer의 update()에 매개변수를 없애고,
각 클래스마다 필요한 데이터만 가져가도록 getter를 써놓으면 된다.
🎮 Random Study
Animation Rigging in Unity
https://www.youtube.com/watch?v=Htl7ysv10Qs
https://kangworld.tistory.com/187

- animation rigging 패키지 설치
- 캐릭터 오브젝트 선택 > Animation Rigging > Bone Renderer Setup : 본 렌더러 추가
- 캐릭터 오브젝트 선택 > Animation Rigging > Rig Setup : Rig 추가
- Rig에 타겟을 바라보게 하는 효과를 주기 위해, Rig 오브젝트 아래에 빈 게임 오브젝트를 만들고 'HeadAim'이라 명명한 뒤 Multi-Aim Constraint 컴포넌트 추가
- Multi-Aim Constraint 설정
- Constrained Obejct : 움직이게 할 대상. 모델에서 헤드 오브젝트를 찾아서 넣어준다.
- Aim Axis : 대상을 바라볼 축. Y로 설정한다.
- Up Axis : 위가 될 축. Y로 설정한다.
- Source Objects : 바라볼 대상. HeadAim 아래에 'Target'이라는 게임 오브젝트를 추가하고, Source Objects에 넣어준다.
- Settings > Min, Max Limit : 돌아갈 수 있는 최대 각도. -100, 100으로 설정한다.
- 씬 뷰 우측 하단 Animation Rigging에서 대상의 크기 모양 색깔을 설정할 수 있다
- 게임 실행하고 Target을 움직이면 대상을 향해 머리가 돌아가는 걸 볼 수 있다.
- Rig 컴포넌트 > Weight : Constraint 적용되는 정도. 플레이어가 멀어지면 바라보지 않게 응용 가능. Multi-Aim Constraint 컴포넌트에서 개별 값을 조절할 수도 있다.
- 애니메이션을 바꿔도 똑같이 대상을 바라본다.

- 상체도 돌아가게 하기 위해, Target을 상위 레벨로 올린 후에 HeadAim을 복사하고 상체를 할당한다.
- 살짝 덜 돌아가게 하기 위해, Source Objects의 Weight를 0.3으로 줄인다.

- 또다른 constraint 효과를 주기 위해, rig 하나를 또 setup한다. 이름은 ArmRig로 바꾼다.
- ArmRig 아래에 빈 오브젝트를 추가하고 ArmMover라 명명하고 Two Bone IK Constraint 컴포넌트를 추가한다.
- Two Bone IK Constraint : 두 개의 뼈를 가진 관절 체계가 목표에 도달하도록 자동으로 회전 및 위치를 계산
- Root에는 팔 위쪽 뼈, Mid에는 팔 아래쪽 뼈, Tip에는 손을 할당한다.
- 빈 오브젝트를 ArmMover 아래에 하나 더 추가하고 Target이라 명명한다. Ctrl을 누르고 모델에 있는 손 오브젝트를 함께 선택한 후, Animation Rigging > Align Transform을 선택한다. 그 후 ArmMover의 Source Objects > Target에 추가한다.
- 특정한 위치를 정해놓고 스크립트로 Weight를 조절하여 특정 동작을 하게 만들 수 있다.
- Animation이나 Timeline 시스템과 같이 사용하여 동작을 저장하거나 재생할 수도 있다.
- Rig 하나에 여러 Constraint를 할당하면, Hierarchy에서의 순서 기준으로 적용된다.
- Rig끼리의 순서는 Rig Builder 컴포넌트에서 지정할 수 있다.
- Package Manager > Animation Rigging > Samples에 가면 어떻게 활용하는지 예시 프로젝트 있다.
Inverse Kinematics (역운동학)?
오브젝트의 끝부분을 먼저 정하면, 이를 기준으로 나머지 관절(뼈)들의 위치와 회전을 자동으로 계산하는 방식