이 캐주얼 드라이빙 게임에서 절차적으로 생성된 무한한 풍경을 통해 WebGL의 잠재력을 발견해 보세요.
Slow Roads는 끝없이 절차적으로 생성되는 풍경을 강조하는 캐주얼 드라이빙 게임으로, 모두 브라우저에서 WebGL 애플리케이션으로 호스팅됩니다. 많은 사용자에게 이러한 집중적인 환경은 제한된 브라우저 컨텍스트에 적합하지 않은 것처럼 보일 수 있습니다. 실제로 이러한 태도를 바로잡는 것이 이 프로젝트의 목표 중 하나였습니다. 이 도움말에서는 웹에서 3D의 잠재력을 강조하기 위해 성능 장벽을 극복하는 데 사용한 몇 가지 기법을 설명합니다.
브라우저에서의 3D 개발
Slow Roads를 출시한 후 의견에서 '브라우저에서 이런 작업이 가능하다는 것을 몰랐습니다'라는 의견이 반복적으로 접수되었습니다. 이러한 생각을 공유하는 것은 결코 소수의 의견이 아닙니다. 2022년 JS 현황 설문조사에 따르면 개발자의 약 80% 가 아직 WebGL을 실험해 보지 않았습니다. 특히 브라우저 기반 게임의 경우 많은 잠재력을 놓칠 수 있다는 점이 안타깝습니다. Slow Roads를 통해 WebGL을 더욱 주목받고 '고성능 JavaScript 게임 엔진'이라는 문구에 주저하는 개발자의 수를 줄이고자 합니다.
WebGL은 많은 사용자에게 미스터리하고 복잡해 보일 수 있지만, 최근 몇 년 동안 개발 생태계는 매우 유능하고 편리한 도구와 라이브러리로 크게 발전했습니다. 이제 프런트엔드 개발자는 컴퓨터 그래픽에 대한 사전 경험이 없어도 그 어느 때보다 쉽게 3D UX를 작업에 통합할 수 있습니다. 업계를 선도하는 WebGL 라이브러리인 Three.js는 3D 구성요소를 React 프레임워크로 가져오는 react-three-fiber를 비롯한 여러 확장 프로그램의 기반이 됩니다. 이제 익숙한 인터페이스와 통합 도구 모음을 제공하는 포괄적인 웹 기반 게임 편집기(예: Babylon.js 또는 PlayCanvas)도 있습니다.
이러한 라이브러리의 유용성은 뛰어나지만, 야심 찬 프로젝트는 결국 기술적 제한사항에 부딪힙니다. 브라우저 기반 게임에 대해 회의적인 사람들은 JavaScript가 단일 스레드이고 리소스가 제한적이라고 강조할 수 있습니다. 하지만 이러한 제한사항을 해결하면 숨겨진 가치를 얻을 수 있습니다. 다른 플랫폼에서는 브라우저에서 제공하는 것과 동일한 즉각적인 접근성과 대량 호환성을 제공하지 않습니다. 브라우저 지원 시스템의 사용자는 애플리케이션을 설치하거나 서비스에 로그인하지 않고도 클릭 한 번으로 재생을 시작할 수 있습니다. 또한 개발자는 UI를 빌드하거나 멀티플레이어 모드의 네트워킹을 처리하는 데 강력한 프런트엔드 프레임워크를 사용할 수 있다는 편리함을 누릴 수 있습니다. 이러한 가치가 브라우저를 플레이어와 개발자 모두에게 훌륭한 플랫폼으로 만드는 요소라고 생각합니다. Slow Roads에서 보여준 것처럼 기술적 제한은 디자인 문제로 축소될 수 있습니다.
느린 도로에서 원활한 성능 달성
Slow Roads의 핵심 요소에는 고속 모션과 비용이 많이 드는 풍경 생성이 포함되므로 원활한 성능이 모든 설계 결정의 핵심이었습니다. 제 주요 전략은 엔진 아키텍처 내에서 문맥별 바로가기를 사용할 수 있는 간소화된 게임플레이 디자인으로 시작하는 것이었습니다. 단점은 미니멀리즘을 추구하기 위해 일부 있으면 좋은 기능을 포기해야 한다는 점이지만, 그 결과 다양한 브라우저와 기기에서 원활하게 재생되는 맞춤설정된 초고도로 최적화된 시스템이 탄생합니다.
다음은 Slow Roads의 린함을 유지하는 주요 구성요소를 분류한 내용입니다.
게임플레이를 중심으로 환경 엔진 형성
게임의 핵심 구성요소인 환경 생성 엔진은 불가피하게 비용이 많이 들며, 메모리 및 컴퓨팅 예산의 가장 큰 비율을 차지합니다. 여기서 사용되는 트릭은 성능 급증으로 프레임 속도가 중단되지 않도록 일정 기간에 걸쳐 과도한 계산을 예약하고 배포하는 것입니다.
환경은 기하학 타일로 구성되며, 카메라에 얼마나 가까워 보이는지에 따라 크기와 해상도('세부 수준' 또는 LoD로 분류됨)가 다릅니다. 자유롭게 돌아다닐 수 있는 카메라가 있는 일반적인 게임에서는 플레이어가 이동할 수 있는 모든 위치에서 플레이어의 주변 환경을 세부적으로 보여주기 위해 다양한 LoD를 지속적으로 로드하고 언로드해야 합니다. 이는 특히 환경 자체가 동적으로 생성되는 경우 비용이 많이 들고 낭비가 될 수 있습니다. 다행히 이 규칙은 사용자가 도로에 있어야 한다는 문맥적 기대 덕분에 느린 도로에서는 완전히 무시할 수 있습니다. 대신 경로 바로 옆에 있는 좁은 통로에 세부적인 도형을 예약할 수 있습니다.

도로의 중심선 자체는 플레이어가 도착하기 훨씬 전에 생성되므로 환경 세부정보가 필요한 정확한 시점과 위치를 정확하게 예측할 수 있습니다. 그 결과 비용이 많이 드는 작업을 사전에 예약하고, 각 시점에 필요한 최소한의 작업만 생성하며, 표시되지 않는 세부정보에 노력을 낭비하지 않는 린 시스템이 탄생합니다. 이 기법은 도로가 단일의 분기되지 않는 경로이기 때문에만 가능합니다. 이는 아키텍처 단축키를 수용하는 게임플레이 절충의 좋은 예입니다.

물리학 법칙에 까다롭게 따짐
환경 엔진의 계산 요구사항 다음으로 물리 시뮬레이션이 중요합니다. Slow Roads는 사용 가능한 모든 지름길을 사용하는 맞춤 최소 물리 엔진을 사용합니다.
여기서 가장 큰 절약은 애초에 너무 많은 객체를 시뮬레이션하지 않는 것입니다. 동적 충돌 및 파괴 가능한 객체와 같은 항목을 무시하여 최소한의 선 맥락을 활용합니다. 차량이 도로에 머물러 있을 것이라고 가정하면 오프로드 물체와의 충돌은 무시해도 됩니다. 또한 도로를 희소한 미드라인으로 인코딩하면 도로 중앙까지의 거리 확인을 기반으로 도로 노면 및 가드레일과의 빠른 충돌 감지를 위한 우아한 트릭을 사용할 수 있습니다. 그러면 오프로드 주행이 더 비싸지지만, 이는 게임플레이 맥락에 적합한 공정한 절충의 또 다른 예입니다.
메모리 사용량 관리
브라우저에서 제한하는 또 다른 리소스이므로 JavaScript가 가비지 컬렉션을 실행하더라도 메모리를 주의 깊게 관리해야 합니다. 간과하기 쉽지만 게임 루프 내에 소량의 새 메모리를 선언해도 60Hz에서 실행할 때 심각한 문제가 발생할 수 있습니다. 대규모 가비지 컬렉션은 사용자가 멀티태스킹할 가능성이 있는 컨텍스트에서 사용자의 리소스를 소모할 뿐만 아니라 완료하는 데 여러 프레임이 걸릴 수 있으므로 눈에 띄는 끊김이 발생합니다. 이를 방지하려면 초기화 시 클래스 변수에 루프 메모리를 미리 할당하고 각 프레임에서 재활용하면 됩니다.

또한 도형 및 관련 데이터 버퍼와 같은 더 무거운 데이터 구조를 경제적으로 관리하는 것도 매우 중요합니다. Slow Roads와 같이 무한 생성되는 게임에서는 대부분의 도형이 일종의 러닝머신에 존재합니다. 오래된 도형이 뒤로 떨어지면 데이터 구조를 저장하고 나중에 게임 세계의 다른 부분에 재활용할 수 있습니다. 이를 객체 풀링이라고 하는 디자인 패턴이라고 합니다.
이러한 관행은 코드의 단순성을 다소 희생하면서도 린 실행을 우선하는 데 도움이 됩니다. 고성능 컨텍스트에서는 편의 기능이 개발자의 이익을 위해 클라이언트에서 빌리는 방식에 유의해야 합니다. 예를 들어 Object.keys()
또는 Array.map()
와 같은 메서드는 매우 유용하지만 각 메서드가 반환 값의 새 배열을 만든다는 점을 간과하기 쉽습니다. 이러한 블랙박스의 내부 작동을 이해하면 코드를 수정하고 은밀한 성능 저하를 방지하는 데 도움이 됩니다.
절차적으로 생성된 애셋으로 로드 시간 단축
게임 개발자의 주요 관심사는 런타임 성능이지만 초기 웹페이지 로드 시간과 관련된 일반적인 공리도 여전히 유효합니다. 사용자는 용량이 큰 콘텐츠에 의도적으로 액세스할 때는 더 관대한 태도를 보일 수 있지만, 로드 시간이 길면 사용자 유지율이 아니라도 환경에 해로울 수 있습니다. 게임에는 텍스처, 사운드, 3D 모델의 형태로 대용량 애셋이 필요한 경우가 많으며, 최소한 세부정보를 생략할 수 있는 곳에서는 이러한 애셋을 신중하게 압축해야 합니다.
또는 클라이언트에서 절차적으로 애셋을 생성하면 애초에 긴 전송을 피할 수 있습니다. 이는 느린 연결을 사용하는 사용자에게 큰 이점이 되며, 개발자는 초기 로드 단계뿐만 아니라 다양한 품질 설정에 맞게 세부사항 수준을 조정할 때도 게임 구성 방식을 더 직접적으로 제어할 수 있습니다.
느린 도로의 대부분의 도형은 절차적으로 생성되며 간단합니다. 맞춤 셰이더가 여러 텍스처를 결합하여 세부정보를 제공합니다. 단점은 이러한 텍스처가 무거운 애셋이 될 수 있지만, 확률적 텍스처링과 같은 메서드를 사용하면 작은 소스 텍스처에서 더 많은 세부정보를 얻을 수 있으므로 비용을 절감할 수 있는 여지가 있습니다. 극단적인 수준에서는 texgen.js와 같은 도구를 사용하여 클라이언트에서 완전히 텍스처를 생성할 수도 있습니다. 오디오도 마찬가지입니다. Web Audio API를 사용하면 오디오 노드로 사운드를 생성할 수 있습니다.
프로시저럴 애셋의 이점을 활용하면 초기 환경을 생성하는 데 평균 3.2초밖에 걸리지 않습니다. 작은 선행 다운로드 크기를 최대한 활용하기 위해 간단한 스플래시 화면이 신규 방문자를 맞이하고 긍정적인 버튼을 누른 후에야 비용이 많이 드는 장면 초기화를 연기합니다. 또한 이 버퍼는 튀어 나온 세션에 편리한 버퍼 역할을 하여 동적으로 로드된 애셋의 낭비되는 전송을 최소화합니다.
후반 최적화에 대한 민첩한 접근 방식
저는 항상 Slow Roads의 코드베이스를 실험용으로 간주해 왔으며, 이에 따라 개발에 매우 민첩한 접근 방식을 취해 왔습니다. 복잡하고 빠르게 진화하는 시스템 아키텍처를 사용하는 경우 중요한 병목 현상이 발생할 수 있는 위치를 예측하기 어려울 수 있습니다. 깔끔하게 구현하는 것보다 원하는 기능을 빠르게 구현하는 데 중점을 두고, 그런 다음 중요한 부분에서 시스템을 최적화하기 위해 역으로 작업해야 합니다. Chrome DevTools의 성능 프로파일러는 이 단계에서 매우 유용하며 이전 버전의 게임과 관련된 몇 가지 주요 문제를 진단하는 데 도움이 되었습니다. 개발자의 시간은 소중하므로 중요하지 않거나 중복된 문제에 시간을 낭비하지 마세요.
사용자 환경 모니터링
이러한 모든 트릭을 구현하는 동안 게임이 실제 환경에서 예상대로 작동하는지 확인하는 것이 중요합니다. 다양한 하드웨어 기능을 수용하는 것은 모든 게임 개발의 기본적인 측면이지만 웹 게임은 최신 데스크톱과 10년 된 휴대기기를 한 번에 포함하는 훨씬 더 광범위한 범위를 타겟팅할 수 있습니다. 이를 해결하는 가장 간단한 방법은 프로파일러에서 밝힌 대로 GPU 및 CPU 집약적인 작업 모두에 대해 코드베이스의 가장 가능성이 높은 병목 현상을 조정하는 설정을 제공하는 것입니다.
자체 머신에서 프로파일링을 수행해도 한계가 있으므로 어떤 식으로든 사용자와의 의견을 교환하는 것이 좋습니다. 느린 도로의 경우 화면 해상도와 같은 문맥 요소와 함께 실적을 보고하는 간단한 분석을 실행합니다. 이러한 분석은 사용자가 게임 내 양식을 통해 제출한 서면 피드백과 함께 socket.io를 사용하여 기본 Node 백엔드로 전송됩니다. 초기에는 이러한 분석을 통해 일관되게 낮은 FPS가 감지되면 설정 메뉴를 강조 표시하거나 성능이 특히 나쁘면 사용자가 하드웨어 가속을 사용 설정해야 할 수도 있다는 경고를 표시하는 등 UX를 간단하게 변경하여 완화할 수 있는 많은 중요한 문제가 포착되었습니다.
전방에 느린 도로가 있습니다.
이러한 모든 조치를 취한 후에도 GPU가 없는 경량 기기를 사용하는 플레이어를 중심으로 낮은 설정으로 플레이해야 하는 상당한 규모의 플레이어층이 남아 있습니다. 사용 가능한 품질 설정 범위로 인해 성능 분포가 상당히 고르지만, 55FPS 이상을 달성하는 플레이어는 52% 에 불과합니다.

다행히 성능을 개선할 수 있는 기회는 아직 많이 있습니다. GPU 수요를 줄이기 위한 렌더링 트릭을 추가하는 것 외에도 가까운 시일 내에 환경 생성을 병렬화하는 웹 워커를 실험하고 싶습니다. 결국 WASM 또는 WebGPU를 코드베이스에 통합해야 할 수도 있습니다. 여유 공간을 확보할 수 있다면 더 풍부하고 다양한 환경을 만들 수 있습니다. 이는 프로젝트의 나머지 부분에서 계속 추구할 목표입니다.
취미 프로젝트로서 Slow Roads는 놀라울 정도로 정교하고 성능이 우수하며 인기 있는 브라우저 게임을 보여주는 데 큰 도움이 되었습니다. WebGL에 관심을 가져 주셔서 감사합니다. 기술적으로 Slow Roads는 WebGL의 전체 기능을 보여주는 매우 간단한 예시입니다. 독자는 Three.js 쇼케이스를 살펴보시기 바랍니다. 특히 웹 게임 개발에 관심이 있는 경우 webgamedev.com 커뮤니티에 참여해 보세요.