웹으로 만나는 가상 현실

가상 현실, 증강 현실 등 다양한 몰입형 환경을 준비하는 데 도움이 되는 몇 가지 기본사항을 알아보세요.

Joe Medley
Joe Medley

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

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

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

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

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

  • 게임
  • 360° 동영상
  • 몰입형 환경에서 제공되는 기존 2D(또는 3D) 동영상
  • 주택 구입
  • 구매 전 집에서 제품 보기
  • 몰입형 예술
  • 아직 아무도 생각해 보지 못한 멋진 아이디어

개념 및 사용

WebXR Device API 사용에 관한 몇 가지 기본사항을 설명하겠습니다. 제가 제공한 내용보다 더 자세한 내용이 필요한 경우 몰입형 웹 작업 그룹의 WebXR 샘플 또는 MDN의 확장 참조 자료를 확인하세요. WebXR Device API의 초기 버전에 익숙하다면 이 모든 자료를 한 눈에 훑어볼 수 있습니다. 변경사항이 있습니다.

이 문서의 코드는 Immersive Web Working Group의 기본 샘플 (데모, 소스)을 기반으로 하지만 명확성과 단순성을 위해 수정되었습니다.

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. WebGLFramebufferXRWebGLLayer에서 WebGLRenderingContext에 전달('바인딩')합니다.
    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.
}

이제 시청자를 위해 무언가를 그려야 합니다. 이는 2부에서 다루겠습니다. 시작하기 전에 세션을 종료하는 방법을 보여드리겠습니다.

세션 종료

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

세션 시작에서 설정 중에 onend 이벤트 핸들러를 추가했음을 기억하세요.

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

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

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

결론

웹 XR 또는 AR 애플리케이션을 작성하는 데 필요한 모든 내용을 설명하지는 않았습니다. 이 내용을 통해 코드를 직접 이해하고 실험을 시작할 수 있기를 바랍니다. 다음 기사에서는 콘텐츠가 화면에 그려지는 프레임 루프를 설명합니다.

사진: UnsplashJESHOOTS.COM