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

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에 관한 이전 게시물을 읽어보거나 관련 주제를 숙지해야 합니다. 세션을 요청하고 입력하는 방법을 알고 있어야 하며 프레임 루프를 실행하는 방법도 알아야 합니다.

히트 테스트에 관한 자세한 내용은 실제 뷰에서 가상 객체 배치 관련 문서를 참고하세요. 이 문서의 코드는 Immersive Web Working Group의 WebXR Device API 샘플에 있는 몰입형 AR 세션 샘플(데모 소스)을 기반으로 합니다.

코드를 자세히 살펴보기 전에 몰입형 AR 세션 샘플을 한 번 이상 사용해야 합니다. Chrome 81 이상이 설치된 최신 Android 휴대전화가 필요합니다.

어떤 경우에 유용한가요?

증강 현실은 브라우저에서 나가지 않고도 AR 사용 사례를 구현할 수 있도록 하여 많은 기존 웹페이지나 새로운 웹페이지에 귀중한 도움이 될 것입니다. 예를 들어 사람들이 교육 사이트에서 학습하는 데 도움이 되고 잠재 구매자가 쇼핑 중에 집에 있는 사물을 시각화할 수 있습니다.

두 번째 사용 사례를 살펴보겠습니다. 실제 장면에 가상 객체의 실물 크기 표현을 배치한다고 상상해 보세요. 배치되면 이미지는 선택된 노출 영역에 머무르고 실제 항목이 해당 노출 영역에 있을 경우의 크기로 표시되며, 사용자가 그 표면 주변을 이동할 수 있을 뿐만 아니라 가까이 또는 멀리 이동할 수도 있습니다. 이를 통해 시청자는 2차원 이미지를 사용할 때보다 더 깊이 객체를 이해할 수 있습니다.

너무 앞서나가고 있어. 지금까지 설명한 작업을 실제로 실행하려면 AR 기능과 노출 영역을 감지하는 몇 가지 수단이 필요합니다. 이 문서에서는 전자를 다룹니다. WebXR Hit Test 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 세션 샘플을 방문한 경우 처음에는 장면이 정적이며 증강 현실이 아닌 것을 확인할 수 있습니다. 손가락으로 드래그하고 스와이프하여 장면 내에서 이동할 수 있습니다. 'AR 시작'을 클릭하면 배경이 사라지고 기기를 움직여 장면 주위를 이동할 수 있습니다. 모드는 서로 다른 참조 공간 유형을 사용합니다. 위의 강조표시된 텍스트는 선택한 방식을 보여줍니다. 다음과 같은 참조 유형을 사용합니다.

local - 출처는 세션 생성 시 뷰어의 위치에 있습니다. 즉, 환경에 꼭 정의된 하한선이 있는 것은 아니며 원점의 정확한 위치는 플랫폼에 따라 다를 수 있습니다. 공간에 미리 설정된 경계는 없지만 회전 외에 이동 없이 콘텐츠를 볼 수 있을 것으로 예상됩니다. 자체 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 제공)