Survival Kids의 그래픽스 및 렌더링 팁

STEVEN CANNAVAN AND DANIEL REIDLER / UNITYSurvival Kids
Aug 27, 2025|8 분
Survival Kids의 게임플레이

올여름, 유니티는 KONAMI와 협력하여 가족용 협동 게임 Survival Kids의 업데이트 버전을 출시했습니다. 유니티 내부에서 처음부터 끝까지 개발한 첫 게임이기도 합니다. 이 게임은 최대 20명 정도의 내부 소규모 팀에서 제작했기 때문에, 팀은 다른 인디 스튜디오처럼 제한된 리소스로 프로젝트 범위와 출시 일정을 맞추기 위한 혁신적인 방법을 찾아야 했습니다. 이 게시물에서는 게임의 시각적 프레임과 렌더링을 어떻게 구현했는지 알아보겠습니다.

시각적 정체성 정의하기

목표는 시각적으로 흥미로운 게임을 제작하는 것이었습니다. 멋지고 예술적인 결과물을 원했지만, 처음에는 타겟 기기의 성능이 어떤지 알 수 없었기 때문에 성능 면에서 부담을 최소화하고자 했습니다.

프로젝트는 시각적인 표현 단계부터 시작했으며, 이때 구상한 아트를 보여 주기 위해 아트 디오라마를 활용했습니다. 여기에는 커스터마이즈된 그림자를 포함하여 독특한 스타일을 살린 조명 설정을 사용했습니다.

또한 팀에서는 URP(유니버설 렌더 파이프라인)를 선택했는데, URP는 다양한 기기에서 뛰어난 성능을 입증한 바 있으며, 게임의 시각적 목표를 충족하기 위해 필요한 새로운 기능을 만들기도 상대적으로 쉬웠기 때문입니다. 게임에는 주로 태양이라는 하나의 광원만 있기 때문에 렌더링된 프레임은 포워드 모드의 기본 URP와 매우 유사합니다. 커스텀 그림자, 앰비언트 오클루전, 몇 가지 기타 커스텀 렌더 기능 등 소소한 수정 사항이 있지만, 전반적으로는 기본 URP가 화면에 구현되어 있습니다.

Survival Kids의 게임플레이
Survival Kids의 게임플레이

가장 큰 추가 요소는 셰이더였습니다. 특정한 아트 요소의 구현을 지원하기 위해 조명 계산 방식을 수정해야 했기 때문입니다. 커스텀 셰이더를 만드는 것이 딱히 새로운 작업은 아니지만, 팀원 누구나 참여할 수 있도록 자체적인 커스텀 Shader Graph 타겟을 작성했습니다. AssemblyDefinitionReference를 활용한 덕분에 완전한 커스텀 URP 버전을 사용할 필요 없이 프로젝트별 Shader Graph 타겟을 추가할 수 있었습니다. 따라서 로컬 Shader Graph 타겟만으로 기본 URP를 유지할 수 있으며, 이는 프로젝트에도 매우 원활하게 작동했습니다.

조명 및 전역 조명

팀에서는 동적 조명을 사용하는 것을 하나의 목표로 삼았으며, 조명 색상, 강도 등을 변경할 수 있는 옵션을 원했습니다. 하지만 이 경우 라이트맵을 사용하여 조명 정보를 손쉽게 베이크할 수 없으며, 이로 인해 바운스 조명/전역 조명에서 베이크로 얻을 수 있는 일부 조명 디테일을 놓칠 수 있었습니다. 동적 조명을 사용하는 접근 방식은 일반적으로 비용이 더 들기 때문에 높은 시각적 품질과 우수한 성능 간의 균형을 맞출 수 있는 다양한 방법을 생각해야 했습니다. 이 때문에 처음에는 라이트 프로브를 사용했고, 또한 오브젝트를 안정적으로 보이게 하기 위해 AO(앰비언트 오클루전)를 더 많이 활용했습니다.

Survival Kids 환경에서의 조명 및 전역 조명 정보
조명 및 전역 조명 정보

전역 조명이 이 프로젝트에 매우 중요할 것이라는 점을 알고 있었기 때문에, 처음에는 런타임에 라이트 프로브를 업데이트하는 커스텀 솔루션을 구현했습니다. 하지만 Unity 6로 전환한 후, 저희 팀에서는 기존에 만든 시스템보다 시각적 품질이 상당히 뛰어나면서도 성능 영향은 비슷했던 APV(적응적 프로브 볼륨)로 전환하고자 했습니다. 좋은 것에서더 좋은 것, 즉 고품질이고 성능이 뛰어난 것으로 업그레이드할 수 있는 옵션이 있다면 전환하는 것이 좋겠죠.

바다

바다는 대부분 Unity URP 데모 프로젝트 보트 어택(Boat Attack)을 기반으로 하되 특유의 스타일을 더 살린 모습으로 표현했습니다. 여기서 정말 하고 싶었던 작업은 섬과 물 속 다른 요소들에서 물결이 발생하도록 만드는 것이었습니다. 이는 일반적으로 뎁스 버퍼를 사용하여 거리로 해안선을 계산하는 방식으로 구현되지만, 이 게임에서는 해안선 대신 훠틀 섬이 있었습니다.

물결은 작은 섬 환경의 해안선에서 일정 거리만큼 떨어진 바다에서 발생합니다.
SDF(부호 거리 필드)는 해안선에서 일정 거리만큼 떨어진 곳에서 물결을 생성합니다.

훠틀 섬에는 갑작스러운 낙차가 있으며, 특히 물 속에 잠긴 터레인을 고려했을 때 효과를 생성하기 위한 뎁스 감쇠가 충분하지 않습니다. 팀에서 낸 최적의 아이디어는 SDF를 사용하는 것이었습니다. 기본적으로 SDF는 오브젝트(이 경우 해안선)의 부호화된 거리를 인코딩하는 텍스처입니다. 이렇게 하면 해안선에서 일정 거리만큼 떨어진 곳에서 물결이 일어나도록 할 수 있고, 사인파와 일부 왜곡 텍스처를 사용해 흥미로운 시각 효과를 줄 수 있습니다.

결과적으로, 에디터 툴을 사용하여 네 가지의 설정된 수위를 기준으로 해안선의 부호화된 거리를 베이크했습니다. 그런 다음, 대부분의 레벨에서 플레이어 진행 상황에 따라 수위가 변하기 때문에 해안선의 실제 위치를 대략적으로 근사하기 위해 이들을 블렌딩 및 선형 보간했습니다. 이렇게 미리 베이크한 SDF 정보를 활용하여 바다 파도 높이를 조정하고 거품, 물결, 커스틱 효과 등을 추가했습니다.


프레임 구성
렌더링된 프레임의 대략적인 구성
렌더링된 프레임의 대략적인 구성. 빨간색으로 표시된 패스는 커스터마이즈된 것입니다.
시각적 상호 작용

시각적 상호 작용을 위해 플레이어, 운반 가능한 오브젝트, 툴 등 위치를 추적해야 하는 모든 항목을 각각 둘러싼 캡슐을 톱다운 뷰로 렌더링하여 RenderTexture로 저장했습니다. 이 텍스처는 월드 공간을 기준으로 하며, 플레이어의 카메라가 움직일 때 슬라이딩 윈도우 방식으로 업데이트됩니다.

그런 다음 캡슐 중심의 오프셋(빨간색, 파란색)과 월드 공간 높이 정보(녹색)를 생성하고, 알파 채널에는 강도의 감쇠 값을 저장합니다. 이 값은 초목의 흔들림, 수면의 애니메이션화된 잔물결과 같은 효과를 만들거나, 터레인을 약간 어둡게 하여 소프트 섀도우 효과를 생성하는 등 다양한 셰이더에 사용됩니다.

플레이어와 오브젝트 주변의 RenderTexture ‘캡슐’에 셰이더를 적용하면, 그림자나 물 속의 물결 흔적 같은 효과로 오브젝트가 월드에 더 자연스럽게 자리 잡은 것처럼 보이게 만들 수 있습니다.
각 플레이어와 옮길 수 있는 오브젝트 주변의 RenderTexture ‘캡슐’에 셰이더를 적용하면, 그림자나 물 속의 물결 흔적 같은 효과로 오브젝트가 월드에 더 자연스럽게 자리잡은 것처럼 보이는 효과를 만들 수 있습니다.
뎁스 및 디더링 프리패스

성능 최적화를 위해, 뎁스 프리패스를 사용하여 오브젝트를 일반적인 방식으로 렌더링하기 전에 뎁스 버퍼를 채움으로써 조기 뎁스 테스트에서 가려지는 오브젝트를 미리 걸러내는 작업을 통해 오브젝트 렌더링 비용을 줄였습니다.

SMAA 패스에서 블러 처리를 위해 스텐실을 사용하고, 지오메트리 뒤를 보기 위해 디더링 패턴으로 뎁스를 미리 채웠습니다.
SMAA 패스에서 블러 처리를 위해 스텐실을 사용하고, 지오메트리 뒤를 보기 위해 디더링 패턴으로 뎁스를 미리 채웠습니다.

디더링된 오브젝트를 커스텀 패스에서 별도로 처리했는데, 오브젝트의 상태나 어떤 플레이어가 오브젝트를 보는지에 따라 렌더링 방식이 달라야 했기 때문입니다. 이 오브젝트들은 렌더러의 불투명 레이어 마스크에서 제외된 다른 게임 오브젝트 레이어에 있기 때문에 자동으로 렌더링되지 않으며, 따라서 커스텀 패스에서 렌더링해야 합니다. 팀에서는 MaterialPropertyBlock을 사용하여 오브젝트의 개별 값을 설정하고, 디더링된 오브젝트를 표시하는 스텐실을 적용하여 나중에 블러 처리할 수 있게 했습니다. 하지만 이렇게 하면 SRP 배칭이 올바르게 작동하지 않으므로 사용을 제한해야 했습니다. 따라서 필요할 때만 MaterialPropertyBlock을 적용하고 작업이 완료되면 제거하여 오브젝트를 다시 배칭 가능한 상태로 되돌리기로 했습니다.

결과적으로 특정 레이어를 뎁스 버퍼에 렌더링하는 방법을 처리하는 전체 패스를 갖게 되었습니다. 그 다음으로는 뎁스 버퍼에 스텐실을 적용하여 어떤 픽셀이 사라지는 오브젝트의 일부인지 표시하고, 이러한 정보는 나중에 안티앨리어싱을 처리할 때 사용했습니다.

그레디언트 그림자

팀이 지향하는 아트 스타일은 그림자의 방향을 따라 그레디언트 방식으로 변화하는 색상 그림자를 포함하는 것이었습니다. 이를 위해 RenderFeature로 생성한 커스텀 스크린 공간 텍스처를 사용하여 섀도우 맵을 월드 공간에서 샘플링하고, 동시에 XZ 평면을 따라 그림자가 이어지는 부분을 확인하여 그림자 블렌드 값을 결정했습니다. 이는 소프트 섀도우에 사용되는 PCF 필터와 유사하지만 한 방향으로만 작동합니다. 이 텍스처는 화면 크기의 약 1/4 정도로 축소되어 렌더링되었고, 팀은 그림자 색상을 세 가지 색상 사이에서 블렌딩했습니다.

그림자의 저해상도 스크린 공간 패스에서 에지 그레디언트 색상을 생성하고, 광원 방향으로 그레디언트를 만듭니다. 이는 나중에 쌍선형 샘플링을 통해 처리됩니다.
그림자의 저해상도 스크린 공간 패스에서 에지 그레디언트 색상을 생성하고, 광원 방향으로 그레디언트를 만듭니다. 이는 나중에 쌍선형 샘플링을 통해 처리됩니다.
MSVAO(멀티 스케일 볼류메트릭 앰비언트 오클루전)

안타깝게도 URP와 함께 제공되는 SSAO는 팀의 요구 사항과 잘 맞지 않았습니다. 모바일 친화적인 구현이기는 하지만 목표로 하는 비주얼을 위해서는 반경 값을 상당히 높게 설정해야 했으며, 이는 프레임 예산의 상당 부분(약 4ms)을 차지했습니다. 그 대신 이전 PostProcessing Stack v2 패키지의 MSVAO 구현을 재사용했고, 여기에 일부 사소한 수준의 변경을 적용하여 효율성을 높였으며 그림자 색상을 통합했습니다.

PostProcessing Stack v2 패키지의 MSVAO를 커스터마이즈하고 사소한 수준의 조정을 적용하여 타겟 플랫폼에서 성능을 향상시킨 버전을 보여 주는 섬 씬
PostProcessing Stack v2 패키지의 MSVAO를 커스터마이즈하고 사소한 수준의 조정을 적용하여 타겟 플랫폼에서 성능을 향상시킨 버전
씬 드로우

Survival Kids에는 URP에서 사용할 수 있는 표준 렌더링 패스(불투명, 스카이박스, 투명)가 포함되어 있지만, 불투명 패스 직후 디더링된 오브젝트를 처리하기 위한 추가 패스도 있습니다. 이 추가 패스에서 실제로 디더링 처리된 지오메트리를 렌더링하게 되는데, 이 레이어의 지오메트리가 불투명 패스에서 렌더링되지 않기 때문입니다. 또한 이 패스에서는 Depth Equals 테스트를 수행하여, 미리 채워진 뎁스 버퍼 영역에서만 렌더링이 이루어지도록 합니다.

디더링 처리된 오브젝트의 지오메트리 드로잉(Depth Equals 테스트). 이 상태에서는 앰비언트 오클루전이 비활성화됩니다.
디더링 처리된 오브젝트의 지오메트리 드로잉(Depth Equals 테스트). 이 상태에서는 앰비언트 오클루전이 비활성화됩니다.

디더링 처리된 오브젝트의 경우, MSVAO가 뎁스 버퍼의 ‘구멍’을 오클루전으로 처리하면서 발생하는 아티팩트 때문에 앰비언트 오클루전을 비활성화해야 합니다.

SMAA + 디더링에 블러 처리를 사용한 시각 효과를 보여주는 게임 이미지
SMAA + 디더링에 블러 처리

씬을 렌더링한 후에는 안티앨리어싱을 적용합니다. 하지만 디더링 처리된 영역에서는 알고리즘(SMAA) 오류로 인해 시각적 아티팩트가 발생합니다. 이를 방지하려면 이러한 영역을 별도로 처리해야 합니다. 디더링 처리된 영역(스텐실로 결정)은 블러 처리되어 해당 영역에 알파 블렌드 효과를 생성하며, 그런 다음 디더링되지 않은 영역에 SMAA가 적용됩니다. 특정 상황에서는 이 과정이 생략되기도 하지만, 결과적으로는 포스트 프로세싱을 위해 정리된 최종 이미지가 생성됩니다.

포스트 프로세싱 및 UI

팀에서는 포스트 프로세싱 효과를 최대한 가볍게 유지했으며, 약간의 톤 매핑, 블룸 및 색상 보정만 사용했습니다.

전에는 UI 뒤의 게임 화면을 부드럽게 보이게 하기 위해 포스트 프로세싱에서 URP의 블러 기능을 사용했지만, 나중에는 비용이 더 낮은 Kawase 블러 RenderFeature로 교체했습니다. UI 시스템은 UGUI를 기반으로 하며, 일부 페이드 처리를 위한 커스텀 렌더링이 적용됩니다.

Survival Kids의 UI
Survival Kids의 UI

처음 UI를 설정할 때는 메뉴가 페이드 인/아웃되도록 했지만, UI에 대한 알파 처리 방식 때문에 문제가 발생했습니다. 처음에는 카메라를 통해 UI를 별도의 텍스처로 렌더링한 다음, 올바르게 blit 처리하여 메인 이미지에 UI의 페이드 효과를 적용했습니다. 하지만 이후에는 전체 추가 카메라 없이 RenderFeature를 사용하여 동일한 효과를 구현하도록 변경했습니다.

유니티 블로그 시리즈의 다른 게시물을 읽고 Survival Kids 제작 과정에 대해 자세히 알아보세요.
- 그래픽스 및 렌더링 팁 - Survival Kids
- Survival Kids의 레벨 레이아웃 및 터레인 워크플로
- Survival Kids의 멀티플레이어 네트워크 인프라 자세히 알아보기