증강 현실: 이미 알고 계신가요?

이미 WebXR Device API를 사용해 본 적이 있다면 거의 완료된 것입니다.

Joe Medley
Joe Medley

WebXR Device API는 작년 가을 Chrome 79에서 출시되었습니다. 당시 언급했듯이 Chrome의 API 구현은 아직 진행 중입니다. Chrome은 일부 작업이 완료되었음을 알려드립니다. Chrome 81에는 다음과 같은 두 가지 새로운 기능이 도입되었습니다.

이 도움말에서는 증강 현실에 대해 설명합니다. 이미 WebXR Device API를 사용해 본 적이 있다면 알아야 할 새로운 내용이 거의 없다는 점에 안심하세요. WebXR 세션을 시작하는 방법도 거의 같습니다. 프레임 루프를 실행하는 방법도 거의 같습니다. 차이점은 증강 현실에 콘텐츠를 적절하게 표시할 수 있는 구성에 있습니다. WebXR의 기본 개념에 익숙하지 않다면 WebXR Device API에 관한 이전 게시물을 읽거나 적어도 거기에 설명된 주제를 숙지해야 합니다. 세션을 요청하고 들어가는 방법과 프레임 루프를 실행하는 방법을 알아야 합니다.

히트 테스트에 관한 자세한 내용은 관련 도움말인 실제 뷰에 가상 객체 배치를 참고하세요. 이 도움말의 코드는 몰입형 웹 작업 그룹의 WebXR Device API 샘플에 있는 몰입형 AR 세션 샘플(데모 소스)을 기반으로 합니다.

코딩을 시작하기 전에 몰입형 AR 세션 샘플을 한 번 이상 사용해야 합니다. Chrome 81 이상이 설치된 최신 Android 휴대전화가 필요합니다.

이 기능은 어떤 용도로 유용하나요?

증강 현실은 브라우저를 벗어나지 않고도 AR 사용 사례를 구현할 수 있도록 하여 기존 웹페이지 또는 신규 웹페이지에 가치 있는 추가 기능이 될 것입니다. 예를 들어 교육 사이트에서 학습하는 데 도움이 되며, 잠재적 구매자가 쇼핑하는 동안 집에 있는 물건을 시각화할 수 있습니다.

두 번째 사용 사례를 생각해 보세요. 실제 장면에 가상 물체의 실물 크기 표현을 배치하는 시뮬레이션을 생각해 보세요. 배치되면 이미지는 선택한 노출 영역에 머물고 실제 항목이 노출 영역에 있는 것처럼 표시되며 사용자가 이미지를 둘러보거나 이미지에 더 가까이 또는 더 멀리 이동할 수 있습니다. 이를 통해 시청자는 2차원 이미지로 파악할 수 있는 것보다 객체를 더 깊이 이해할 수 있습니다.

제가 조금 진도를 앞서 가는 듯 합니다. 설명한 작업을 실제로 실행하려면 AR 기능과 표면을 감지하는 수단이 필요합니다. 이 도움말에서는 전자를 다룹니다. WebXR 히트 테스트 API에 관한 함께 제공되는 도움말 (위 링크 참고)에서는 후자를 다룹니다.

세션 요청

세션을 요청하는 방법은 이전에 본 것과 매우 유사합니다. 먼저 xr.isSessionSupported()를 호출하여 원하는 세션 유형을 현재 기기에서 사용할 수 있는지 확인합니다. 이전과 같이 'immersive-vr'를 요청하는 대신 'immersive-ar'를 요청합니다.

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

이전과 마찬가지로 'AR 시작' 버튼이 사용 설정됩니다. 사용자가 클릭하면 xr.requestSession()를 호출하고 'immersive-ar'도 전달합니다.

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

편의 속성

마지막 코드 샘플에서 두 줄을 강조 표시했음을 눈치채셨을 것입니다. XRSession 객체에 isImmersive라는 속성이 있는 것처럼 보입니다. 이 속성은 내가 직접 만든 편의 속성이므로 사양의 일부가 아닙니다. 나중에 시청자에게 표시할 항목을 결정하는 데 사용합니다. 이 속성이 API의 일부가 아닌 이유는 무엇인가요? 앱에서 이 속성을 다르게 추적해야 할 수 있으므로 사양 작성자는 API를 깔끔하게 유지하기로 결정했습니다.

세션 시작

이전 도움말에서 onSessionStarted()가 어떻게 표시되었는지 기억해 보세요.

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

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

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

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

증강 현실 렌더링을 고려하여 몇 가지 항목을 추가해야 합니다. 배경을 사용 중지합니다. 먼저 배경이 필요한지 확인합니다. 여기에서 편의 속성을 처음 사용합니다.

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

  if (session.isImmersive) {
    removeBackground();
  }

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

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

  refSpaceType = xrSession.isImmersive ? 'local' : 'viewer';
  xrSession.requestReferenceSpace(refSpaceType).then((refSpace) => {
    xrSession.requestAnimationFrame(onXRFrame);
  });

}

참조 공간

이전 도움말에서는 참조 스페이스를 간략히 살펴봤습니다. 제가 설명하는 샘플에서는 이 중 두 개를 사용하므로 누락된 부분을 수정해야 합니다.

참조 공간은 가상 세계와 사용자의 실제 환경 간의 관계를 설명합니다. 다음과 같은 작업을 통해 이를 실행합니다.

  • 가상 세계의 위치를 표현하는 데 사용되는 좌표계의 원점을 지정합니다.
  • 사용자가 해당 좌표계 내에서 이동할 것으로 예상되는지 지정합니다.
  • 해당 좌표계에 사전 설정된 경계가 있는지 여부입니다. 여기에 표시된 예시는 사전 설정된 경계가 있는 좌표계를 사용하지 않습니다.

모든 참조 공간에서 X 좌표는 왼쪽과 오른쪽을, Y는 위와 아래를, Z는 앞뒤를 나타냅니다. 양수 값은 각각 오른쪽, 위쪽, 뒤쪽을 나타냅니다.

XRFrame.getViewerPose()에서 반환하는 좌표는 요청된 참조 공간 유형에 따라 다릅니다. 프레임 루프에 관해 자세히 알아보겠습니다. 지금은 증강 현실에 적합한 참조 유형을 선택해야 합니다. 여기서도 편의 속성을 사용합니다.

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

  if (session.isImmersive) {
    removeBackground();
  }

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

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

  refSpaceType = xrSession.isImmersive ? 'local' : 'viewer';
  xrSession.requestReferenceSpace(refSpaceType).then((refSpace) => {
    xrSession.requestAnimationFrame(onXRFrame);
  });
}

몰입형 AR 세션 샘플을 방문한 경우 처음에는 장면이 정적이며 증강 현실이 전혀 적용되지 않는 것을 알 수 있습니다. 손가락을 드래그하고 스와이프하여 장면을 이동할 수 있습니다. 'START AR'을 클릭하면 배경이 사라지고 기기를 움직여 장면을 이동할 수 있습니다. 모드는 서로 다른 참조 공간 유형을 사용합니다. 위에서 강조 표시된 텍스트는 선택 방법을 보여줍니다. 다음 참조 유형을 사용합니다.

local - 원점은 세션 생성 시 시청자의 위치에 있습니다. 즉, 환경에 반드시 잘 정의된 하한선이 있는 것은 아니며 원점의 정확한 위치는 플랫폼에 따라 다를 수 있습니다. 공간에 사전 설정된 경계는 없지만 회전 외의 움직임 없이 콘텐츠를 볼 수 있을 것으로 예상됩니다. Google의 AR 예시에서 볼 수 있듯이 공간 내에서 약간의 움직임이 가능할 수 있습니다.

viewer - 페이지에 인라인으로 표시되는 콘텐츠에 가장 자주 사용되는 이 공백은 시청 기기를 따릅니다. getViewerPose에 전달되면 추적을 제공하지 않으므로 애플리케이션에서 XRReferenceSpace.getOffsetReferenceSpace()로 수정하지 않는 한 항상 원점에 있는 포즈를 보고합니다. 샘플에서는 이를 사용하여 카메라의 터치 기반 화면 이동을 사용 설정합니다.

프레임 루프 실행

개념적으로는 이전 도움말에 설명된 VR 세션에서 수행한 작업과 다르지 않습니다. 참조 공간 유형을 XRFrame.getViewerPose()에 전달합니다. 반환된 XRViewerPose는 현재 참조 스페이스 유형에 해당합니다. viewer를 기본값으로 사용하면 페이지에서 AR 또는 VR에 대한 사용자 동의가 요청되기 전에 콘텐츠 미리보기를 표시할 수 있습니다. 이는 중요한 점을 보여줍니다. 인라인 콘텐츠는 몰입형 콘텐츠와 동일한 프레임 루프를 사용하므로 유지해야 하는 코드의 양이 줄어듭니다.

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  let xrViewerPose = xrFrame.getViewerPose(refSpaceType);
  if (xrViewerPose) {
    // Render based on the pose.
  }
}

결론

이 도움말 시리즈에서는 웹에서 몰입형 콘텐츠를 구현하는 기본사항만 다룹니다. 몰입형 웹 작업 그룹의 WebXR Device API 샘플에서는 더 많은 기능과 사용 사례를 보여줍니다. 또한 표면을 감지하고 실제 카메라 뷰에 가상 항목을 배치하는 API를 설명하는 히트 테스트 도움말도 게시했습니다. 올해는 web.dev 블로그에서 더 많은 도움말을 확인하세요.

사진: Unsplash데이비드 그랑모긴