Skip to content

멀티플레이어 크리에이터 월드를 위한 브라우저 3D 오픈 월드 기술

우리는 크리에이터를 공유 오픈 월드에 넣고 싶습니다. 로비가 아닙니다. 갤러리도 아닙니다. 사람들이 탐험하고, 짓고, 서로의 작업물을 우연히 마주칠 수 있는 살아있는 3D 공간입니다. 브라우저 탭에서 로드되고 머물 만한 장소처럼 느껴지는 무언가입니다.

이건 어려운 문제입니다. Skyrim과 The Witcher 3는 세계를 만드는 데 수억 달러를 썼고, 그러고도 수십 기가바이트짜리 디스크 용량과 전용 하드웨어에서 출시됩니다. 우리가 노리는 건 브라우저 탭, 수백 명 플레이어에 걸친 공유 상태, 그리고 크리에이터가 실제로 다시 빚을 수 있는 세계입니다.

이 가이드는 우리가 기술을 연구하며 찾아낸 것을 기록합니다. 오늘 가능한 것, 다가오는 것, 그리고 어떤 아키텍처가 우리를 거기로 데려다줄지를 다룹니다.

Skyrim과 The Witcher에서 배울 수 있는 것

기술을 고르기 전에, 가장 성공한 두 오픈 월드가 실제로 어떻게 작동하는지 이해하면 도움이 됩니다. 그들의 기법은 의외로 브라우저 제약에 잘 들어맞습니다.

Skyrim의 Cell 시스템

Skyrim의 오픈 월드는 플레이어 주변으로 5x5 cell 그리드를 스트리밍합니다. 멀리 있는 산은 저해상도 임포스터입니다. 여러분은 전혀 눈치채지 못합니다.

Skyrim은 세계를 57x37개의 외부 cell 그리드로 나누며, 각 cell은 4096x4096 게임 단위(대략 59미터)입니다. 엔진은 어느 순간이든 플레이어 주변 5x5 cell 그리드를 로드합니다. 걸어가면 뒤쪽 가장자리의 cell이 언로드되고 앞쪽 가장자리의 cell이 스트리밍되어 들어옵니다. 내부 공간(던전, 건물)은 문 트리거로 로드되는 별도의 worldspace입니다.

이건 브라우저 월드에 그대로 적용됩니다. 전체 맵을 로드하지 않습니다. 플레이어 주변 동네를 로드하고 그가 움직임에 따라 청크를 교체합니다. 핵심 통찰은 이렇습니다. Skyrim은 멀리 있는 지형의 전체 디테일을 절대 보여주지 않습니다. 다중 해상도 방식을 씁니다.

Skyrim의 LOD(Level of Detail) 단계:

  • 1-2 cell 안에서 전체 디테일(플레이어 바로 주변 영역)
  • 중거리에서 단순화된 메시(물체는 작은 지오메트리를 잃음)
  • 중거리 너머의 나무와 바위는 빌보드 임포스터
  • 지형 LOD는 먼 풍경에 미리 구운 저해상도 메시를 사용
  • 물체 페이드 거리는 물체별로 튜닝(풀이 가장 먼저 사라지고 건물이 가장 마지막)

Skyrim의 풍경은 cell당 32x32 정점 패치를 가진 하이트맵 기반 지형을 씁니다. 각 패치는 알파 맵으로 블렌딩한 다른 텍스처를 가질 수 있습니다. 이건 저장과 렌더링이 저렴합니다. 단일 cell의 지형 데이터는 메가바이트가 아니라 킬로바이트 단위로 측정됩니다.

우리가 적용할 수 있는 것: 청크 기반 스트리밍, 하이트맵 지형, 공격적인 LOD, 내부/외부 분리, 그리고 멀리 있는 지형은 기하학적으로 정확할 필요 없이 시각적으로 설득력만 있으면 된다는 발상입니다.

The Witcher 3의 스트리밍 아키텍처

The Witcher 3의 136 km2 세계는 콘텐츠 인식 스트리밍을 씁니다. 200m 너머의 나무는 평평한 임포스터입니다. 건물은 지형과 독립적으로 스트리밍됩니다.

The Witcher 3의 세계는 Skyrim보다 큽니다(전 지역 합쳐 대략 136 km2). 더 정교한 스트리밍 시스템을 씁니다. CD Projekt RED는 세계를 엄격한 그리드가 아니라 스트리밍 섹터로 나누는 커스텀 엔진(REDengine 3)을 만들었습니다.

각 섹터는 콘텐츠 레이어의 계층 구조를 담습니다:

  • 지형은 4개의 LOD 레벨을 가진 패치로 스트리밍됩니다
  • 식생은 GPU 인스턴싱과 거리 기반 컬링을 씁니다
  • 정적 지오메트리(건물, 바위)는 지형과 독립적으로 스트리밍됩니다
  • 게임플레이 오브젝트(NPC, 아이템, 트리거)는 퀘스트 상태와 근접도에 따라 로드됩니다

렌더러는 물리 기반 머티리얼을 사용하는 디퍼드 셰이딩을 씁니다. 특히 관련 있는 한 가지 트릭이 있습니다. The Witcher 3는 임포스터를 공격적으로 씁니다. 200미터 떨어진 나무는 가지와 잎이 있는 3D 모델이 아닙니다. 항상 카메라를 향하는 평평한 텍스처 쿼드입니다. 엔진은 이 임포스터를 여러 각도에서 미리 렌더링하고 카메라가 움직이면 교체합니다. 충분히 멀리 있어서 여러분은 전혀 눈치채지 못합니다.

월드 구성: The Witcher 3의 오픈 월드는 별도의 팀이 동시에 작업하며 레이어로 구축했습니다. 지형 팀은 풍경을 조각했습니다. 환경 아트 팀은 구조물을 배치했습니다. 퀘스트 팀은 트리거와 NPC 경로를 연결했습니다. 이 레이어 구성 시스템 덕분에 대규모 팀이 서로 방해하지 않고 작업할 수 있었습니다.

우리가 적용할 수 있는 것: 레이어 월드 구성(크리에이터 플랫폼에 중요), 먼 물체를 위한 임포스터 렌더링, 많은 광원을 위한 디퍼드 렌더링, 그리고 스트리밍은 콘텐츠 인식이어야 한다는 통찰(볼 수 없는 내부를 로드하지 말고, 가까이 있지 않은 NPC를 스폰하지 말 것)입니다.

Breath of the Wild의 화학 엔진

BotW는 태블릿급 하드웨어에서 돌아가는데도 멋집니다. 셀 셰이딩 스타일, 수채화풍 거리 안개, 스크립트 콘텐츠보다 시스템적 상호작용. 양식화된 오픈 월드의 기준점입니다.

오픈 월드 디자인에 대한 닌텐도의 접근은 통상적인 공식을 뒤집었습니다. 세계를 스크립트 콘텐츠로 채우는 대신, 시스템적 규칙을 만들고 플레이어가 창발적 행동을 발견하게 했습니다. 불은 풀로 번집니다. 금속은 뇌우 속에서 전기를 전도합니다. 바람은 물체를 옮깁니다. 모든 것이 일관된 물리/화학 레이어를 통해 모든 것과 상호작용합니다.

이건 크리에이터 월드에 중요합니다. 세계 자체가 개별적으로 배치된 어떤 물체보다 더 흥미로울 수 있음을 시사하기 때문입니다. 크리에이터가 정적 메시를 배치하는 것만이 아니라 머티리얼 속성과 상호작용 규칙을 정의할 수 있다면, 세계는 창발적 행동을 얻고 아무도 명시적으로 설계하지 않은 영역조차 탐험할 가치가 생깁니다.

BotW에서 얻는 기술적 교훈:

  • 비교적 낮은 폴리곤 수와 해상도(Switch 도크 모드에서 900p). 양식화된 셀 셰이딩 외관이 낮은 충실도를 가립니다. 오늘날 브라우저 월드는 비슷한 시각적 품질을 달성할 수 있습니다.
  • 거리 렌더링은 수채화풍 스카이박스로 페이드되는 툰 셰이딩 안개를 씁니다. 렌더링이 저렴하고 실제로 아름답습니다. 이런 종류의 대기 원근은 프래그먼트 셰이더에서 사실상 공짜입니다.
  • 세계는 대략 84 km2지만 듬성듬성합니다. 맵 대부분은 통행 가능한 지형이고 관심 지점이 그 위에 흩어져 있습니다. 밀집된 콘텐츠는 마을과 사당에 남겨둡니다. 이 "듬성듬성하지만 흥미로운" 접근은 The Witcher 3의 밀집한 Novigrad에 비해 에셋 요구량을 극적으로 줄입니다.
  • 물리 물체는 상호작용을 결정하는 머티리얼 태그(나무, 금속, 음식, 폭발물)를 가집니다. 실제 규칙 수는 적지만(아마 20-30가지 상호작용 유형) 무한해 보이는 방식으로 결합합니다.

GTA V의 월드 레이어링

GTA V의 Los Santos가 살아있는 느낌인 건 레이어드 앰비언트 시스템 덕분입니다. 교통, 보행자, 시간대, 날씨. 멀리 있는 건물은 합성된 사진이지 3D 모델이 아닙니다.

Los Santos에 대한 Rockstar의 접근은 다른 교훈을 줍니다. GTA V의 세계가 살아있는 느낌인 건 모든 NPC가 퀘스트를 가져서가 아니라 레이어드 앰비언트 시스템 덕분입니다.

도시에는 도로망 위 수백 대 차량을 시뮬레이션하는 교통 시스템이 있습니다. 보행자는 경로를 걷고, 플레이어에게 반응하고, 서로 상호작용합니다. 시간대는 인구 밀도, 등장하는 NPC 유형, 앰비언트 활동을 바꿉니다. 날씨는 운전 물리와 NPC 행동에 영향을 줍니다.

크리에이터 월드에서 얻을 통찰은 앰비언트 생명이 박물관처럼 느껴지는 세계와 장소처럼 느껴지는 세계의 차이를 만든다는 점입니다. 단순한 행동(머리 위로 나는 새, 해안에 부딪히는 파도, 건물 사이를 걷는 NPC)만으로도 살아있는 세계의 환상을 만듭니다.

GTA V에서 얻는 기술적 교훈:

  • 맵은 75 km2이며 공격적인 LOD와 속도 기반 스트리밍 시스템(빠르게 운전하면 걸을 때보다 더 멀리 로드)을 결합합니다.
  • GTA Online은 이 세계에 30명의 플레이어를 동시에 넣습니다. 30명에서도 Rockstar는 공간 관심 관리가 필요하다는 걸 발견했습니다. 가까운 플레이어에 대해서는 자세한 업데이트를, 먼 플레이어에 대해서는 덜 빈번한 업데이트를 받습니다. 같은 원칙이 우리의 200명 플레이어 목표에 적용됩니다.
  • GTA V의 에셋 파이프라인은 역사상 가장 효율적인 것 중 하나입니다. 극단적인 텍스처 압축, 메시 공유, 절차적 디테일 덕분에 전체 게임이 대략 80 GB에 들어갑니다. 건물 내부는 모듈식 부품을 광범위하게 재사용합니다.
  • 게임은 정교한 임포스터 시스템을 사용하는데, 멀리 있는 건물은 실제로는 합성된 평평한 사진입니다. 전환 거리가 특정 시야각에 맞춰 튜닝되어 있어 플레이어는 전혀 눈치채지 못합니다.

Elden Ring의 심리스 오픈 월드

Elden Ring의 79 km2 맵은 듬성듬성한 개방 지형과 밀집된 수작업 던전을 섞습니다. 같은 환경 에셋이 다른 배치로 곳곳에 나타납니다. 구성과 조명이 달라지면 반복은 사라집니다.

FromSoftware는 Elden Ring을 Dark Souls와 같은 엔진 위에 만들었지만 오픈 월드로 확장했습니다. 결과가 흥미로운 이유는 (Rockstar나 CD Projekt에 비해) 비교적 작은 팀이 어떻게 큰 오픈 월드를 만들 수 있는지 보여주기 때문입니다.

비결은 밀도 변화입니다. Elden Ring의 맵은 거대하지만(대략 79 km2) 넓은 구간이 흩어진 적과 관심 지점이 있는 개방 지형입니다. 밀집된 수작업 콘텐츠(Stormveil 성 같은 레거시 던전)는 오픈 월드에 박혀 있으며 Skyrim이 쓰는 것과 같은 내부/외부 분리를 사용합니다.

Elden Ring에서 얻는 기술적 교훈:

  • 세계는 큰 타일로 스트리밍됩니다. 말 위에서는 아주 멀리 볼 수 있지만 먼 지형은 극도로 단순화됩니다. 가까이서는 디테일이 Dark Souls 3에 견줄 만합니다.
  • 로딩 화면은 빠른 이동이나 특정 던전에 들어갈 때만 나타납니다. 오픈 월드 자체는 끊김 없이 스트리밍됩니다.
  • 게임은 환경 에셋을 광범위하게 재사용합니다. 같은 나무 모델, 바위 형태, 폐허 조각이 맵 전체에 다른 배치로 나타납니다. 배치와 조명에 충분한 다양성이 있으면 반복은 눈에 띄지 않습니다. 이건 모듈식 조각 라이브러리가 무한한 다양성을 생성할 수 있는 크리에이터 월드에 그대로 적용됩니다.
  • 멀티플레이어는 세션 기반(다른 플레이어를 여러분의 세계로 소환)이지 영속적이지 않습니다. 하지만 비동기 기능(메시지, 핏자국, 다른 플레이어의 유령)은 영속 서버의 네트워킹 부담 없이 공유 존재감을 만듭니다. 이런 앰비언트 멀티플레이어 기능은 브라우저 월드에 추가하기 저렴합니다.

No Man's Sky: 모든 것을 절차적으로

공유 시드에서 생성된 1800경 개의 행성. 모든 플레이어가 서버에 저장하지 않고도 같은 우주를 봅니다. 기지 건설 데이터는 작습니다. 부품 ID와 트랜스폼뿐입니다.

No Man's Sky는 절차적 생성의 극단적 사례입니다. 공유 시드에서 생성된 1800경 개의 행성이 있어, 그중 아무것도 서버에 저장하지 않고도 모든 플레이어가 같은 우주를 봅니다.

생성 파이프라인은 단계적으로 작동합니다. 은하 레벨 시드가 항성 위치를 결정하고, 항성 시드가 행성 수와 유형을 결정하며, 행성 시드가 지형 생성(다중 옥타브 노이즈), 바이옴 할당, 동식물 종, 색상 팔레트, 자원 분포를 구동합니다. 모든 것이 시드에서 결정론적으로 계산되므로, 같은 좌표를 방문하는 두 플레이어는 어떤 행성 데이터도 교환하지 않고 같은 행성을 봅니다.

No Man's Sky에서 얻는 기술적 교훈:

  • 지형 생성은 노이즈 함수 스택을 가진 복셀 기반 마칭 큐브를 씁니다. 이는 하이트맵 지형이 표현할 수 없는 동굴, 오버행, 떠 있는 섬을 가능하게 합니다. 트레이드오프는 청크당 더 높은 연산 비용이지만, 결과는 시각적으로 더 흥미로운 지형입니다.
  • 기지 건설 시스템은 우리가 구상하는 것에 가장 가깝습니다. 플레이어가 배치한 구조물은 서버에 영속하고 다른 플레이어에게 보입니다. 기지 데이터는 작고(위치와 회전을 가진 부품 목록), 누군가 행성을 방문할 때 온디맨드로 스트리밍됩니다.
  • 게임은 무한한 다양성에도 불구하고 반복적인 콘텐츠로 초기에 비판받았습니다. 시드 기반 생성은 무한한 지형을 만들 수 있지만 놀라움은 제한적입니다. 교훈은 이렇습니다. 절차적 생성은 캔버스에는 통하지만, 어떤 장소가 설계되고 의도된 느낌을 주는 건 크리에이터가 배치한 콘텐츠입니다.
  • Hello Games는 출시 몇 년 후 멀티플레이어를 추가했습니다. 최대 32명의 플레이어가 완전한 건설과 탐험을 하며 세션을 공유합니다. 네트워크 모델은 단순합니다. 한 플레이어가 호스트하고 다른 이들이 연결합니다. 영속 상태를 가진 브라우저 월드에는 서버 권위 모델이 더 낫지만, No Man's Sky는 공유 절차적 세계가 실현 가능함을 증명합니다.

Minecraft: 크리에이터 월드의 청사진

3억 장 판매. 16x16 픽셀 텍스처. 완전히 편집 가능한 지형. 무한 생성. 멀티플레이어. 크리에이터 월드의 가장 중요한 참고점. 브라우저 클론들이 이 개념이 WebGL에서 작동함을 증명합니다.

Minecraft는 우리가 만들려는 것에 어떤 그래픽 AAA 타이틀보다 더 중요한 참고점입니다. 3억 장 판매. 세계는 무한히 생성되고, 완전히 파괴 가능하며, 멀티플레이어입니다. 크리에이터는 Minecraft에서 물체를 배치하는 데 그치지 않습니다. 지형 자체를 다시 빚습니다.

Minecraft에서 얻는 기술적 교훈:

  • 세계는 16x16x384 블록 청크로 나뉩니다. 플레이어 근처 청크만 로드됩니다(렌더 거리 설정 가능). 이건 Skyrim과 같은 청크 스트리밍 패턴이지만 완전히 편집 가능한 지형을 가집니다.
  • 각 청크는 팔레트 압축된 블록 ID 배열로 저장됩니다. 5가지 다른 블록 유형만 있는 청크는 전체 블록 ID 대신 블록당 4비트 팔레트 인덱스를 저장합니다. 이는 청크 데이터를 매우 작게 만듭니다(압축 후 보통 청크당 10-50 KB).
  • Minecraft의 멀티플레이어 프로토콜은 문서가 잘 되어 있고 비교적 단순합니다. 서버는 플레이어가 움직임에 따라 청크 데이터를 보냅니다. 블록 변경은 작은 델타 업데이트(위치 + 새 블록 유형)로 브로드캐스트됩니다. 이건 우리가 크리에이터 편집에 쓸 바로 그 모델입니다.
  • 게임은 Java로 실행되며 이제 C++로 된 Bedrock Edition도 있습니다. 핵심 개념이 WebGL에서 작동함을 증명하는 브라우저 기반 Minecraft 클론(ClassiCube, eaglercraft)이 있습니다. 이들은 보통 60fps에서 8-12 청크 렌더 거리를 처리하며, 약 200-400미터 시야를 제공합니다.
  • Minecraft의 모딩 생태계가 진짜 해자입니다. 모드는 새 블록, 엔티티, 바이옴, 게임플레이 시스템을 추가합니다. 크리에이터 월드에는 확장성이 기본 경험만큼 중요하다는 걸 시사합니다. 크리에이터가 (물체 배치만이 아니라) 새 상호작용 유형을 정의할 수 있다면, 세계는 시간이 지나며 더 풍부해집니다.
  • 레드스톤(Minecraft의 게임 내 배선 시스템)은 단순하고 조합 가능한 프리미티브를 주면 크리에이터가 복잡한 시스템을 만든다는 걸 보여줍니다. 논리 게이트, 자동 농장, 계산기. 단순한 규칙 집합이 놀라운 복잡성을 생성합니다. 이건 BotW 화학 엔진과 같은 교훈입니다.

AAA 오픈 월드 전반의 공통 패턴

이 모든 타이틀을 살펴보면 같은 패턴이 계속 나타납니다:

공간 분할은 보편적입니다. cell(Bethesda), 섹터(CD Projekt), 청크(Mojang/Rockstar), 타일(FromSoftware) 무엇이든, 모든 오픈 월드는 공간을 로드 가능한 단위로 나눕니다. 어떤 엔진도 전체 세계를 메모리에 담으려 하지 않습니다.

모든 것이 다중 해상도. 지형, 메시, 텍스처, 심지어 오디오까지 모두 여러 품질 레벨을 가집니다. 받는 해상도는 얼마나 가까운지, 그리고 물체가 얼마나 중요한지에 달려 있습니다.

오클루전 컬링은 순수 삼각형 처리량보다 더 중요합니다. 볼 수 없는 것을 렌더링하지 않는 게 볼 수 있는 것을 최적화하는 것보다 더 많은 성능을 아낍니다. Skyrim은 단순한 거리 기반 시스템을 씁니다. The Witcher 3는 큰 오클루더(건물, 절벽)를 가진 소프트웨어 오클루전을 씁니다. UE5의 Nanite 같은 현대 엔진은 하드웨어 오클루전 쿼리로 이를 한 단계 더 밀고 나갑니다.

비동기 로딩은 전환을 숨깁니다. 이 게임들은 오픈 월드에 대해 로딩 화면을 보여주지 않습니다(빠른 이동이나 내부 전환에만). 백그라운드 스레드에서 콘텐츠를 로드하고, 병렬로 압축을 풀고, 새 콘텐츠를 점진적으로 교체합니다.

폴리곤 수보다 아트 디렉션. Skyrim은 2011년에 당시에도 수수했던 그래픽으로 출시했습니다. BotW는 태블릿급 칩에서 돌아가는데도 아름답습니다. Minecraft는 16x16 픽셀 텍스처를 쓰며 역사상 가장 시각적으로 알아보기 쉬운 게임 중 하나입니다. 브라우저 월드에는 이게 엄청나게 중요합니다. 낮은 충실도라도 잘 디렉팅된 아트 스타일은 기술적으로 앞섰지만 예술적으로 밋밋한 세계를 항상 이깁니다.

스크립트 콘텐츠보다 시스템적 디자인. BotW의 화학 엔진, Minecraft의 블록 상호작용, GTA V의 교통 시스템은 모두 단순한 규칙에서 창발적 행동을 만듭니다. 이건 만들기 더 저렴하고, 운영하기 더 저렴하며, 수작업 스크립트 시퀀스보다 더 많은 플레이어 이야기를 생성합니다. 크리에이터 월드에서 시스템적 디자인은 아무도 명시적으로 설계하지 않은 영역에서도 세계가 흥미롭게 유지된다는 뜻입니다.

크리에이터가 배치한 콘텐츠는 영속성과 가시성이 필요합니다. Minecraft 기지, No Man's Sky 기지, GTA Online 부동산은 모두 세션을 가로질러 영속하고 다른 플레이어에게 보입니다. 크리에이터 콘텐츠의 데이터 모델은 항상 작은 반면(부품 ID + 트랜스폼) 시각적 표현은 풍부합니다(클라이언트가 데이터를 완전한 3D 씬으로 확장).

렌더링: 브라우저가 실제로 할 수 있는 것은?

Three.js

Three.js는 기반입니다. 가장 큰 커뮤니티(GitHub 별 10만 개 이상), 가장 많은 예제, 가장 넓은 호환성을 가집니다. WebGL 2를 추상화하며 WebGPURenderer를 통해 실험적 WebGPU 지원을 제공합니다.

오픈 월드를 위해 Three.js가 주는 것:

  • 식생, 바위, 반복 지오메트리를 위한 인스턴스드 렌더링(InstancedMesh)
  • 내장 LOD 시스템(THREE.LOD가 거리에 따라 메시 교체)
  • 물체별 자동 절두체 컬링
  • 커스텀 BufferGeometry나 하이트맵 기반 PlaneGeometry를 통한 지형
  • MeshStandardMaterialMeshPhysicalMaterial을 통한 PBR 머티리얼
  • EffectComposer를 통한 포스트프로세싱(bloom, SSAO, 톤 매핑)
  • 커스텀 코드로 캐스케이드 섀도우 매핑이 가능한 섀도우 맵
  • 주요 에셋 포맷으로서의 glTF/GLB(작고, GPU 준비됨)

Three.js에는 오픈 월드에 중요한 활발한 도구 생태계도 있습니다. three-mesh-bvh는 복잡한 메시에 대한 레이캐스팅과 공간 쿼리를 가속합니다. postprocessing(vanruesc 제작)은 Three의 내장보다 더 성능 좋은 포스트프로세싱 스택을 제공합니다. three-gpu-pathtracing은 레퍼런스 품질 렌더링을 가능하게 합니다.

오픈 월드의 한계: Three.js에는 대규모로 스트리밍, LOD 관리, 공간 분할을 처리하는 내장 씬 그래프가 없습니다. 그건 직접 만들어야 합니다. 내장 엔티티 컴포넌트 시스템(ECS)도, 물리도, 지형 시스템도 없습니다. 이건 엔진이 아니라 렌더러입니다. 메모리 레이아웃과 로딩 전략을 직접 제어하므로 커스텀 오픈 월드에는 사실 장점이지만, 초기 작업이 더 많다는 뜻이기도 합니다.

typescript
const lod = new THREE.LOD();
lod.addLevel(highDetailMesh, 0);
lod.addLevel(mediumDetailMesh, 50);
lod.addLevel(lowDetailMesh, 200);
lod.addLevel(impostorSprite, 500);
scene.add(lod);

Babylon.js

Babylon.js는 또 다른 주요 경쟁자입니다. Microsoft가 후원하며, 오픈 월드라는 특정 문제에 대해 Three.js보다 깊은 내장 기능을 가집니다.

관련 내장 기능:

  • 큰 씬의 효율적 컬링을 위한 옥트리 기반 씬 분할
  • 대규모 인스턴스드 렌더링을 위한 Solid Particle System
  • 내장 LOD와 멀티 텍스처 스플래팅을 가진 하이트맵 기반 지형
  • 시각적 셰이더 생성을 위한 노드 머티리얼 에디터
  • WebGPU 지원(Babylon이 더 일찍 투자했기에 Three.js보다 성숙)
  • Havok 물리 통합(Wasm 컴파일, 프로덕션 품질)
  • 점진적 로딩을 가진 glTF 스트리밍

Babylon의 DynamicTerrain 확장은 하이트맵 데이터에서 지형 청크를 즉석에서 생성하고, LOD를 자동으로 처리하며, 텍스처 스플래팅을 지원합니다. 이건 Three.js가 기본으로 제공하는 어떤 것보다 Skyrim이 하는 것에 훨씬 가깝습니다.

typescript
const terrain = new BABYLON.DynamicTerrain("terrain", {
  terrainSub: 100,
  mapData: heightmapData,
  mapSubX: 1000,
  mapSubZ: 1000,
}, scene);
terrain.LODLimits = [4, 3, 2, 1];

트레이드오프: Babylon.js는 더 큰 라이브러리입니다(전체 빌드는 미니파이 후 약 1-2MB, Three.js는 약 600KB). 하지만 오픈 월드에서는 Three.js에 충분히 많은 커스텀 코드를 추가하게 되어 크기 차이가 무시할 만해질 가능성이 높습니다. Babylon에는 또한 자체 노드 머티리얼 시스템, 인스펙터, 개발 도구가 있어 반복을 빠르게 합니다.

Babylon.js 8.0(2025년 3월 출시)은 여기서 엔진 코어로서의 입지를 굳혔습니다. 이제 모든 코어 엔진 셰이더가 GLSL과 WGSL 양쪽으로 제공되어, WebGPU가 변환 레이어 없이 작동하고 WebGPU 번들은 예전의 대략 절반 크기입니다. 같은 릴리스는 Havok의 완전한 캐릭터 컨트롤러를 엔진에 들여왔고, 면적 광원, 재구축된 오디오 엔진, 가우시안 스플래팅 개선(SPZ와 압축 PLY 포맷, 구면 조화, 더 낮은 메모리/CPU 사용량)을 가져왔습니다.

PlayCanvas

PlayCanvas는 언급할 가치가 있습니다. 가장 프로덕션에서 검증된 웹 우선 3D 엔진이기 때문입니다. Snap, Facebook, 수많은 광고 클라이언트가 이걸로 복잡한 3D 경험을 출시했습니다. 엔진은 약 1MB로 빠르게 로드되며, 클라우드 에디터는 협업 월드 구축을 가능하게 합니다.

오픈 월드에 한정해서 PlayCanvas는 드로우 콜 최적화를 위한 배치 그룹, 내장 라이트매퍼, 가우시안 스플래팅 지원(포토그래메트리로 캡처한 현실 세계 환경에 관련)을 제공합니다. 런타임은 탄탄하고 모바일 브라우저에 잘 최적화되어 있습니다.

WebGPU: 성능 해방

WebGPU는 브라우저 오픈 월드의 방정식을 바꿉니다. 가장 중요한 두 가지 기능:

컴퓨트 셰이더는 GPU 측 지형 생성, 식생 배치, 파티클 시뮬레이션, 심지어 단순한 물리까지 가능하게 합니다. WebGL 세계에서는 이 모든 게 CPU의 JavaScript에서 실행됩니다. WebGPU로는 지형 패치를 전적으로 GPU에서 생성하고, LOD 전환을 GPU에서 계산하고, 컬링 패스를 GPU에서 실행할 수 있습니다. 이는 네트워킹, 게임 로직, 콘텐츠 스트리밍을 위해 CPU를 풀어줍니다.

간접 렌더링은 GPU가 컴퓨트 셰이더 출력에 기반해 무엇을 그릴지 결정하게 합니다. 드로우 콜 하나를 제출하면, GPU가 거리에 기반해 각 LOD 레벨에 대해 몇 개의 인스턴스를 렌더링할지 결정합니다. 이게 현대 엔진이 수백만 개의 풀잎이나 나무를 처리하는 방식입니다. 간접 렌더링(WebGL은 지원하지 않음) 없이는 CPU가 모든 것을 정렬하고 배치해야 하며, 이는 밀집 씬에서 병목이 됩니다.

WebGPU는 이제 모든 주요 브라우저에서 제공됩니다. Chrome과 Edge는 버전 113부터 지원했고, Firefox는 Windows(141)와 Apple Silicon macOS(145)에 추가했으며, Safari 26은 2025년 말 macOS, iOS, iPadOS, visionOS에 가져왔습니다. 이로써 모바일을 포함해(Chrome for Android와 Samsung Internet도 제공) 전 세계 지원율이 약 82%에 이릅니다. WebGPU가 활성화되지 않은 구형 브라우저와 기기를 위해 여전히 WebGL 2 폴백을 유지하겠지만, 격차는 빠르게 줄었습니다.

wgsl
@compute @workgroup_size(64)
fn generateTerrain(@builtin(global_invocation_id) id: vec3<u32>) {
    let worldPos = vec2<f32>(f32(id.x), f32(id.y)) * cellSize + worldOffset;
    let height = fbmNoise(worldPos, octaves, persistence);
    heightmap[id.x + id.y * width] = height;
}

권장 렌더링 스택

데스크톱의 크리에이터를 겨냥한 브라우저 오픈 월드를 위해:

주력: Three.js 또는 Babylon.js, 가능한 곳에서는 WebGPU 렌더러, WebGL 2 폴백. Babylon은 내장 오픈 월드 프리미티브가 더 강합니다. Three.js는 더 큰 커뮤니티와 더 높은 유연성을 가집니다.

우리의 선택: 엔진 코어로는 Babylon.js. 내장 지형 LOD, 옥트리 컬링, Havok 물리(Wasm), 성숙한 WebGPU 지원 때문입니다. Babylon에 없는 곳에서는 Three.js 생태계 도구를 씁니다(예: 공간 쿼리용 mesh BVH). 모든 것을 커스텀 월드 스트리밍 레이어로 감쌉니다.

월드 스트리밍 아키텍처

이게 어려운 부분입니다. 브라우저 탭은 데스크톱에서 대략 2-4 GB 메모리(브라우저가 부과한 한계), 모바일에서 약 1 GB를 받으며 직접 디스크 접근이 없습니다. 모든 것이 네트워크를 통해 옵니다. 보이는 세계를 메모리에 유지하면서 플레이어가 움직이는 방향 바로 앞의 콘텐츠를 스트리밍하는 아키텍처가 필요합니다.

청크 기반 월드 그리드

Skyrim의 cell 시스템처럼, 세계를 규칙적인 청크 그리드로 나눕니다. 각 청크는 따로 로드, 렌더링, 언로드할 수 있는 독립 단위입니다.

청크 크기가 중요합니다. 너무 작으면 높은 오버헤드로 끊임없이 로드/언로드합니다. 너무 크면 각 청크 다운로드가 너무 오래 걸립니다. 일반적인 광대역 연결을 가진 브라우저 월드를 위해:

  • 지면 레벨에서 64x64미터 청크
  • 각 청크는 다음을 담습니다: 하이트맵 패치(2-4 KB), 텍스처 스플랫 맵(압축 16-32 KB), 인스턴스드 참조로서의 정적 메시(인스턴스 데이터 1-50 KB), 매니페스트로서의 크리에이터 배치 오브젝트(1-10 KB)
  • 로드 반경: 전체 디테일로 5x5 청크(320m 시야), 중간 LOD로 9x9, 지형만으로 17x17
  • 목표: 각 청크의 전체 디테일 데이터를 200 KB 미만으로, 그래서 5x5 동네는 5 MB 미만

점진적 로딩 파이프라인

청크에 관한 모든 것을 한 번에 로드하지 마세요. 우선순위 큐를 씁니다:

  1. 지형 지오메트리 먼저(하이트맵만, 청크당 2-4 KB). 플레이어는 100ms 안에 지면을 봅니다.
  2. 지형 텍스처(스플랫 맵, 저해상도 먼저 그다음 업그레이드). 지면은 200ms 안에 색을 가집니다.
  3. 주요 구조물(건물, 큰 바위). 실루엣이 500ms 안에 나타납니다.
  4. 디테일 오브젝트(식생, 작은 소품, 크리에이터 아이템). 세계는 1-2초에 걸쳐 채워집니다.
  5. 고해상도 텍스처가 마지막에 업그레이드됩니다. 멀리 있는 건물의 텍스처가 1초 더 걸려도 아무도 눈치채지 못합니다.

이건 사람 눈이 작동하는 방식에 맞습니다. 우리는 빠진 지면과 빠진 큰 구조물을 알아챕니다. 빠진 풀은 알아채지 못합니다.

메모리 관리

브라우저 메모리는 유한하고 가비지 컬렉터는 여러분의 적입니다. 단 한 번의 GC 일시정지가 한 프레임 동안 60fps에서 10fps로 떨어뜨릴 수 있습니다.

오브젝트 풀링은 필수입니다. 흔한 오브젝트(나무, 바위, 풀 패치)용 풀을 미리 할당하고 청크가 로드/언로드될 때 재활용합니다. 핫 패스에서 절대 새 THREE.MeshBABYLON.Mesh 인스턴스를 만들지 마세요. 대신 풀링된 오브젝트의 지오메트리와 머티리얼 참조를 교체합니다.

텍스처 아틀라스는 드로우 콜과 메모리 단편화를 모두 줄입니다. 모든 지형 텍스처를 몇 개의 큰 아틀라스로 묶습니다. 크리에이터가 업로드한 텍스처를 서버에서 청크별 아틀라스로 묶어 단일 이미지로 스트리밍합니다.

지오메트리 압축을 Draco나 Meshopt로 하면 다운로드 크기를 5-10배 줄이고, 압축 해제는 Web Worker에서 실행되어 메인 스레드를 막지 않습니다. 지형에 한정하면, 양자화된 하이트맵(단순 델타 인코딩으로 압축한 16비트 값)이 어떤 범용 메시 포맷보다 작습니다.

ArrayBuffer 소유권 이전은 worker와 메인 스레드 사이의 복사를 피합니다. worker가 메시 압축을 풀면, 전송 가능 객체와 함께 postMessage를 사용해 버퍼를 메인 스레드로 복사 없이 이전합니다.

에셋 전달

정적 월드 데이터를 위한 엣지 캐싱이 있는 CDN. 자주 바뀌지 않는 지형 청크, 베이스 메시, 텍스처 아틀라스는 공격적으로 캐싱해야 합니다(Cache-Control: max-age=31536000, immutable).

콘텐츠 주소 지정 스토리지는 각 에셋 버전이 URL에 고유한 해시를 갖는다는 뜻입니다. 크리에이터가 청크를 수정하면 새 버전은 새 해시를 얻고, 여전히 보고 있는 사람을 위해 옛 버전은 캐시에 남습니다. 캐시 무효화가 필요 없습니다.

Basis Universal 압축이 있는 KTX2 텍스처. 이들은 기기가 지원하는 어떤 GPU 포맷으로든 압축이 풀립니다(BC7, ASTC, ETC2, 또는 RGBA 폴백). 1024x1024 지형 텍스처는 비압축 4 MB에서 KTX2로 대략 150 KB가 됩니다. 수천 개의 고유한 텍스처를 가진 세계에는 이 압축이 실현 가능과 불가능의 차이입니다.

모든 3D 에셋을 위한 glTF Binary(GLB). 3D의 JPEG입니다. 모든 브라우저 엔진이 로드하고, 작으며, 텍스처, 머티리얼, 애니메이션을 단일 파일에 임베드할 수 있습니다. 메시 압축에는 Draco나 Meshopt 확장을 씁니다. 크리에이터가 업로드한 에셋은 서버 측에서 최적화된 GLB로 처리된 후 세계에 들어옵니다.

멀티플레이어 네트워킹

수백 명의 크리에이터를 같은 세계에 넣으려면 실시간 이동, 영속 월드 상태, 크리에이터 편집을 녹아내리지 않고 처리하는 네트워킹 아키텍처가 필요합니다.

서버 아키텍처

월드 상태를 위한 권위 서버. 브라우저는 신뢰할 수 없습니다. 모든 의미 있는 동작(물체 배치, 지형 수정, 청크 간 이동)은 서버 측에서 검증됩니다. 클라이언트는 로컬에서 예측하고 서버 상태와 조정합니다.

공간 샤딩은 세계를 여러 서버 인스턴스에 나눕니다. 각 샤드는 월드 그리드의 직사각형 영역을 소유합니다. 플레이어 밀도가 변하면 샤드는 분할되거나 병합될 수 있습니다. 이게 EVE Online이 한 우주에서 수천 명의 플레이어를 다루는 방식이며, 더 작은 규모에서도 같은 원칙입니다.

대부분의 상호작용이 로컬인 크리에이터 월드에서는(여러분은 자기 영역에서 짓고, 이웃은 그걸 볼 수 있음) 공간 샤딩이 자연스럽게 작동합니다. 샤드 경계에 서 있는 플레이어는 두 샤드의 콘텐츠를 모두 보는데, 이는 샤드 간 가시성 쿼리가 필요하지만 이미 해결된 문제입니다.

서버를 위한 기술 옵션:

기술강점사용 사례
Cloudflare Durable Objects엣지 배포, 자동 확장, 내장 영속성, WebSocket 지원월드 샤드 상태, 청크별 권위
Hathora / Rivet관리형 게임 서버 호스팅, DDoS 방어, 글로벌 배포전용 게임 서버 인스턴스
ColyseusNode.js용 오픈소스 게임 서버 프레임워크, 스키마 기반 상태 동기화상태 디핑이 있는 룸 기반 멀티플레이어
PartyKit엣지 배포, WebSocket + WebRTC, Cloudflare Workers 기반실시간 협업, 경량 멀티플레이어
커스텀 Rust/Go최대 제어, 인스턴스당 최고 성능저지연 물리가 필요한 고밀도 샤드

우리의 맥락(Cloudflare 인프라): Durable Objects가 자연스럽게 들어맞습니다. 각 월드 청크는 그 청크 콘텐츠의 권위 상태를 보유하는 Durable Object가 됩니다. 플레이어는 현재 청크를 담당하는 Durable Object에 WebSocket으로 연결합니다. 인접 청크로 이동하면 그 청크의 DO에 연결합니다. Durable Objects는 상태를 디스크에 자동으로 영속하므로 월드 데이터가 재시작을 넘어 살아남습니다.

클라이언트-서버 통신

신뢰성 있는 순서 보장 메시지(채팅, 월드 편집, 인벤토리, 게임 상태)를 위한 WebSocket. 플레이어가 볼 수 있는 활성 샤드당 연결 하나(보통 1-4개 연결).

신뢰성 없고 순서 없는 메시지(플레이어 위치, 애니메이션, 일시적 효과)를 위한 WebRTC DataChannel. WebRTC는 P2P가 가능하지만, 많은 플레이어가 있는 세계에서는 N² 연결을 피하기 위해 SFU(Selective Forwarding Unit)를 거쳐 실행합니다. Cloudflare Calls나 LiveKit이 SFU 역할을 할 수 있습니다.

상태 동기화는 델타 압축을 씁니다. 서버는 각 클라이언트가 본 것을 추적하고 변경 사항만 보냅니다. 크리에이터 월드에서 이건 특히 중요합니다. 월드 상태(어떤 물체가 존재하는지, 어디에 있는지, 어떤 속성을 가졌는지)는 플레이어 위치보다 훨씬 덜 자주 변하기 때문입니다. 월드 상태 업데이트는 2-5 Hz로 보내고 플레이어 위치는 20-30 Hz로 업데이트할 여유가 있습니다.

typescript
interface WorldChunkState {
  version: number;
  terrain: TerrainPatch;
  objects: PlacedObject[];
  creators: CreatorPresence[];
}

interface DeltaUpdate {
  chunkId: string;
  fromVersion: number;
  toVersion: number;
  addedObjects: PlacedObject[];
  removedObjectIds: string[];
  modifiedObjects: Partial<PlacedObject>[];
  creatorMoves: CreatorPosition[];
}

크리에이터 편집의 충돌 해결

두 크리에이터가 같은 영역을 동시에 수정할 때, 충돌 해결 전략이 필요합니다. 이게 실시간 협업 모델 선택이 중요한 지점입니다.

Last-write-wins가 가장 단순합니다. 각 물체는 어느 순간이든 단일 소유자를 가집니다. 여러분이 건물을 편집 중이면, 여러분이 놓아줄 때까지 다른 누구도 그걸 편집할 수 없습니다. 단순하고 충돌이 없지만 협업을 제한합니다.

**Operational Transform(OT)**은 Google Docs가 쓰는 것입니다. 연산은 동시 연산에 대해 변환되어 일관된 결과를 냅니다. 이건 텍스트에는 통하지만 3D 공간 연산에는 복잡해집니다. Figma는 2D 캔버스에 이것의 변형을 씁니다.

**CRDT(Conflict-free Replicated Data Types)**는 조정 없이 항상 같은 상태로 수렴하는 동시 편집을 허용합니다. 이산 물체(각각 ID와 속성을 가짐)를 가진 세계에는, 속성별 Last-Writer-Wins Register와 물체 컬렉션을 위한 Add-Wins Set의 조합이 자동 수렴을 줍니다. Yjs와 Automerge는 JavaScript용 프로덕션 품질 CRDT 라이브러리입니다.

우리의 권장: 월드 물체 상태(무엇이 존재하는지, 어디에 있는지, 어떤 속성을 가졌는지)에는 CRDT를, 공간 검증(같은 자리에 두 물체 없음, 물체는 월드 경계 안에 유지)에는 권위 서버를 씁니다. CRDT가 협업을 처리합니다. 서버가 물리를 처리합니다.

규모 다루기: 몇 명의 플레이어?

브라우저 MMO는 오늘날 존재합니다. Hordes.io는 브라우저의 한 씬에서 200명 이상의 플레이어를 돌립니다. BrowserQuest(Mozilla의 실험)는 단순한 타일 기반 세계로 수백 명을 다뤘습니다. 질문은 브라우저가 멀티플레이어를 다룰 수 있느냐가 아니라, 플레이어 수가 늘어날 때 어떤 시각적 충실도를 유지할 수 있느냐입니다.

플레이어 렌더링 예산: 보이는 각 플레이어는 메시, 애니메이션, 그리고 잠재적으로 크리에이터 맞춤 외형이 필요합니다. 60fps에서는 프레임당 16ms가 있습니다. 합리적인 예산:

  • 근거리에서 완전히 애니메이션된 50명의 플레이어: 애니메이션 + 스키닝 약 2ms
  • 중거리의 200명 플레이어(단순화된 애니메이션, 인스턴스드): 약 1ms
  • 미니맵의 점/아이콘으로 표시되는 500명 이상: 무시할 만함

이는 한 시야에 약 250명의 보이는 인구를 주는데, 크리에이터 월드에는 충분하고도 남습니다. World of Warcraft 수도도 한 시야에 200명 넘는 캐릭터를 렌더링하는 일은 거의 없습니다.

네트워크 예산: 각 플레이어가 20 Hz로 위치를 보내면 대략 40바이트 * 20 = 초당 800바이트입니다. 시야 안 200명 플레이어: 위치 데이터 160 KB/s. 월드 상태, 채팅, 크리에이터 동작을 더하면 클라이언트당 200-500 KB/s를 보게 됩니다. 광대역 능력 안에 충분히 들어가지만 압축할 가치가 있습니다.

지형 시스템

지형은 모든 오픈 월드의 기반입니다. 또한 브라우저 제약이 가장 세게 부딪히는 곳이기도 합니다. 지형은 어디에나 있고 항상 보여야 하기 때문입니다.

하이트맵 기반 지형

Skyrim처럼 하이트맵을 씁니다. 높이 값의 2D 그리드가 정점 셰이더를 통해 3D 지형을 생성합니다. 이건 임의 메시 지형보다 극적으로 작습니다.

16비트 정밀도의 4096x4096 하이트맵은 비압축 32 MB입니다. 하지만 한 번에 전부 로드하지 않습니다. 각 64m 청크는 하이트맵의 65x65 구간(16비트로 약 8.4 KB)을 씁니다. 델타 인코딩과 zlib으로 압축하면 청크당 2 KB 미만이 됩니다.

텍스처 스플래팅은 블렌드 맵으로 여러 지형 머티리얼(풀, 바위, 흙, 모래)을 칠합니다. 각 청크는 4채널 RGBA 스플랫 맵을 가지며 각 채널은 한 머티리얼의 블렌드 가중치를 제어합니다. 스플랫 맵당 4개 텍스처와 청크별로 스플랫 맵을 바꿀 수 있는 능력으로, 세계 전체에 걸쳐 시각적 다양성을 얻습니다.

현대 지형 렌더러는 가상 텍스처링(메가텍스처라고도 하며 id Software가 Rage에서 쓴 기술)을 씁니다. 런타임에 스플래팅하는 대신, 블렌딩된 지형 텍스처를 고해상도로 미리 렌더링하고 카메라가 움직임에 따라 그 타일을 스트리밍합니다. 이건 스토리지를 런타임 성능과 맞바꿉니다. WebGPU의 컴퓨트 셰이더는 가상 텍스처링에 필요한 피드백과 페이지 테이블 관리를 처리할 수 있습니다.

Clipmap 또는 Geoclipmapping

브라우저에서 큰 지형을 렌더링하려면 CDLOD(C. Dick's LOD)나 geoclipmapping 방식이 잘 작동합니다. 지형은 카메라 주변의 동심원 링 집합으로 렌더링되며, 각 링은 이전 링의 절반 해상도입니다. 카메라 가까이서는 전체 해상도 지형을 봅니다. 멀리서는 더 거친 버전을 봅니다. 지오메트리가 레벨 사이에서 모핑하므로 전환이 부드럽습니다.

이 기법은 GPU 친화적이고(링당 드로우 콜 하나), 일정한 메모리로 무한 지형을 다루며, WebGL 2에서 작동합니다. Flight Simulator와 대부분의 현대 오픈 월드 게임이 어느 정도 쓰는 것입니다.

크리에이터가 수정한 지형

크리에이터가 지형을 조각할 수 있다면, 베이스 하이트맵 위에 수정 사항을 저장하고 스트리밍하는 방법이 필요합니다. 두 가지 접근:

델타 하이트맵은 베이스 지형과 수정된 지형의 차이를 저장합니다. 세계 대부분은 수정되지 않았으므로(델타가 0) 이건 극도로 잘 압축됩니다. 청크를 로드할 때 베이스 위에 델타를 적용합니다.

복셀 오버레이는 더 극적인 수정(동굴, 오버행, 아치)을 위한 것입니다. 하이트맵은 한 점이 두 높이를 갖는 지형을 표현할 수 없습니다. 수정된 청크에만 저장된 희소 복셀 그리드가 이를 처리합니다. 마칭 큐브나 듀얼 컨투어링이 메시를 생성합니다. 이건 더 비싸지만 Minecraft 스타일 지형 편집을 가능하게 합니다.

AI 기반 월드 생성

여기가 Cinevva의 기존 생성형 AI 능력이 힘의 배율기가 되는 곳입니다. 모든 바위와 나무를 손으로 만드는 대신, 크리에이터는 AI에게 세계를 채우도록 지시할 수 있습니다.

뉴럴 필드를 이용한 지형 생성

뉴럴 지형 생성에 대한 최근 연구(NVIDIA의 GET3D, Terragen의 신경망 모드, "Terrain Generation Using Procedural Models" 같은 논문)는 훈련된 모델이 텍스트 프롬프트나 스케치 입력에서 그럴듯한 지형을 생성할 수 있음을 보여줍니다. 크리에이터가 대략적인 해안선을 그리고 "바위 해안과 만나는 숲이 우거진 언덕"이라고 말하면 적절한 침식, 식생 마스크, 머티리얼 할당을 가진 하이트맵을 얻을 수 있습니다.

브라우저 전달을 위해서는 생성을 서버 측에서 실행하고 결과를 스트리밍합니다. 생성 모델은 브라우저에서 실행될 필요가 없습니다. 브라우저가 표준 지형 파이프라인으로 렌더링할 수 있는 하이트맵과 스플랫 맵을 만듭니다.

3D 에셋 생성

Hunyuan3D, Meshy, Tripo, Rodin 같은 모델은 텍스트나 이미지에서 3D 메시를 생성할 수 있습니다. 크리에이터 월드를 위한 워크플로:

  1. 크리에이터가 원하는 것을 묘사하거나 스케치합니다("이끼 낀 돌 아치" 또는 "미래풍 가로등")
  2. 서버가 생성 모델을 실행해 하이폴리 메시를 만듭니다
  3. 서버가 자동 처리합니다: 웹 친화적 폴리곤 수로 데시메이션, LOD 생성, 텍스처를 아틀라스로 베이크, Draco 압축으로 GLB 내보내기
  4. 에셋이 크리에이터의 인벤토리에 나타나 세계에 배치할 준비가 됩니다

이 파이프라인은 Cinevva에 이미 부분적으로 존재합니다. 빠진 조각은 LOD/최적화 단계와 월드 배치 시스템입니다.

절차적 채우기

AI 생성 에셋이 있어도 숲의 모든 나무를 수동으로 배치하는 건 지루합니다. 절차적 산포 규칙은 크리에이터가 구역을 정의하게 하고("이 영역은 빽빽한 숲", "이 비탈은 바위 너덜") 시스템이 자동으로 채웁니다.

GPU 컴퓨트 셰이더가 브라우저에서 산포를 실행할 수 있습니다. 밀도 맵과 규칙 집합(최소 간격, 경사 제약, 높이 범위)이 주어지면, 컴퓨트 패스가 전체 청크의 인스턴스 위치를 1ms 미만으로 생성합니다. 밀도 맵을 수정하면 식생이 즉시 재생성됩니다.

엔티티 컴포넌트 시스템(ECS)

수천 개의 물체를 가진 오픈 월드는 효율적인 엔티티 관리 시스템이 필요합니다. ECS 패턴(Unity의 DOTS와 Bevy 이후 게임 엔진에서 인기)은 JavaScript에 잘 들어맞습니다.

bitECS는 타입화 배열과 비트 연산을 쓰는 고성능 JavaScript ECS입니다. 엔티티는 단순 정수입니다. 컴포넌트는 연속된 타입화 배열입니다(컴포넌트 유형당 하나). 시스템은 배열을 순차적으로 순회하는데, JavaScript에서도 캐시 친화적입니다.

typescript
import { createWorld, defineComponent, Types, defineQuery, addEntity, addComponent } from 'bitecs';

const Position = defineComponent({ x: Types.f32, y: Types.f32, z: Types.f32 });
const Velocity = defineComponent({ x: Types.f32, y: Types.f32, z: Types.f32 });
const ChunkRef = defineComponent({ chunkX: Types.i16, chunkZ: Types.i16 });

const world = createWorld();
const movingQuery = defineQuery([Position, Velocity]);

function movementSystem(world) {
  const entities = movingQuery(world);
  for (let i = 0; i < entities.length; i++) {
    const eid = entities[i];
    Position.x[eid] += Velocity.x[eid] * dt;
    Position.y[eid] += Velocity.y[eid] * dt;
    Position.z[eid] += Velocity.z[eid] * dt;
  }
  return world;
}

오픈 월드에서 ECS는 모든 것을 처리합니다: 플레이어 캐릭터, 배치된 물체, NPC, 파티클, 트리거, 월드 소품. 청크가 언로드되면 그 엔티티는 ECS에서 제거됩니다. 청크가 로드되면 엔티티가 추가됩니다. ECS는 공간 조직을 신경 쓰지 않습니다. 그저 컴포넌트를 처리합니다.

물리

WebAssembly 덕분에 브라우저 물리는 의외로 좋아졌습니다.

Rapier (Rust -> Wasm)

Rapier는 Rust로 작성되어 WebAssembly로 컴파일되는 물리 엔진입니다. 강체, 콜라이더, 조인트, 캐릭터 컨트롤러, 레이캐스팅을 처리합니다. 성능은 일반적인 게임 워크로드에서 네이티브 Bullet/PhysX의 2-3배 이내입니다.

오픈 월드에서 Rapier는 다음을 처리합니다:

  • 플레이어 캐릭터 컨트롤러(지형 위 걷기, 계단 오르기, 비탈 미끄러지기)
  • 물체 대 물체 충돌(배치된 물체, 발사체)
  • 플레이어 상호작용을 위한 레이캐스팅(물체를 클릭해 선택)
  • 트리거 볼륨(영역에 들어가면 이벤트 발생)

Rapier는 Web Worker에서 실행되므로 물리 시뮬레이션이 렌더링을 막지 않습니다. 매 프레임 렌더러에 위치를 보내고 입력 이벤트를 받습니다.

Havok for Web (Babylon.js 통해)

Babylon.js를 쓴다면 Havok 물리가 Wasm 모듈로 내장되어 있습니다. Havok은 대부분의 AAA 게임(Half-Life 2, Skyrim, Breath of the Wild)을 떠받치는 물리 엔진입니다. Wasm 빌드는 프로덕션 품질이며 Babylon의 씬 그래프에 최적화되어 있습니다.

지형 충돌

물리 엔진은 지형을 위한 충돌 지오메트리가 필요합니다. 전체 보이는 지형에 대해 전체 해상도 삼각형 메시를 생성하면 비쌉니다. 대신 플레이어 근처 청크(가장 가까운 3x3이나 5x5 청크)에만 충돌 하이트필드를 생성하고 나머지에는 단순화된 충돌을 씁니다. Rapier의 하이트필드 콜라이더는 바로 이 사용 사례를 위해 설계되었습니다.

오디오

소리는 3D 공간을 시각적 데모에서 장소로 바꿉니다. Web Audio API는 브라우저에서 공간 오디오에 필요한 모든 것을 제공합니다.

HRTF를 이용한 공간 오디오(Head-Related Transfer Function)는 소리를 3D 공간에 배치합니다. 왼쪽의 폭포는 왼쪽에 있는 것처럼 들립니다. 가까이 가면 커집니다. 건물 뒤로 가면 먹먹해집니다(추가 처리와 함께).

앰비언스 존은 오디오의 텍스처 스플래팅처럼 작동합니다. 영역(숲, 동굴, 해안, 도시)을 정의하고 플레이어가 이동함에 따라 앰비언트 사운드스케이프를 크로스페이드합니다. 이게 Skyrim이 숲을 살아있게 들리게 하는 방식입니다. 바람, 새, 바스락거리는 잎, 먼 동물 소리를 겹칩니다. 어느 것도 복잡하지 않습니다. 모두 공간적입니다.

Web Audio 성능은 수십 개의 동시 공간 소스에 충분히 좋습니다. 병목은 보통 처리가 아니라 에셋 크기입니다. 압축 오디오에는 Opus나 AAC를 쓰고, 긴 앰비언트 트랙은 스트리밍하고, 짧은 효과음(발소리, 상호작용)은 미리 로드합니다.

물, 날씨, 대기

기억에 남는 모든 오픈 월드에는 물과 날씨가 있습니다. 이 시스템들은 분위기를 정의하고 세계를 살아있게 합니다. 또한 브라우저에서 의외로 달성 가능합니다.

물 렌더링

브라우저 3D의 물에는 세 가지 복잡도 레벨이 있고, 가장 단순한 것을 먼저 출시하고 나중에 업그레이드할 수 있습니다.

레벨 1: 반사 평면. 반사/굴절 머티리얼을 가진 수면 높이의 평평한 메시. 씬을 거꾸로 뒤집어 텍스처에 렌더링하고(평면 반사), 파란 색조와 블렌딩하고, 파도 움직임을 위해 스크롤하는 노멀 맵을 더합니다. 이게 Skyrim의 기본 물 셰이더가 하는 것입니다. Three.js에서는 공식 저장소의 Water 예제가 이를 구현합니다. Babylon.js에서는 WaterMaterial이 기본으로 합니다. 비용: 반사를 위한 추가 렌더 패스 하나(절반 해상도면 충분), 그리고 수면 그리기. 중급 GPU에서는 프레임당 2-3ms를 더합니다.

레벨 2: 스크린 스페이스 반사 + 깊이 기반 효과. 별도의 반사 렌더 패스 대신 기존 프레임 버퍼를 샘플링해 반사를 얻습니다(SSR). 깊이 기반 색상 흡수(물은 깊을수록 어둡다), 깊이 비교를 이용한 해안선 거품, 수중 지형에 투영되는 코스틱을 더합니다. 이게 The Witcher 3가 쓰는 것입니다. SSR은 Three.js의 포스트프로세싱 스택과 Babylon.js의 렌더링 파이프라인 양쪽에 있습니다. 비용: SSR 1-2ms, 깊이 효과는 무시할 만함.

레벨 3: FFT 해양 시뮬레이션. 넓은 바다에는 고속 푸리에 변환을 써서 GPU에서 파동 스펙트럼을 시뮬레이션합니다. Jerry Tessendorf의 논문 "Simulating Ocean Water"(2001)는 모든 주요 게임 엔진이 쓰는 기반입니다. FFT는 WebGPU 컴퓨트 셰이더로 실행되어 매 프레임 변위 맵과 노멀 맵을 생성합니다. 결과 해양은 놀랍도록 설득력 있어 보입니다. 이게 Sea of Thieves, Assassin's Creed Black Flag, Uncharted 4가 쓰는 것입니다. WebGPU에서 256x256 FFT 해양은 데스크톱 GPU에서 1ms 미만으로 실행됩니다.

wgsl
@compute @workgroup_size(16, 16)
fn fftOceanDisplacement(@builtin(global_invocation_id) id: vec3<u32>) {
    let k = vec2<f32>(f32(id.x) - N/2.0, f32(id.y) - N/2.0);
    let omega = sqrt(length(k) * gravity);
    let phase = omega * time;
    let h = spectrum[id.xy] * vec2<f32>(cos(phase), sin(phase));
    displacement[id.xy] = h;
}

크리에이터 월드에는 레벨 1(반사 평면)로 시작하고 렌더러가 성숙하면 레벨 2로 업그레이드합니다. 레벨 3은 세계에 넓은 바다가 있을 때만 필요합니다.

날씨 시스템

Skyrim과 BotW의 날씨는 전환을 가진 상태 머신으로 구동됩니다. 맑음 > 흐림 > 비 > 폭풍 > 맑음. 각 상태는 여러 시스템을 동시에 바꿉니다: 스카이박스, 안개 밀도, 앰비언트 광 색상, 파티클 효과(비/눈), 오디오(바람, 비), 게임플레이 속성(BotW에서 젖은 표면은 미끄럽다).

브라우저 월드에서 날씨 시스템은 세 레이어를 가집니다:

하늘 렌더링. 절차적 하늘 셰이더는 스카이박스 텍스처보다 저렴하고 유연합니다. Preetham이나 Hosek-Wilkie 하늘 모델은 태양 위치만으로 물리적으로 그럴듯한 하늘 색상을 계산합니다. 평면을 통해 스크롤되는 3D 노이즈로 구름 레이어를 더합니다. Babylon.js에는 내장 절차적 하늘 머티리얼이 있습니다. Three.js에는 Sky 예제가 있습니다. 둘 다 무시할 만한 GPU 비용으로 설득력 있는 결과를 냅니다(단일 풀스크린 쿼드).

파티클 효과. 비는 위에서 떨어지는 수천 개의 얇은 쿼드로 된 파티클 시스템입니다. 눈은 비슷하지만 더 느리게 떠다니는 궤적을 가집니다. 안개는 깊이에 기반해 씬을 안개 색으로 블렌딩하는 포스트프로세싱 패스입니다. 이 모든 게 표준 WebGL 효과입니다. 비용은 파티클 수에 달려 있습니다. 1만 개의 비 파티클은 프레임당 대략 0.5ms를 더합니다.

환경 반응. 젖은 표면은 스페큘러 반사를 늘립니다. 눈 쌓임은 위를 향한 표면에 흰색을 더합니다. 웅덩이는 오목한 지형에 나타납니다. 이건 지오메트리 변경이 아니라 셰이더 트릭입니다. "wetness" 유니폼이 머티리얼 거칠기를 바꿉니다. "snow cover" 유니폼이 노멀이 위를 향한 표면에 흰색을 블렌딩합니다. GTA V와 The Witcher 3가 바로 이 접근을 씁니다.

동기화된 날씨. 멀티플레이어 세계에서 날씨는 클라이언트 간에 일관되어야 합니다. 가장 단순한 접근: 서버가 1 Hz로 날씨 상태(전환 진행도 포함)를 브로드캐스트합니다. 클라이언트는 로컬에서 보간합니다. 날씨가 천천히 변하므로(맑음에서 비로 전환이 30-60초 걸림) 지연된 업데이트조차 부드럽게 보입니다.

대기 원근

이건 세계를 크게 느끼게 하는 가장 효과적인 단일 시각 기법이며, 거의 공짜입니다. 멀리 있는 물체는 대기의 빛 산란 때문에 더 흐릿하고, 더 푸르고, 대비가 덜해 보입니다. 모든 오픈 월드가 이를 씁니다.

프래그먼트 셰이더에서 깊이에 기반해 먼 픽셀을 대기 색상 쪽으로 블렌딩합니다: