WebXR로 웹 VR 게임 만들기

허형준·2023년 10월 31일
4

기술

목록 보기
9/9
post-thumbnail

이 포스트에서는 WebXR을 ThreeJS에서 사용하는 VR기술로 한정해서 설명하고 있습니다. WebXR기술은 VR외에도 AR, 공간인식등을 포괄하는 API입니다.

1. VR 시장의 문제

VR 시장은 게임이 지배한다. 대부분의 사람들은 VR기기를 사도 즐길 게임 컨텐츠가 없으니 그냥 창고에 보관해두기만 한다. 필자의 지인도 즐길만한 컨텐츠가 없어 당근마켓에 팔았다고 했다. 그런 VR 시장이 가진 고질적인 문제는 대략 5가지 정도 있는데, 접근성, 게임의 가격부담, 컨텐츠 부족, 플레이타임, 어지러움이다.

일단 플레이 하려면 VR기기가 있어야 한다. 오큘러스 2는 44만원, 최근에 출시한 3는 69만원 이다. VR기기 치고는 가성비가 높은 편이지만 그럼에도 범용성 측면에서 가격부담이 있다. 게이밍 전용 기기라고 한정한다면 가격은 다른 게임기기와 마찬가지로 조금 나가는 편이다. 다른 기기의 경우 닌텐도 스위치가 36만원, 플레이 스테이션 5가 68만원이니까.

다음으로 게임 자체의 가격이다. 간혹 무료게임도 보이지만, 대부분 10000원을 넘어간다. 평균적으로 2만원 정도 한다. 필자처럼 게임을 한달에 몇 번 정도 즐기는 사람들을 대상으로는 상대적으로 비싸게 다가온다.

VR하면 늘 컨텐츠 부족이 따라다닌다. 그만큼 VR 시장에서는 컨텐츠가 중요하고, 그런 연유로 늘 VR이 실패했었다. 물론 비트세이버같은 스테디셀러도 존재하지만 극히 드물고, 있다고 해도 가격때문에 한 번 더 놀란다. 동시에 VR기기에서 바로 플레이 가능한 standalone 게임이 부족한 탓도 있다. 아무래도 PC와 연동해서 플레이할 수 있는 게임이 많은건 사실이다. 이는 VR 기기 자체 성능을 향상시키는 방법으로 해결 가능하다.

플레이시간도 그리 길지 않다. 이는 배터리의 한계하고도 연계되는데, 오큘러스 2의 배터리 러닝타임이 2시간 이기 때문이다. 따라서 VR게임사들도 여기에 러닝타임을 맞춰야 몰입도를 높일 수 있다. 더해서 2시간 이상 플레이하면 눈의 피로도도 상당히 증가한다. 필자의 경우 영화를 보더라도 10분 이상을 가만히 앉아서 볼 수 없었다. 게임의 경우 1시간 이상 플레이하면 급격하게 피로해졌다.

마지막으로 어지러움이다. VR이 처음 개발되고 대중에 공개되었을때부터 지금까지 꾸준히 제기되고 있는 문제점이다. 최근 들어 해상도와 지연시간이 개선되어 이런 어지러움 증상은 많이 개선되었으나 여전히 적응과 개선이 필요한 부분이다. 필자의 경우 한 자리에 있으면서 플레이하는 게임은 어지러움이 덜 했으나 스파이더맨 게임, 레이싱 게임의 경우 상당히 어지러웠다.

사실 이는 인간이 가진 한계라고 본다. 우리의 뇌는 주변 환경과 감각을 끊임없이 일치시키려 노력하는데, 들어오는 감각과 환경이 일치하지 않는다면 이상하다는 신호를 보내고 이같은 현상이 어지러움으로 나타나게 된다.

그럼에도 딜레이, 렉, 해상도 및 선명도를 개선하는 기술적 노력으로도 VR 가진 여러 한계를 극복할 수 있다. 이번 메타 퀘스트 3의 경우에 패스스루와 선명도를 개선해 주변 환경과 상호작용할 수 있도록 개발했다. 이제 VR기기를 쓰고도 방 안을 자유롭게 돌아다닐 수 있게 된 셈이다. 약간의 부끄러움을 감수할 용기가 있다면 집 밖에서도 쓰고다녀보는걸 추천한다. (필자의 경험담이다)

사진 출처 주커버그 인스타

2. VR 시장의 현재

이제 VR 시장의 현재를 알아보자. 시장의 전망 자체는 긍정적이다. 계속 성장할것으로 예상되고 있다. 코로나 덕택에 관심이 늘기는 했으나 그 전망은 꾸준히 이어질 것으로 내다보는 상황이다.

현재 VR 선두주자는 단연 메타다. 최근에는 Apple도 Vision Pro를 시연하며 시장 진입을 알렸는데, 이 시점에서 개발자들이 고민해야하는건 컨텐츠라고 생각한다.

오큘러스2 출시 이후 많은 VR컨텐츠들이 개발되고 접속하는 유저는 증가하고 있다. 아래는 월간 스팀에서 VR기기로 접속한 사용자의 수다. 16년에 비해 20년에는 기하급수적으로 증가했다. 특히 이는 코로나의 영향으로도 볼 수 있는데, 상대적으로 집에 있는 시간이 많아져서 생긴 현상이라고 해석된다.

그럼 이제 한가지 질문을 던져볼 수 있다. “VR 컨텐츠를 무료로 공급하고 플레이타임을 길게 가져갈만한 컨텐츠를 만든다면?” 그런 게임은 지난 VR 시장이 가진 잠재력을 최대한 이끌어 줄 수 있을지도 모른다. 필자는 이를 가능하게 하는 기술이 WebXR이 되지 않을까 조심스레 예측하는 바다.

3. WebXR

최근에 VR기기를 하나 구매했다. WebXR를 공부해보려고 했는데, WebXR 기술의 완성도나 지연 시간은 상상 이상으로 좋았다. 개인적으로 게임을 구매하는걸 별로 좋아하지는 않아서 스토어에 있는 게임은 구매하지 않았지만, 한 가지 놀라운 점을 발견했다.

WebXR 기술의 성숙도가 올라왔는데도, 웹 컨텐츠가 여전히 부족하다. 웹은 앞선 VR의 문제점중 접근성과 유료화 부문을 해결할 도구이기도 하다. 그럼에도 시중에 나와있는 웹 VR게임의 수는 터무니 없이 적었다. 사실 이건 게임엔진들의 문제이기도 하다. 실제로 Unity에서 VR 웹게임을 개발하기에는 성능상에 문제가 많다. Unity가 웹에 최적화 되어있는 엔진도 아니라는 점도 한계로 작용한다.

그래서 자체적으로 웹 게임을 구현할 수 밖에 없었다. 다행히 ThreeJS에서 WebXR을 지원하길래 조금 더 편하게 개발할 수 있으리라 생각했다.

3-1. ThreeJS와 WebXR의 연동

ThreeJS에서 WebXR을 사용하려면 2가지 방법이 있다. WebXR의 표준 API를 사용하거나 ThreeJS에서 제공하는 도구를 이용하거나. 사실 두 가지 방법 모두 WebXR를 이용하는거라 큰 차이는 없다. 그래도 ThreeJS에서 제공하는 도구가 WebXR를 다루는게 더 편하기 때문에 이 포스트에서는 ThreeJS를 기준으로 설명하겠다. 표준 API가 궁금하신 분들은 WebXR Device API - Web APIs | MDN에서 확인 가능하다.

먼저 XR을 허용해주어야 한다.

import { VRButton } from 'three/examples/jsm/webxr/VRButton';

class Scene {
	constructor() {
		this.init()
	}

	init() {
        document.body.appendChild( VRButton.createButton( renderer )); // VR을 활성화하는 버튼이다.
        renderer.xr.enabled = true; // XR 기능을 활성화한다.
        this.renderer.setAnimationLoop(this.animateXR.bind(this)); // 이 경우 ThreeJS에서 할당된 requestAnimationFrame( this.animate.bind(this) );으로는 동작하지 않기 때문에 별도로 애니메이션 루프를 만들어주어야 한다.
	}

	animateXR() {
		...
        this.renderer.render( this.scene, this.camera );
	}
}

다음으로는 컨트롤러의 위치와 회전값을 알아야 한다. 아래 코드는 맨 처음으로 활성화된 컨트롤러를 가져오는 함수다. 오큘러스의 경우 컨트롤러의 배터리를 아끼기 위해 사용자가 오큘러스를 키고 컨트롤러를 움직이면 진동이 울리며 활성화 되는데, 그 중 가장 먼저 활성화된 컨트롤러를 가져온다. 회전값은 ThreeJS와 동일하게 controller.rotation 오브젝트에 있다.

const controller = this.renderer.xr.getController(0); 
this.model.position.set(controller.position.x, controller.position.y, controller.position.z)

3-2. WebXR의 장점

Immersive Web Developer Home에 장점이 소개되어 있다. 간단히 정리해보자면,

지속된 개발과 모든 VR플랫폼에서 동작가능하다 개발자에 입장에서 Crossplatform은 개발 효율성과 배포의 용이성을 높여준다. JS의 일렉트론, Flutter나 RN이 칭송받는 이유와 마찬가지다. 한 코드만 개발해도 여러 플랫폼에 동시에 배포할 수가 있다. 동시에 웹 플랫폼의 장점으로 빠르고 유연하게 배포할 수 있다는 점이다. 필자가 쓴 GoCD Pipeline 구축을 이용하면 코드 변화를 CI/CD 툴에서 바로 감지한 후 배포할 수 있다.

새로운 기기가 등장해도 API 수정 및 새로운 코드 추가가 필요 없다. 새로 Apple Vision Pro가 나올때면 기존 VR게임을 포팅하거나 수정할 필요가 생긴다. 그러나 WebXR을 사용해 만든 게임은 그런 수정 없이 바로 접속하기만 하면 된다. 개발자 입장에서도, 유저 입장에서도 편하다.

AR, VR모두 개발 가능하다. Apple Vision Pro, Meta 퀘스트 3 모두 컬러 패스스루를 지원한다. 이는 혼합현실 (MR)을 염두해두고 만든 기능으로, 다른 게임의 경우 각각의 기능을 따로 구현해야 한다. 그러나 WebXR을 사용하면 동시에 개발할 수 있다.

유저는 VR 콘텐츠에 바로 접속 가능하다. 배포된 주소로만 접근하면 바로 VR콘텐츠를 실행시킬 수 있다. 어떠한 설치 과정 없이 바로 접속할 수 있다는건 유저 입장에서 불필요한 저장공간을 차지하지 않게 할 수 있어 매력적이다.

WebGL 기반으로 동작한다. 웹 표준을 준수하고 따라서 API가 크게 변경되거나 삭제될 일은 없다. 또한 안정적으로 동작한다.

등으로 소개되어 있다. 사실상 이정도면 게임 개발사들이 굳이 앱으로 만들어서 배포해야 할까 라는 생각도 든다. 그러나 대게 개발사들은 VR을 웹으로 개발하지 않는다. 이유는 물론 WebXR 이 가진 한계가 너무도 명확하기 때문이다.

3-3. WebXR의 한계

성능문제가 있다. 조금만 라이팅이 들어가도 끊긴다. 오브젝트가 많아도 끊긴다. 필자의 경우 폴리곤의 수는 5000이하로 최적화 한다. 이렇게 하지 않으면 로딩시간이 오래걸린다. 게다가 조금만 메모리, CPU 성능을 차지해도 프레임은 계속 끊긴다.

사실적 표현의 한계도 있다. VR 컨텐츠는 몰입감을 주어야 하는데, 그러기 위해서는 주변 텍스처나 머터리얼이 최대한 사실적으로 묘사되어야 한다. 그러나 앞선 성능 문제로 그래픽 표현에 한계가 있다.

지원하는 게임 엔진의 수가 부족하거나 잘 쓰지 않는다. Unity로도 WebXR을 적용하고 웹 게임을 개발할 수 있지만, 성능 문제가 심각한 편이다. 차라리 네이티브로 배포하는게 효율적이다. 정말 웹으로 개발하고 싶다면 별도의 게임엔진 없이 ThreeJS나 babylon.js를 사용한다. 이쪽은 아예 JS기반으로 동작하며 성능상의 이점도 충분히 가져올 수 있다. 그러나 이 라이브러리를 또 배워야 한다는 점 때문에 게임 개발자들은 잘 쓰지 않는다.

문서의 수가 적은 점도 한 몫 한다. 관련 문서의 수가 턱없이 부족하다. 당장 소개하는 글은 많지만 구체적인 방법이나 트러블슈팅에 대한 해결책은 많이 부족한 상황이다. 물론 MDN문서에 구체적인 사용 방법과 표준이 명시되어 있지만, 필자처럼 ThreeJS에서 지원하는 WebXR을 쓸 경우 깃허브 이슈탭을 확인해보거나 관련 개발자에게 직접 물어봐야 한다.

지원 환경이 제한적이다. 크롬의 최신 브라우저 및 안드로이드 기기에서는 대부분 지원하지만, iOS에서는 지원하지 않는다. 다만, VR로 생각해봤을때 오큘러스, HTC등 유명한 가상현실기기 개발사들은 안드로이드를 기반으로 하기 때문에 호환에서는 문제 없다. 그럼에도 다른 기기로 확장하고 싶거나 AR기능을 모바일에서도 제공하고 싶다면 이러한 제한 요소는 걸림돌이 된다.
다행히도 Apple에서는 Vision Pro Safari에 WebXR기술을 도입하겠다고 밝혔다. 관련 기사

3-4. WebXR 게임 사례

대부분 아케이드 게임, 그래픽 요소가 적은 게임이다. 웹 특성상 화면에 오브젝트가 많아지고 모델의 크기가 1MB를 넘어가는 순간부터 느려지기 시작하기 때문에 최대한 경량화와 최적화가 필요하다. 그래서인지 모델의 수는 간소화되어 있고 그래픽적 요소에서 사실적인걸 뺀, 보드게임같은 느낌이 든다.

혹시나 VR 기기가 있다면 체험해보길 추천한다. 어쩌면 새로운 게임 아이디어를 얻을 수도 있으니. 필자가 직접 플레이해보고 괜찮은 게임만 선정해서 집어넣었다.

RogueSaber: 광선검 게임

Up There: 우주별 탐험

Spiderman: 스파이더맨

Access Mars: 화성 표면 보기

https://github.com/PicchiKevin/WebXR-games

3-5. 게임을 만들어보자

공부해보려고 광선검 게임을 만들었다. ThreeJS의 컨트롤러 세팅 및 기타 설정도 굉장히 간편했다. 아래 Enter VR 버튼도 기본적으로 지원하는 기능이다.

VR 게임을 개발하면서 마주한 몇 가지 문제점과 해결방안을 정리해보고자 한다.

HTTPS가 필요하다. WebXR을 사용하기 위해서는 HTTPS 통신이 되어있어야 한다. 이를 위해 local개발 환경에서는 mkcert를 통해 HTTPS를 등록해준다. 필자의 경우 Node 환경을 가지고 있어 아래처럼 코드를 작성해주면 자동으로 세팅이 완료된다.

const options = {
 key: fs.readFileSync('./key/private.pem'),
 cert: fs.readFileSync('./key/public.pem')
};

const server = https.createServer(options, app);

server.listen(port, () => {
 console.log("HTTPS server listening on port " + port);
});

광선검과 총알간 충돌처리가 필요하다. 이는 ThreeJS에서 지원하는 OBB 모듈로 해결했다. OBB 알고리즘이 비효율적인 알고리즘이긴 하나, 필자가 자체적으로 GJK와 같은 알고리즘을 쓰기에는 실력이 부족해서 그냥 있는거 가져다 사용했다. 나름대로 쓸만했고 충돌 된 이후나 오브젝트가 너무 멀어질 경우 계산에서 제외하는 방식으로 최적화 했다.
한 Scene에 들어가는 충돌 처리의 수는 15개 내외로 제한했다. 만일 여기서 200개가 넘어간다면 프레임수는 급격하게 떨어지기 시작한다.

오브젝트의 폐기가 필요하다. 오브젝트를 Scene에서 지워주지 않을경우에도 랜더링 시간이 오래걸리기 때문에 꼭 오브젝트를 폐기해주길 바란다. 오브젝트 폐기는 생각보다 간단하다. 가장먼저 geometry를 .dispose()해주고, Scene에서 지워준다. 이후 model을 undefined처리해주면 화면에서의 랜더링이 제거된다.

public removeModel() {
   this.model.geometry.dispose()
   this.scene.remove( this.model );
   this.model = undefined
}

사실 문법이 생각보다 간편해서 놀랐다. 물론 WebXR의 표준 API는 불친절하지만, ThreeJS로 개발할 생각이라면 정말 편하게 VR기능을 추가할 수 있다. 마지막으로 필자가 개발한 게임 소스와 주소를 적어두며 글을 마친다.

게임의 주소는 saber.devent.kr이고 혹시나 코드가 궁금하신 분들을 위해 소스를 첨부해둔다.

https://github.com/Public-Game-Entity/vr-lightsaber

profile
소프트웨어 개발자.

0개의 댓글