
프론트엔드
WebXRWebXR
WebXR Device API는 브라우저에서 VR(가상현실)과 AR(증강현실) 경험을 구현하는 웹 표준 API다. WebVR의 후속으로 2019년 표준화되었으며, Three.js, Babylon.js, A-Frame 등과 함께 사용된다.
WebXR 세션 유형
| 유형 | 설명 | 사용 기기 |
|---|---|---|
| immersive-vr | 완전 가상현실 (헤드셋 전체 화면) | Quest, Valve Index |
| immersive-ar | 현실 공간에 가상 오브젝트 | 폰 카메라, HoloLens |
| inline | 페이지 내 3D 미리보기 | 모든 브라우저 |
기본 VR 세션
javascript
// WebXR 지원 확인
if (navigator.xr) {
const supported = await navigator.xr.isSessionSupported('immersive-vr');
if (supported) {
document.querySelector('#enter-vr').addEventListener('click', enterVR);
}
}
async function enterVR() {
const session = await navigator.xr.requestSession('immersive-vr', {
requiredFeatures: ['local-floor'],
optionalFeatures: ['hand-tracking'],
});
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2', { xrCompatible: true });
await gl.makeXRCompatible();
const layer = new XRWebGLLayer(session, gl);
session.updateRenderState({ baseLayer: layer });
const refSpace = await session.requestReferenceSpace('local-floor');
session.requestAnimationFrame(function onXRFrame(time, frame) {
session.requestAnimationFrame(onXRFrame);
const pose = frame.getViewerPose(refSpace);
if (!pose) return;
gl.bindFramebuffer(gl.FRAMEBUFFER, layer.framebuffer);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
for (const view of pose.views) {
const viewport = layer.getViewport(view);
gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
renderEye(view.projectionMatrix, view.transform.inverse.matrix);
}
});
}Three.js WebXR (더 쉬운 방법)
javascript
import * as THREE from 'three';
import { VRButton } from 'three/addons/webxr/VRButton.js';
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.xr.enabled = true;
document.body.appendChild(VRButton.createButton(renderer));
// VR 컨트롤러
const controller1 = renderer.xr.getController(0);
controller1.addEventListener('selectstart', onSelectStart);
scene.add(controller1);
// XR 렌더 루프
renderer.setAnimationLoop((timestamp, frame) => {
if (frame) {
// XR 세션 활성 상태
const referenceSpace = renderer.xr.getReferenceSpace();
const session = renderer.xr.getSession();
}
renderer.render(scene, camera);
});AR 히트 테스트 (현실 표면 감지)
javascript
const session = await navigator.xr.requestSession('immersive-ar', {
requiredFeatures: ['hit-test'],
});
const hitTestSource = await session.requestHitTestSource({
space: await session.requestReferenceSpace('viewer'),
});
session.requestAnimationFrame((time, frame) => {
const hitTestResults = frame.getHitTestResults(hitTestSource);
if (hitTestResults.length > 0) {
const pose = hitTestResults[0].getPose(refSpace);
// 현실 표면에 오브젝트 배치
reticle.matrix.fromArray(pose.transform.matrix);
}
});