Membuat sesi AR yang imersif menggunakan WebXR

Halaman ini akan memandu Anda untuk membuat aplikasi AR imersif yang sederhana menggunakan WebXR.

Anda memerlukan lingkungan pengembangan yang kompatibel dengan WebXR untuk memulai.

Membuat halaman HTML

WebXR mengharuskan interaksi pengguna agar dapat memulai sesi. Buat tombol yang memanggil activateXR(). Setelah memuat halaman, pengguna dapat menggunakan tombol ini untuk memulai pengalaman AR.

Buat file baru bernama index.html dan tambahkan kode HTML berikut ke file tersebut:

<!doctype html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <title>Hello WebXR!</title>

  <!-- three.js -->
  <script src="https://unpkg.com/three@0.126.0/build/three.js"></script>
</head>
<body>

<!-- Starting an immersive WebXR session requires user interaction.
    We start this one with a simple button. -->
<button onclick="activateXR()">Start Hello WebXR</button>
<script>
async function activateXR() {
  // Add a canvas element and initialize a WebGL context that is compatible with WebXR.
  const canvas = document.createElement("canvas");
  document.body.appendChild(canvas);
  const gl = canvas.getContext("webgl", {xrCompatible: true});

  // To be continued in upcoming steps.
}
</script>
</body>
</html>

Menginisialisasi tiga.js

Tidak banyak yang akan terjadi saat menekan tombol Start. Untuk menyiapkan lingkungan 3D, Anda dapat menggunakan library rendering untuk menampilkan adegan.

Dalam contoh ini, Anda akan menggunakan three.js, library rendering 3D JavaScript yang menyediakan perender WebGL. Three.js menangani rendering, kamera, dan grafik adegan, sehingga konten 3D lebih mudah ditampilkan di web.

Membuat scene

Lingkungan 3D umumnya dimodelkan sebagai adegan. Buat THREE.Scene yang berisi elemen AR. Kode berikut memungkinkan Anda melihat kotak berwarna tanpa lampu dalam AR.

Tambahkan kode ini ke bagian bawah fungsi activateXR():

const scene = new THREE.Scene();

// The cube will have a different color on each side.
const materials = [
  new THREE.MeshBasicMaterial({color: 0xff0000}),
  new THREE.MeshBasicMaterial({color: 0x0000ff}),
  new THREE.MeshBasicMaterial({color: 0x00ff00}),
  new THREE.MeshBasicMaterial({color: 0xff00ff}),
  new THREE.MeshBasicMaterial({color: 0x00ffff}),
  new THREE.MeshBasicMaterial({color: 0xffff00})
];

// Create the cube and add it to the demo scene.
const cube = new THREE.Mesh(new THREE.BoxBufferGeometry(0.2, 0.2, 0.2), materials);
cube.position.set(1, 1, 1);
scene.add(cube);

Menyiapkan rendering menggunakan Three.js

Agar dapat melihat adegan ini dalam AR, Anda memerlukan renderer dan kamera. Perender menggunakan WebGL untuk menggambar scene Anda ke layar. Kamera menjelaskan area pandang tempat adegan dilihat.

Tambahkan kode ini ke bagian bawah fungsi activateXR():

// Set up the WebGLRenderer, which handles rendering to the session's base layer.
const renderer = new THREE.WebGLRenderer({
  alpha: true,
  preserveDrawingBuffer: true,
  canvas: canvas,
  context: gl
});
renderer.autoClear = false;

// The API directly updates the camera matrices.
// Disable matrix auto updates so three.js doesn't attempt
// to handle the matrices independently.
const camera = new THREE.PerspectiveCamera();
camera.matrixAutoUpdate = false;

Membuat XRSession

Titik entri ke WebXR adalah melalui XRSystem.requestSession(). Gunakan mode immersive-ar agar konten yang dirender dapat dilihat di lingkungan dunia nyata.

XRReferenceSpace menjelaskan sistem koordinat yang digunakan untuk objek dalam dunia virtual. Mode 'local' sangat cocok digunakan untuk pengalaman AR, dengan ruang referensi yang memiliki asal di dekat penampil dan pelacakan yang stabil.

Untuk membuat XRSession dan XRReferenceSpace, tambahkan kode ini ke bagian bawah fungsi activateXR():

// Initialize a WebXR session using "immersive-ar".
const session = await navigator.xr.requestSession("immersive-ar");
session.updateRenderState({
  baseLayer: new XRWebGLLayer(session, gl)
});

// A 'local' reference space has a native origin that is located
// near the viewer's position at the time the session was created.
const referenceSpace = await session.requestReferenceSpace('local');

Render tampilan

Sekarang Anda dapat merender tampilan. XRSession.requestAnimationFrame() menjadwalkan callback yang dijalankan saat browser siap menggambar frame.

Selama callback frame animasi, panggil XRFrame.getViewerPose() untuk mendapatkan pose penampil yang relatif terhadap ruang koordinat lokal. Ini digunakan untuk mengupdate kamera dalam adegan, mengubah cara pengguna melihat dunia virtual sebelum perender menggambar adegan menggunakan kamera yang telah diupdate.

Tambahkan kode ini ke bagian bawah fungsi activateXR():

// Create a render loop that allows us to draw on the AR view.
const onXRFrame = (time, frame) => {
  // Queue up the next draw request.
  session.requestAnimationFrame(onXRFrame);

  // Bind the graphics framebuffer to the baseLayer's framebuffer
  gl.bindFramebuffer(gl.FRAMEBUFFER, session.renderState.baseLayer.framebuffer)

  // Retrieve the pose of the device.
  // XRFrame.getViewerPose can return null while the session attempts to establish tracking.
  const pose = frame.getViewerPose(referenceSpace);
  if (pose) {
    // In mobile AR, we only have one view.
    const view = pose.views[0];

    const viewport = session.renderState.baseLayer.getViewport(view);
    renderer.setSize(viewport.width, viewport.height)

    // Use the view's transform matrix and projection matrix to configure the THREE.camera.
    camera.matrix.fromArray(view.transform.matrix)
    camera.projectionMatrix.fromArray(view.projectionMatrix);
    camera.updateMatrixWorld(true);

    // Render the scene with THREE.WebGLRenderer.
    renderer.render(scene, camera)
  }
}
session.requestAnimationFrame(onXRFrame);

Menjalankan Hello WebXR

Buka file WebXR di perangkat Anda. Anda seharusnya bisa melihat kubus berwarna dari semua sisi.

Menambahkan hit test

Cara umum untuk berinteraksi dengan dunia AR adalah melalui uji hit, yang menemukan titik potong antara sinar dan geometri dunia nyata. Pada Hello WebXR, Anda akan menggunakan hit test untuk menempatkan bunga matahari di dunia virtual.

Menghapus kubus demo

Hapus kubus yang tidak menyala dan ganti dengan adegan yang menyertakan pencahayaan:

const scene = new THREE.Scene();

const directionalLight = new THREE.DirectionalLight(0xffffff, 0.3);
directionalLight.position.set(10, 15, 10);
scene.add(directionalLight);

Menggunakan fitur hit-test

Untuk menginisialisasi fungsi hit test, minta sesi dengan fitur hit-test. Temukan fragmen requestSession() sebelumnya, lalu tambahkan hit-test ke dalamnya:

const session = await navigator.xr.requestSession("immersive-ar", {requiredFeatures: ['hit-test']});

Menambahkan loader model

Saat ini, adegan hanya berisi kubus berwarna. Untuk membuat pengalaman lebih menarik, tambahkan loader model, yang memungkinkan model GTF dimuat.

Di tag <head> dokumen Anda, tambahkan GLTFLoader Three.js'.

<!-- three.js -->
<script src="https://unpkg.com/three@0.126.0/build/three.js"></script>

<script src="https://unpkg.com/three@0.126.0/examples/js/loaders/GLTFLoader.js"></script>

Memuat model GLTF

Gunakan loader model dari langkah sebelumnya untuk memuat reticle penargetan dan bunga matahari dari web.

Tambahkan kode ini di atas onXRFrame:

const loader = new THREE.GLTFLoader();
let reticle;
loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/reticle/reticle.gltf", function(gltf) {
  reticle = gltf.scene;
  reticle.visible = false;
  scene.add(reticle);
})

let flower;
loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/sunflower/sunflower.gltf", function(gltf) {
  flower = gltf.scene;
});

// Create a render loop that allows us to draw on the AR view.
const onXRFrame = (time, frame) => {

Membuat sumber hit test

Untuk menghitung persimpangan dengan objek dunia nyata, buat XRHitTestSource menggunakan XRSession.requestHitTestSource(). Sinar yang digunakan untuk hit testing memiliki ruang referensi viewer sebagai origin, yang berarti hit test dilakukan dari tengah area pandang.

Untuk membuat sumber hit test, tambahkan kode ini setelah membuat ruang referensi local:

// A 'local' reference space has a native origin that is located
// near the viewer's position at the time the session was created.
const referenceSpace = await session.requestReferenceSpace('local');

// Create another XRReferenceSpace that has the viewer as the origin.
const viewerSpace = await session.requestReferenceSpace('viewer');
// Perform hit testing using the viewer as origin.
const hitTestSource = await session.requestHitTestSource({ space: viewerSpace });

Menggambar reticle penargetan

Untuk memperjelas lokasi penempatan bunga matahari, tambahkan reticle penargetan ke adegan. Reticle ini akan tampak menempel pada permukaan dunia nyata, menandakan tempat bunga matahari akan berlabuh.

XRFrame.getHitTestResults menampilkan array XRHitTestResult dan menampilkan persimpangan dengan geometri dunia nyata. Gunakan persimpangan ini untuk memosisikan reticle penargetan pada setiap frame.

camera.projectionMatrix.fromArray(view.projectionMatrix);
camera.updateMatrixWorld(true);

const hitTestResults = frame.getHitTestResults(hitTestSource);
if (hitTestResults.length > 0 && reticle) {
  const hitPose = hitTestResults[0].getPose(referenceSpace);
  reticle.visible = true;
  reticle.position.set(hitPose.transform.position.x, hitPose.transform.position.y, hitPose.transform.position.z)
  reticle.updateMatrixWorld(true);
}

Menambahkan interaksi saat diketuk

XRSession menerima peristiwa select saat pengguna menyelesaikan tindakan utama. Dalam sesi AR, ini sesuai dengan ketukan pada layar.

Buat bunga matahari baru muncul saat pengguna mengetuk layar dengan menambahkan kode ini selama inisialisasi:

let flower;
loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/sunflower/sunflower.gltf", function(gltf) {
  flower = gltf.scene;
});

session.addEventListener("select", (event) => {
  if (flower) {
    const clone = flower.clone();
    clone.position.copy(reticle.position);
    scene.add(clone);
  }
});

Menguji hit test

Gunakan perangkat seluler untuk membuka halaman. Setelah WebXR membangun pemahaman tentang lingkungan, reticle akan muncul di platform dunia nyata. Ketuk layar untuk meletakkan bunga matahari, yang dapat dilihat dari semua sisi.

Langkah berikutnya