웹으로 만나는 가상 현실

가상 현실, 증강 현실 등 다양한 몰입형 환경에 대비하기 위한 몇 가지 기본사항이 있습니다.

Joe Medley
Joe Medley

몰입형 경험이 Chrome 79에서 웹에 도입되었습니다. WebXR Device API는 가상 현실을 가져올 수 있는 기능을 제공하며 Chrome 81에서는 증강 현실 지원이 제공됩니다. GamePad API를 업데이트하면 컨트롤의 고급 사용이 VR로 확장됩니다. Firefox Reality, Oculus Browser, Edge, Magic Leap의 Helio 브라우저 등 다른 브라우저에서도 곧 이러한 사양을 지원할 예정입니다.

이 도움말에서는 몰입형 웹에 관한 시리즈를 시작합니다. 이 분할 결제에서는 기본 WebXR 애플리케이션을 설정하고 XR 세션을 시작하고 종료하는 방법을 다룹니다. 이후 기사에서는 프레임 루프 (WebXR 환경의 핵심), 증강 현실의 세부사항, AR 세션에서 노출 영역을 감지하는 수단인 WebXR Hit Test API를 다룹니다. 달리 명시되지 않는 한 이 도움말과 후속 도움말에서 다루는 모든 내용은 AR과 VR에 동일하게 적용됩니다.

몰입형 웹이란 무엇인가요?

몰입형 경험(증강 현실과 가상 현실)을 설명하기 위해 두 가지 용어를 사용하지만, 많은 경우 완벽한 현실에서 완전한 가상 현실, 그리고 어느 정도 몰입도가 있는 스펙트럼으로 생각할 수 있습니다. XR의 'X'는 몰입형 경험의 스펙트럼에서 모든 것을 나타내는 일종의 대수적 변수로 이러한 생각을 반영하기 위한 것입니다.

완전한 현실에서 완전한 몰입형에 이르는 시각적 경험의 스펙트럼을 보여주는 그래프
몰입형 환경의 스펙트럼

몰입형 환경의 예는 다음과 같습니다.

  • 게임
  • 360° 동영상
  • 몰입감 넘치는 환경에서 제공되는 전통적인 2D (또는 3D) 동영상
  • 주택 구매
  • 구매하기 전에 집에 있는 제품 확인하기
  • 몰입형 아트
  • 누구도 떠올리지 못한 멋진 음악

개념 및 사용법

WebXR Device API를 사용하는 몇 가지 기본 사항을 설명하겠습니다. 위에서 설명한 것보다 자세한 내용이 필요한 경우 Immersive Web Working Group의 WebXR 샘플 또는 MDN의 증가하는 참조 자료를 확인하세요. WebXR Device API의 초기 버전에 익숙하다면 이 자료를 모두 살펴보시기 바랍니다. 변경사항이 있습니다.

이 문서의 코드는 몰입형 웹 작업 그룹의 기본 샘플 (데모, 소스)을 기반으로 하지만 명확성과 단순성을 위해 편집되었습니다.

WebXR 사양을 만들 때 사용자를 보호하기 위한 보안 및 개인 정보 보호 조치를 강화했습니다. 따라서 구현은 특정 요구사항을 준수해야 합니다. 웹페이지 또는 앱은 활성 상태이고 포커스가 있어야 뷰어에서 민감한 정보를 요청할 수 있습니다. 웹페이지 또는 앱은 HTTPS를 통해 제공되어야 합니다. API 자체는 작동에 필요한 센서와 카메라에서 얻은 정보를 보호하도록 설계되었습니다.

세션 요청

XR 세션에 들어가려면 사용자 동작이 필요합니다. 이를 가져오려면 특성 감지를 사용하여 navigator.xr를 통해 XRSystem를 테스트하고 XRSystem.isSessionSupported()를 호출합니다. Chrome 버전 79 및 80에서는 XRSystem 객체의 이름이 XR였습니다.

아래 예에서는 'immersive-vr' 세션 유형의 가상 현실 세션을 원한다고 표시했습니다. 다른 세션 유형'immersive-ar''inline'입니다. 인라인 세션은 HTML 내에 콘텐츠를 표시하기 위한 것으로, 주로 티저 콘텐츠에 사용됩니다. 몰입형 AR 세션 샘플에서 이를 확인할 수 있습니다. 이후 문서에서 설명해 드리겠습니다.

가상 현실 세션이 지원된다는 사실을 알게 되면 사용자 동작을 가져올 수 있는 버튼을 사용 설정합니다.

if (navigator.xr) {
  const supported = await navigator.xr.isSessionSupported('immersive-vr');
  if (supported) {
    xrButton.addEventListener('click', onButtonClicked);
    xrButton.textContent = 'Enter VR';
    xrButton.enabled = supported; // supported is Boolean
  }
}

버튼을 사용 설정한 후 클릭 이벤트를 기다렸다가 세션을 요청합니다.

let xrSession = null;
function onButtonClicked() {
  if (!xrSession) {
    navigator.xr.requestSession('immersive-vr')
    .then((session) => {
      xrSession = session;
      xrButton.textContent = 'Exit XR';
      onSessionStarted(xrSession);
    });
  } else {
    xrSession.end();
  }
}

이 코드의 객체 계층 구조에 주목하세요. navigator에서 xr로 이동하여 XRSession 인스턴스로 이동합니다. 초기 버전의 API에서는 스크립트를 통해 세션을 요청하기 전에 기기를 요청해야 했습니다. 이제 기기는 암시적으로 획득됩니다.

세션 시작

세션을 가져온 후에는 세션을 시작하고 입력해야 합니다. 하지만 먼저 몇 가지를 설정해야 합니다. 세션에는 사용자가 종료할 때 앱 또는 웹페이지를 재설정할 수 있도록 onend 이벤트 핸들러가 필요합니다.

장면을 그리는 <canvas> 요소도 필요합니다. XR 호환 WebGLRenderingContext 또는 WebGL2RenderingContext여야 합니다. 모든 그리기는 이러한 도구 또는 Three.js와 같은 WebGL 기반 프레임워크를 사용하여 실행됩니다.

이제 그릴 장소가 생겼으므로 여기에 그릴 콘텐츠 소스가 필요합니다. 이를 위해 XRWebGLLayer 인스턴스를 만듭니다. XRSession.updateRenderState()를 호출하여 이를 캔버스와 연결합니다.

세션에 들어가면 가상 현실에서 사물이 어디에 있는지 파악할 방법이 필요합니다. 참조 공간이 필요합니다. 'local-floor' 참조 공간은 원점이 뷰어 근처에 있고 y축이 층 수준에서 0이고 움직이지 않을 것으로 예상되는 공간입니다. 다른 유형의 참조 공간도 있지만 이 주제는 제가 여기서 다룰 수 있는 것보다 더 복잡한 주제입니다. 변수에 참조 공간을 저장합니다. 화면에 그릴 때 이 참조 공간이 필요하기 때문입니다.

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);

  let canvas = document.createElement('canvas');
  webGLRenContext = canvas.getContext('webgl', { xrCompatible: true });

  xrSession.updateRenderState({
    baseLayer: new XRWebGLLayer(xrSession, webGLRenContext)
  });

  xrSession.requestReferenceSpace('local-floor')
  .then((refSpace) => {
    xrRefSpace = refSpace;
    xrSession.requestAnimationFrame(onXRFrame);
  });
}

참조 공간을 가져온 후 XRSession.requestAnimationFrame()를 호출합니다. 이는 프레임 루프에서 이루어지는 가상 콘텐츠 표시의 시작입니다.

프레임 루프 실행

프레임 루프는 콘텐츠가 화면에 반복적으로 그려지는 사용자 에이전트가 제어하는 무한 루프입니다. 콘텐츠는 프레임이라는 개별 블록에 그려집니다. 프레임이 이어지면 움직이는 듯한 착시를 불러일으킵니다. VR 애플리케이션의 경우 초당 프레임 수는 60~144입니다. Android용 AR은 초당 30프레임으로 실행됩니다. 코드는 특정 프레임 속도를 가정해서는 안 됩니다.

프레임 루프의 기본 프로세스는 다음과 같습니다.

  1. XRSession.requestAnimationFrame()를 호출합니다. 이에 응답하여 사용자 에이전트는 개발자가 정의한 XRFrameRequestCallback를 호출합니다.
  2. 콜백 함수 내에서 다음을 실행합니다.
    1. XRSession.requestAnimationFrame()를 다시 호출합니다.
    2. 시청자의 포즈를 가져옵니다.
    3. XRWebGLLayer에서 WebGLRenderingContextWebGLFramebuffer를 ('바인딩') 전달합니다.
    4. XRView 객체를 반복하여 XRWebGLLayer에서 XRViewport를 가져와 WebGLRenderingContext에 전달합니다.
    5. 프레임 버퍼에 무언가를 그립니다.

이 도움말의 나머지 부분에서는 1단계와 2단계의 일부, XRFrameRequestCallback 설정 및 호출을 설명합니다. 2단계의 나머지 항목은 파트 II에서 다룹니다.

XRFrameRequestCallback

XRFrameRequestCallback는 개발자가 정의합니다. DOMHighResTimeStampXRFrame 인스턴스라는 두 가지 매개변수를 사용합니다. XRFrame 객체는 단일 프레임을 디스플레이에 렌더링하는 데 필요한 정보를 제공합니다. DOMHighResTimeStamp 인수는 나중에 사용할 수 있습니다.

다른 작업을 하기 전에 다음 애니메이션 프레임을 요청하겠습니다. 앞서 언급한 것처럼 프레임 타이밍은 기본 하드웨어를 기반으로 하는 사용자 에이전트가 결정합니다. 다음 프레임을 먼저 요청하면 콜백 중에 오류가 발생하면 프레임 루프가 계속됩니다.

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  // Render a frame.
}

이제 시청자가 볼 수 있도록 무언가를 그려야 합니다. 그것은 파트 II에 대한 논의입니다. 이동하기 전에 세션을 종료하는 방법을 보여드리겠습니다.

세션 종료

몰입형 세션은 XRSession.end() 호출을 통해 자체 코드로 종료되는 등의 여러 가지 이유로 종료될 수 있습니다. 다른 원인으로는 헤드셋 연결이 끊어지거나 다른 애플리케이션이 헤드셋을 제어하는 경우 등이 있습니다. 따라서 제대로 작동하는 애플리케이션은 end 이벤트를 모니터링해야 합니다. 이 경우 세션 및 관련 렌더링 객체를 삭제하세요. 종료된 몰입형 세션은 재개할 수 없습니다. 몰입형 환경에 다시 들어가려면 앱에서 새 세션을 시작해야 합니다.

설정 중에 onend 이벤트 핸들러를 추가했다는 세션 들어가기를 떠올려 보세요.

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);
  // More setup…
}

이벤트 핸들러 내에서 사용자가 세션을 시작하기 전의 앱 상태를 복원합니다.

function onSessionEnded(event) {
  xrSession = null;
  xrButton.textContent = 'Enter VR';
}

결론

아직 Web XR 또는 AR 애플리케이션을 작성하는 데 필요한 모든 것을 설명하지는 않았습니다. 스스로 코드를 이해하고 실험을 시작하기에 충분한 정보를 얻으셨기를 바랍니다. 다음 도움말에서는 콘텐츠가 화면에 그려지는 프레임 루프에 대해 설명하겠습니다

사진: JESHOOTS.COM, Unsplash