
읽기 전에: 날씨 시스템(환경 제어 시스템)은 게임의 품질감과 몰입감을 크게 끌어올립니다. 이 글은 상·하 두 편으로 구성되며, 상편에서는 날씨 시스템이 보통 어떤 구성과 일을 담당하는지 정리한 뒤, 로직 프레임워크 관점의 설계 아이디어와 실제 적용 사례를 공유합니다. 핵심은 컴포넌트화, 보간(Interpolation)·오버라이드(Override) 로직, 코드 자동 생성(Source Generator)의 세 가지입니다. 필자는 넷이즈 레이훠(网易雷火)의 브루스로, 환경 표현 관련 렌더링 분야에서 약 10년의 경험을 가지고 있습니다. 2015년에 레이훠에 합류했으며, 참여한 프로젝트로는 逆水寒, 콘솔 싱글 프로젝트, 逆水寒 모바일, 永劫无间 모바일 등이 있습니다.
날씨 시스템 개요
날씨 시스템의 영어 명칭은 TOD(Time of Day) 입니다. TOD가 맡는 일은 시간, 날씨, 시나리오/연출 애니메이션, 게임플레이, 지역 등에 따라 서로 다른 환경 설정을 전환하고, 최종적으로 플레이어에게 더 풍부한 렌더링 결과를 제공하는 것입니다.
기능적으로 날씨 시스템은 크게 두 부분으로 나뉩니다.
환경 표현
대표적인 환경 표현 요소는 다음과 같습니다.
- 조명: 메인 라이트, 환경광, GI, 캐릭터/이펙트의 환경별 보정(예: 보조광, 노출 조정 등)
- 하늘: 물리 대기(Atmosphere), 핸드페인트 스카이박스
- 구름: 2D 구름, 절차 노이즈 기반 볼류메트릭 클라우드, 고정 형태 볼류메트릭 클라우드, 운해, 파티클 빌보드 구름
- 안개: 대기 안개, 지수 높이 안개, 볼류메트릭 포그, 배치형 라이트 포그
- 비/눈: 파티클, 머티리얼 표현(젖음/물결/적설), 변형 눈(Deformation Snow)
- 기타: 태양/달, 별, 오로라, 풍력 등
아래에서는 아직도 비교적 활발히 연구되는 몇 가지 방향을 간단히 소개합니다.
볼류메트릭 클라우드

trueSKY, Horizon 2015, RDR2 2019, Horizon 2022

UE VDB Clouds, Horizon 2023
노이즈 관점에서 볼류메트릭 클라우드는 크게 두 가지로 나눌 수 있습니다. 절차 노이즈 기반(예: trueSKY, Horizon 시리즈, RDR2) 과 물리 시뮬레이션 기반(예: UE5 VDB Clouds, Nubis3 Clouds) 입니다. 절차 노이즈 방식은 “클라우드 형태가 동적으로 변화하지 못한다”는 문제를 해결하려는 맥락에서 자주 사용되고, 물리 시뮬레이션 방식은 형태가 더 자연스럽거나 더 제어 가능하다는 장점이 있습니다. 다만 Nubis3의 경우 큰 형태는 잘 변하지 않아, 기술이 한 바퀴 돌아오는 느낌도 있습니다.
아티스트가 절차 노이즈 기반 구름에 대해 자주 불만을 가지는 지점은 두 가지입니다. (1) 가장자리 디테일 정밀도, 하부 조명 변화의 풍부함 같은 “결과 품질”과, (2) 형태를 얼마나 편하게 편집할 수 있는지 입니다. trueSKY는 디테일 정밀도는 높지만 물리적으로는 다소 비현실적인 계열에 가깝고, 나머지 엔진/구현은 또 다른 스펙트럼에 놓입니다. 어느 쪽이 더 낫다고 단정하긴 어렵고, 취향과 프로젝트 요구에 따라 갈립니다.
볼류메트릭 포그

bwronski 2014, Frostbite 2015, RDR2 2019, TLOU2 2020

NVIDIA 테셀레이션 기반 볼류메트릭 라이트
첫 번째 이미지는 주류 접근으로, 3D 텍스처를 뷰 프러스텀 내부에 매핑하고 모든 계산을 3D 텍스처 공간에서 수행합니다. TLOU2(2020)는 여기에 대해 몇 가지 깊은 최적화를 적용했습니다. 또한 점광/스포트라이트 감쇠를 프리베이크하는 방식은 실제로 시도해 본 적이 있는데, 점광은 효과 대비 이득이 큰 편인 반면 스포트라이트는 구현이 복잡하고 성능 손실도 생겨, 보통은 IES 프로파일 같은 커스텀이 필요한 경우가 아니라면 비용 대비 효율이 낮았습니다.
두 번째 이미지는 비교적 비주류 접근으로, GPU 테셀레이션으로 볼류메트릭 라이트용 메시를 구성합니다. Fallout 4에서 이 방식이 사용되었습니다.
변형 눈(Deformation Snow)

Tomb Raider, TLOU, RDR, God of War

Batman, Horizon
대상을 기준으로 보면 두 가지로 나눌 수 있습니다. (1) 캐릭터에 바인딩된 앵커를 “찍는” 방식, (2) 변형을 유발하는 물체 자체를 “찍는” 방식입니다. 전자는 가장자리 융기 같은 효과를 비교적 쉽게 만들 수 있고, 후자는 발자국/자국 형태가 물체에 더 잘 맞으며 아티스트가 앵커를 바인딩/편집할 필요가 줄어듭니다.
렌더링 방식으로도 분류할 수 있는데, (1) 테셀레이션, (2) 패럴랙스 매핑으로 깊이(Depth)를 쓰는 방식입니다. 테셀레이션은 디테일이 다소 적을 수 있으나 카메라를 낮춰도 티가 덜 나며, 저사양 AMD GPU에서 성능이 그리 좋지 않을 때가 있습니다. 흥미롭게도 God of War 최신 세대는 패럴랙스에서 다시 테셀레이션으로 회귀했습니다.
로직 처리
환경 설정의 보간/오버라이드와 관련해 자주 등장하는 로직 요구 사항은 예를 들어 다음과 같습니다.
- 타임라인 기반 환경 간 보간 전환
- 던전 진입 또는 시나리오/연출 애니메이션이 외부 환경을 덮어쓰는(override) 처리
- 타임라인 보간 전환 중에 비/눈 같은 날씨 보간 전환을 추가로 도입
- 비/눈 날씨 환경은 타임라인 중 일부 파라미터만 덮어쓰는 형태(예: 구름, 안개 농도만 변경)
- 두 환경의 렌더링 토글(스위치)이 서로 다름(예: 한쪽은 2D 구름 ON, 다른 쪽은 OFF)
- 보간이 어려운 파라미터(예: 텍스처)
- 주야 전환 시 “더블 메인 라이트”가 대기/볼류메트릭 클라우드에 미치는 처리
- 연출 환경이 끝난 뒤 몇 분 뒤에 사라지게 해서 몰입감을 강화
다음 장에서는 보간/오버라이드 로직의 전체 구조를 소개하지만, 위 요구 사항을 하나씩 해결하는 개별 솔루션을 모두 제공하진 않습니다.
설계와 실전 적용
날씨 시스템의 목표는 환경 관련 렌더링 기능(Feature)을 하나의 프레임워크로 통합하고, 환경 편집과 타임라인 기반 환경 보간을 제공하며, 코드 구조는 읽기 쉽고 반복 개선이 가능해야 합니다. 또한 사용성 측면에서도 진입장벽이 낮아야 합니다.
구체적으로는 다음 다섯 가지 목표로 정리할 수 있습니다.
- 모든 Feature를 씬에 배치되는 컴포넌트 형태로 제공한다. 씬의 건축 요소와 함께 놓여 있어 위치 파악과 편집이 쉬워지며, 별도 문서/교육 없이도 누구나 씬에서 특정 Feature를 손쉽게 켜고 끌 수 있다. 이는 버그 원인 추적이나 특정 간섭 제거에 매우 유용하다.
- Feature 간 디커플링: Feature끼리도, Feature와 EnvironmentMgr 사이도 결합도를 낮춘다.
- 환경 편집 패널은 활성화된 Feature의 설정만 표시한다.
- 새 Feature 추가 시 특정 클래스 몇 개와 인터페이스 구현만으로 확장할 수 있게 하고, 기존 코드는 거의 건드리지 않는다. (현 버전에서 바뀌는 곳은 2군데: Editor의 add 컴포넌트 메뉴 추가, FeatureProfile↔Id 매핑. 이후 Source Generator로 제거 가능)
- 보간, 복사 등의 코드는 Source Generator로 IDE에서 실시간 자동 생성한다.

왼쪽: Feature를 컴포넌트로 씬에 배치 / 오른쪽: 활성 Feature만 편집 패널에 표시
이 목표들을 중심으로, 아래 두 파트로 설명합니다.
- 컴포넌트화 + 보간/오버라이드 로직
- 코드 자동 생성
컴포넌트화, 보간 및 오버라이드 로직

코드 조직 구조
각 Feature는 FeatureComponent를 상속하는 컴포넌트(예: Atmosphere, VolumetricCloud)를 가지며, 각자 FeatureRenderer(URP의 RenderFeature), 씬 기본 설정(DefaultSetting)을 가집니다. 활성화된 컴포넌트는 EnvironmentMgr에 등록되며, 이 매니저가 컴포넌트를 통합 업데이트합니다. 업데이트 작업에는 런타임에서의 “최종 환경 설정” 반영이 포함되고, 이 최종 환경 설정은 Timeline 모듈에서 가져옵니다.
각 Feature 컴포넌트는 생성 시 씬의 기본 설정(DefaultSetting) 을 바인딩합니다. 파라미터는 조정할 수 있지만 참조 자체는 바꿀 수 없게 해서(레퍼런스가 비는 문제 방지) 안정성을 확보합니다. 아래는 PC 볼류메트릭 클라우드 컴포넌트의 인스펙터 예시입니다.

PC 볼류메트릭 클라우드 컴포넌트: Feature Renderer + Default Setting
환경 설정에는 오버라이드를 켠 Feature의 설정 인덱스만 기록합니다. 각 Feature의 설정 타입에는 ProfileVariantId가 있고, 이는 “해당 설정 타입 전체 개수” 범위 내의 0부터 시작하는 인덱스입니다. 환경 설정을 로드하면, 기록된 Feature 설정을 ProfileVariantId에 따라 배열의 해당 슬롯(버킷)에 넣습니다.

로드된 설정은 ProfileVariantId에 따라 버킷에 배치
보간을 수행하기 전에, 씬 기본 설정 + 환경에서 오버라이드된 설정을 합쳐 “완전한 런타임 설정”을 구성합니다. 이후에는 런타임 설정끼리만 보간하면 되므로, “오버라이드 여부”, “설정 존재 여부(널 여부)” 같은 다양한 예외를 매번 처리할 필요가 없습니다.

기본 설정과 오버라이드를 결합해 최종 설정 구성
전통적인 환경 매니저 방식은 각 기본 환경에 “완전한 Feature 설정”을 모두 기록합니다. 하지만 물리적으로 자연스러운 결과를 위해 환경마다 따로 조정해야 하는 파라미터는 의외로 적습니다. 예를 들어 아래 영상의 볼류메트릭 클라우드 설정은 씬 기본 설정을 그대로 사용하고, 환경에서 따로 조정하지 않았습니다.

볼류메트릭 클라우드 파라미터는 고정, 태양 각도와 대기만 조정
이 새로운 방식은 계층적으로 조정하기 쉬우며, 각 환경은 꼭 필요한 설정만 저장/조정하므로 환경 간 중복 데이터를 줄일 수 있습니다. 또한 사용자는 환경 편집기를 열지 않아도, 씬에서 개별 Feature를 확인·조정할 수 있습니다.
코드 자동 생성
현대 C# IDE는 “클래스 밖에서 private 멤버에 접근했다” 같은 코드 분석을 해줍니다. 이와 유사하게 .NET Compiler Platform(Roslyn) 은 코드 분석 API를 제공하며, 이를 이용해 Analyzer를 직접 작성해 컴파일러가 얻는 구문/의미 정보를 기반으로 코드를 생성할 수 있습니다. Analyzer는 DLL로 빌드해 Unity에 넣고 RoslynAnalyzer 태그를 붙이면, Unity에서 C# 프로젝트를 생성할 때 해당 Analyzer가 함께 동작합니다.

프로젝트에서는 자동으로 “복사/보간 코드”를 생성해야 하는 partial class에 CopyableClass, InterpolableClass 같은 Attribute를 붙입니다. Analyzer는 해당 Attribute가 붙은 클래스만 처리하고, 구체적인 생성 로직은 여기서 생략합니다.

사용 시에는 Attribute만 붙이고, 분석기에서 필터링
일반적인 사용법은, 수동 작성 코드와 자동 생성 코드가 static partial 메서드로 연결되는 형태입니다. 수동 코드에서 메서드 선언만 하고, 자동 생성 코드에서 구현을 제공합니다. 다만 이 방식에는 “반환값 불가”, “out 파라미터 불가”, “접근 지정자 제약” 같은 제한이 있으며, 자동 생성 코드와 수동 코드가 같은 DLL 안에 있어야 합니다.

DeepCopyImpl / LerpImpl 선언

자동 생성된 구현
하지만 각 설정 타입마다 이런 코드를 반복해서 4줄씩 작성해야 하는 점이 번거로워, 이후에는 “디스크로 코드 생성” 방식으로 전환하며 이 패턴을 대부분 버렸습니다. Roslyn Source Generator는 본래 생성 코드를 디스크에 저장하지 않지만, Unity에서도 Source Generator를 지원하는데 왜 디스크 저장이 필요했을까요?
반복 코드 제거도 이유지만, 더 큰 이유는 Source Generator 성능 문제였습니다. 최신의 Incremental Generators는 성능이 크게 개선되었지만 Unity가 이를 지원하지 않았습니다. Incremental Generators를 쓰기 위해 IDE에서 코드가 생성되게 하고, Analyzer가 생성 코드를 디스크 파일로 기록하도록 하여 버전 관리에 포함시키면 더 통제 가능해집니다.
다만 디스크 기록은 또 다른 문제를 만듭니다. IDE에서 코드를 편집하면 Generator가 실행되고, 파일이 디스크에 써지면 그 변화가 다시 트리거되어 또 생성… 이런 식의 반복이 발생할 수 있습니다. Rider에서는 디스크 쓰기가 반복되는 문제가 나타났고, VS 2022에서는 에러로 이어질 수 있었습니다.
현재는 매크로로 생성 코드 영역을 분리하는 방식으로 해결했습니다. Unity에는 ENABLE_GENERATED_CODE 매크로를 추가하고, C# 프로젝트에서는 해당 매크로를 제거(IDE용 C# 프로젝트 생성 패키지 수정 필요)합니다. 이렇게 하면 생성 코드는 Unity에서만 보이므로 정상 동작하고, IDE에서는 보이지 않아 디스크 쓰기 루프나 에러를 피할 수 있습니다.
디스크 저장 방식으로 바꾸면 static partial의 번거로움을 피할 수 있습니다. 예를 들어 베이스 클래스는 아래처럼 선언하고, 수동 작성 자식 클래스는 별도 선언 없이도, 자동 생성된 자식 클래스가 override 구현을 직접 생성해 넣으면 됩니다.

베이스 클래스 선언(매크로로 구분)

IDE에서 즉시 생성(회색 코드는 매크로로 분리되어 표시)
속성 보간에 대해서는, Unity Volume 시스템처럼 다양한 타입을 VolumeParameter로 래핑하고 각 타입이 보간 인터페이스를 구현하며 OnEnable에서 리플렉션으로 파라미터를 수집하는 방법도 있습니다. 그러나 이렇게 래핑하면 Odin Inspector 사용이 불편해져 별도의 Drawer 구현이 필요하므로, 이 글의 사례에서는 그 방식을 선택하지 않았습니다.
이상으로 날씨 시스템 주제 공유 상편을 마칩니다. 도움이 되었길 바랍니다. 다음 편에서는 세 가지 렌더링 효과(3D 번개, 스톰 클라우드, 지표면에 붙는 운해)를 다룰 예정이니 기대해 주세요.
레이훠 스튜디오의 다른 토픽
https://techartnomad.tistory.com/747
[번역] 넷이즈 레이훠(LGDC) 시리즈|모바일 파이프라인 상수 소개 및 구현 공유
저자: 网易游戏 레이훠(雷火) 사업부도입: 모바일 파이프라인 상수(Pipeline Constants)는 Vulkan/Metal 그래픽스 API에서 제공되는 기능으로, GraphicsPipeline을 생성할 때 특정 상수 값을 지정할 수 있게 해
techartnomad.tistory.com
'TECH.ART.FLOW.IO' 카테고리의 다른 글
| [번역][NVIDIA] Depth Precision Visualized (0) | 2026.05.25 |
|---|---|
| [번역] 넷이즈 레이훠 LGDC 시리즈 게임 개발에서 비바람을 부르는 마법(하편): 3D 번개, 폭풍운, 지표면 구름바다 효과 공유 (0) | 2026.05.25 |
| 이 블로그를 유익하게 읽는 방법 (8) | 2026.05.24 |
| [번역] UE5 마개조 스타일라이즈드 렌더링 - Ramp 그라데이션 컬러 라이트 구현 (0) | 2026.05.24 |
| [번역] 넷이즈 레이훠(LGDC) 시리즈|모바일 파이프라인 상수 소개 및 구현 공유 (0) | 2026.05.24 |