Membuat sesi AR yang imersif menggunakan WebXR

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

Anda memerlukan lingkungan pengembangan yang kompatibel dengan WebXR untuk memulai.

Membuat halaman HTML

WebXR memerlukan 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 dalamnya:

<!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>

Melakukan inisialisasi three.js

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

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

Membuat scene

Lingkungan 3D biasanya dimodelkan sebagai tampilan. Buat THREE.Scene yang berisi elemen AR. Kode berikut memungkinkan Anda melihat kotak berwarna yang tidak menyala di 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 tampilan ini dalam AR, Anda memerlukan perender dan kamera. Perender menggunakan WebGL untuk menggambar tampilan ke layar. Kamera menjelaskan area pandang tempat tampilan 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 memperbarui kamera dalam tampilan, mengubah cara pengguna melihat dunia virtual sebelum perender menggambar tampilan menggunakan kamera yang diperbarui.

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);

Jalankan Hello WebXR

Buka file WebXR di perangkat Anda. Anda akan dapat melihat kubus berwarna dari semua sisi.

Menambahkan hit test

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

Menghapus kubus demo

Hapus kubus yang tidak diterangi dan ganti dengan tampilan 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 melakukan inisialisasi fungsi hit test, minta sesi dengan fitur hit-test. Temukan fragmen requestSession() sebelumnya, lalu tambahkan hit-test ke fragmen tersebut:

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

Menambahkan loader model

Saat ini, tampilan hanya berisi kubus berwarna. Untuk membuat pengalaman lebih menarik, tambahkan loader model, yang memungkinkan model GLTF 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 asal, yang berarti bahwa hit test dilakukan dari pusat area tampilan.

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 tempat bunga matahari akan ditempatkan, tambahkan reticle penargetan ke tampilan. Reticle ini akan tampak menempel pada permukaan dunia nyata, menandakan di mana bunga matahari akan ditambatkan.

XRFrame.getHitTestResults menampilkan array XRHitTestResult dan mengekspos persimpangan dengan geometri dunia nyata. Gunakan persimpangan ini untuk memosisikan reticle penargetan di 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 di 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 permukaan dunia nyata. Ketuk layar untuk menempatkan bunga matahari, yang dapat dilihat dari semua sisi.

Langkah berikutnya