
VRChat 이용자들에게 많은 관심을 받는 에셋이 있는데, 바로 AO 마스킹 에셋입니다.
AO가 무엇인가? 부터 짧게 짚고 갈게요.

AO는 Ambient Occlusion, 차폐에 의한 그림자입니다.
구석진 부분을 더 어둡게 해서 더 사실적인 느낌을 주는 쉐이더 기능입니다.
고사양 게임을 즐기실 경우 익숙한 설정일 겁니다.


문제는 대부분 아바타의 눈 모양은 오목하게 패여 있는 구조여서,
AO가 아바타에 일괄적으로 적용되면 눈 흰자 부분이 검게 (어둡게) 변한다는 점입니다.
저희가 아바타에 적용하는 마테리얼 기능일 경우, 마스킹 텍스쳐 등을 통해 적용 영역을 세밀하게 통제할 수 있지만,
VRChat 월드 단계에서 AO가 강제로 적용된다면 통제 밖이므로 조금 다른 접근을 해봐야 합니다.
"오목하게 패여 있다면, 그렇게 보이지 않게 속이면 되잖아?"
AO를 막기 위한 여정은 기본적으로 이렇게 시작하게 됩니다.
이 글에서는 이러한 원리를 사용해서,
AO (차폐 그림자)를 눈 부분에 적용하지 않는 AO 마스킹 마테리얼을 제작해 보겠습니다.

아바타에 Alt+Shift+N 으로 빈 오브젝트를 만듭니다.
오브젝트 우클릭 > 3D Object > Sphere
아바타 하위에 구체 메쉬인 Sphere를 추가합니다. (앞으로 구체라고 부르겠습니다.)

구체에서 Sphere Collider는 제거합니다.
저희는 충돌 판정 없이 오브젝트 메쉬만 사용할 것입니다.

MA Bone proxy 컴포넌트를 구체를 넣은 부모 오브젝트에 추가합니다.
설정은 이렇게 합니다.
1. Attachment mode > As child; at root (자식으로; 루트에서)
2. Advanced 설정 펼치고 Bone reference > Head 지정
이렇게 설정함으로써 이 오브젝트는 아바타 Head 본에 자식으로 위치하게 됩니다.

Bone proxy를 잘 지정했다면 자동으로 구체 위치가 이동하고,
이 상태에서 구체 Transform의 상대적인 scale과 position을 조절하여 위치를 눈에 맞게 맞춰줄 겁니다.

씬 뷰 우상단에 있는, XYZ 기즈모의 원뿔 모양을 클릭하면 각 축으로 화면을 정렬할 수 있어 작업에 용이하니 참고해 주세요.

또한 scale의 클립 모양 아이콘 (constrained proportions) 을 체크 해제함으로써,
자유롭게 변형을 할 수 있으니 이 또한 필요에 따라 이용해 주세요.
눈의 흰자가 다 덮어지게 하면 설정은 다 됐습니다.
정밀한 수치보다는, 대략적인 위치를 맞추는 것에 의미를 두면 됩니다.
이제 기능을 가진 마테리얼로 바꿔 봅시다.

생성한 Sphere는 default 마테리얼을 사용하고 있어, 따로 수정할 수 없습니다.
새 마테리얼을 만들어 할당합시다.
저희가 원하는 기능은 VRChat 아바타에 폭넓게 사용되는 Liltoon에서 구현 가능하기에,
쉐이더는 먼저 이걸 사용해 보겠습니다.
이후 배포용으로, 독립적인 쉐이더로도 구현해볼 것입니다.
이는 Liltoon으로 기능을 성공적으로 완성한 이후에 다뤄보도록 하겠습니다.

1.쉐이더 Liltoon 선택, 렌더링 모드 불투명
투명해야 하는 거 아닌가요? 는 후술하겠습니다.
기본 설정 > 기본 설정
2. Cull mode > Back
메쉬의 반대편을 그려내지 않아 연산 시 최적화시키는 기본 설정입니다.
3. Zwrite off
Zwrite는 오브젝트의 깊이 값 (Depth buffer)을 기록해 원근에 따른 오브젝트의 표시 설정을 원활하게 하는 설정입니다.
유니티의 포스트 프로세싱 (PPv2) 적용 과정에서는 이 설정값과 별개로 씬의 Depth를 직접 읽어 참고합니다.
활성화 여부와 관련이 없으므로, 최적화를 위해 체크 해제 (off) 합니다.
4. Render Queue > 2500 이하
AO 효과는 렌더큐 2500을 초과하는 반투명 오브젝트에는 적용되지 않으므로, 값에 주의해서 설정합니다.

확장 설정 > 렌더링 설정
Color Mask > None
색을 그리지 않습니다. 즉 깊이 역할만 수행합니다.
그렇기 때문에 색의 투명 여부는 중요하지 않아서, 렌더링 모드를 불투명(Opaque) 으로 설정한 겁니다.
이렇게 설정하면 아래의 Forward 및 ForwardAdd 색상 출력은 이루어지지 않기 때문에 설정을 생략할 수 있습니다.

기본 설정 > VRChat
Custom Safety Fallback > Shader Type > Hidden
아바타의 기능이 차단된 상황에서도 표시되지 않도록 수정하기까지 해주면,
마테리얼 구성은 끝입니다.

AO가 적용된 월드에 입장해서 빌드한 아바타를 집어넣지 않아도,
작업 화면에서 Post-process Volume > Ambient Occlusion 필터를 사용해 제작한 기능을 실시간으로 테스트할 수 있습니다.
간단한 테스트 환경을 구축해 봅시다.
포스트 프로세싱을 테스트하려면, 다음과 같은 요소가 필요합니다.
1. Volume (Post-process Volume)
화면에 적용할 특수효과 및 그 설정값입니다. 필터라고 이해하시면 빠릅니다.
2. Layer (Post-process Layer)
카메라가 어떤 Volume을 읽을지를 Layer에서 가져옵니다.
이를 위해 Volume을 특정 Layer에 등록하고, 카메라가 해당 Layer를 수신하도록 설정해서 서로를 연결해야 합니다.
3. Camera
정해진 Volume을 읽어서 화면에 적용시킬 수 있는 시점(View)입니다.
이제 하나씩 만들어 봅시다.

1. Ctrl+Shift+N으로 씬에 새 오브젝트를 추가합니다.
2. 오브젝트에 Post-process Volume 컴포넌트를 추가합니다.
3. Is Global을 체크해서 Volume이 특정 영역 조건 제한이 아닌 전체 씬에 적용되도록 합니다.
4. 우상단 Tag / Layer 부분에서 Layer를 Water로 지정합니다.
이렇게 함으로써 Volume이 Water 채널에 등록되고, Camera에서 호출해서 이용할 수 있습니다.


왜 Water인가?
→ 저희가 일반적으로 작업하는 VRChat 아바타 프로젝트에서는 Water 레이어를 사용하지 않습니다.
그러므로 Volume의 Layer 등록 시 순전히 안 쓰는 채널을 할당한 것입니다.
작업 규모가 커지는 등 구분이 필요할 경우에는,
Layer를 눌렀을 때 나오는 드롭다운 메뉴에서 Add layers... 로 개별 레이어를 지정해 주세요.

5. Profile에서 새 프로파일을 만듭니다.
6. Add effect > Unity > Ambient Occlusion 으로 AO를 추가합니다.
Mode (알고리즘) 체크할 필요 x
Intensity (강도) 체크, 1 이상으로 설정해야 뚜렷하게 보입니다.
Thickness (범위) 체크, 취향껏 조절
Z Bias (깊이 보정) 체크, 값 1e-06 입력
기본값은 1e-05 (0.00001)인데, 이대로는 보정값이 너무 커 AO가 제대로 보이지 않습니다. 줄여줘야 합니다.
Color (AO 색상) 체크할 필요 x

7. 하이어라키 우클릭 > Camera 추가
카메라를 Ctrl+Shift+F 단축키를 사용해 씬 뷰에서 보고 있는 위치와 각도에 일치시킵니다.
이 과정에서 Game 윈도우를 Scene의 아래나 옆에 위치시켜 확인하기 쉽게 창 구성을 조절했습니다.
Clear Flags > Solid color, Background는 Scene 색상 참고
Field of View > 30 이하
Clipping Planes > Near 0.1
정도면 무난하게 둘 수 있습니다.

8. 카메라에 Post-process Layer 컴포넌트 추가
Layer에 Water를 지정함으로써 이전에 Water Layer에 등록한 Volume을 가져옵니다.
Is Global이므로 특별한 추가설정 없이 바로 적용됩니다.
다 됐습니다.

잘 따라오셨다면, 이제 Game 윈도우에서 AO가 적용된 결과물을 확인할 수 있습니다.
화면 기준, 왼쪽 눈과 오른쪽 눈이 가지는 비주얼 차이가, 저희가 설정한 마테리얼이 가져온 차이입니다.
실시간으로 원하는 각도에서 보면서 설정값을 조절하면 됩니다.

다 작업했다면, 반대쪽 눈은,
구체 오브젝트를 복사한 다음 X값 축 부호만 바꾸면 간단하게 적용할 수 있습니다.
이제 빌드하면 끝입니다.


테스트 환경과 동일하게, 인게임에서도 잘 적용된 모습을 확인할 수 있습니다.
좋네요.

더불어서, 제 사례에서는 단순하게 적용한 구체 메쉬의 한계도 확인할 수 있었습니다.
꼭 멍이 든 거 같네요.

일반적인 사용자가 메쉬 모양을 밑바닥부터 아바타의 눈 모양에 맞추게 설정하기에는 어렵고 시간이 많이 듭니다.
BOOTH에서 판매하는 AO 마스킹 관련 인기 에셋들은,
깊이용 메쉬가 눈과 눈꺼풀 사이에 잘 위치하게 할 수 있는 다양한 솔루션을 제공하는 경우가 많습니다.
거기에 더불어 저희가 하나씩 설정한 마테리얼과, 테스트 환경도, Prefab으로 쉽게 제공해주기도 합니다.
여러모로 시간노력 비용을 단축해 주기에,
에셋의 수요가 확실한 영역이라고 볼 수 있겠습니다.
이렇게 VRChat용 AO 마스킹 마테리얼과, 테스트 환경까지 작업을 완료함으로써 1편을 마치겠습니다.
2편에서는 ShaderLab 코드 작성으로, Liltoon이 아닌 커스텀 쉐이더로 마테리얼 기능을 동일하게 구현해 보겠습니다.
읽어주셔서 감사합니다!