Tạo phiên thực tế tăng cường sống động bằng WebXR

Trang này sẽ hướng dẫn bạn cách tạo một ứng dụng thực tế tăng cường sống động đơn giản bằng WebXR.

Bạn sẽ cần một môi trường phát triển tương thích với WebXR để bắt đầu.

Tạo trang HTML

WebXR cần có sự tương tác của người dùng để có thể bắt đầu phiên. Tạo một nút gọi activateXR(). Sau khi tải trang, người dùng có thể sử dụng nút này để bắt đầu trải nghiệm thực tế tăng cường.

Tạo một tệp mới có tên là index.html rồi thêm mã HTML sau vào tệp đó:

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

Khởi chạy three.js

Sẽ không có gì xảy ra khi bạn nhấn nút Start (Bắt đầu). Để thiết lập môi trường 3D, bạn có thể sử dụng thư viện kết xuất để hiển thị cảnh.

Trong ví dụ này, bạn sẽ sử dụng three.js, một thư viện kết xuất JavaScript 3D cung cấp trình kết xuất WebGL. Three.js xử lý việc kết xuất, máy ảnh và biểu đồ cảnh, giúp bạn dễ dàng hiển thị nội dung 3D trên web.

Tạo cảnh

Môi trường 3D thường được mô hình hoá dưới dạng một cảnh. Tạo một THREE.Scene chứa các phần tử AR. Mã sau đây cho phép bạn xem một hộp màu không được chiếu sáng trong AR.

Thêm mã này vào cuối hàm 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);

Thiết lập tính năng kết xuất bằng three.js

Để có thể xem cảnh này ở chế độ AR, bạn cần có trình kết xuấtmáy ảnh. Trình kết xuất sử dụng WebGL để vẽ cảnh của bạn lên màn hình. Máy ảnh mô tả khung nhìn mà cảnh được xem.

Thêm mã này vào cuối hàm 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;

Tạo một XRSession

Điểm truy cập vào WebXR là thông qua XRSystem.requestSession(). Sử dụng chế độ immersive-ar để cho phép xem nội dung kết xuất trong môi trường thực tế.

XRReferenceSpace mô tả hệ toạ độ dùng cho các đối tượng trong thế giới ảo. Chế độ 'local' phù hợp nhất với trải nghiệm AR, với không gian tham chiếu có gốc gần người xem và khả năng theo dõi ổn định.

Để tạo XRSessionXRReferenceSpace, hãy thêm mã này vào cuối hàm 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');

Kết xuất cảnh

Bây giờ, bạn có thể kết xuất cảnh. XRSession.requestAnimationFrame() lên lịch cho một lệnh gọi lại được thực thi khi trình duyệt đã sẵn sàng vẽ khung.

Trong lệnh gọi lại khung ảnh động, hãy gọi XRFrame.getViewerPose() để lấy tư thế của người xem so với không gian toạ độ cục bộ. Phương thức này dùng để cập nhật máy ảnh trong cảnh, thay đổi cách người dùng xem thế giới ảo trước khi trình kết xuất vẽ cảnh bằng máy ảnh đã cập nhật.

Thêm mã này vào cuối hàm 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);

Chạy Hello WebXR

Chuyển đến tệp WebXR trên thiết bị của bạn. Bạn sẽ có thể xem một khối màu từ mọi phía.

Thêm kiểm thử lượt nhấn

Một cách phổ biến để tương tác với thế giới AR là thông qua kiểm thử va chạm. Phương thức này tìm thấy giao điểm giữa một tia và hình học thực tế. Trong Hello WebXR, bạn sẽ dùng một phép thử nhấn để đặt một bông hoa hướng dương vào thế giới ảo.

Xoá khối minh hoạ

Xoá khối không sáng và thay thế bằng một cảnh có ánh sáng:

const scene = new THREE.Scene();

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

Sử dụng tính năng hit-test

Để khởi chạy chức năng kiểm thử lượt nhấn, hãy yêu cầu phiên bằng tính năng hit-test. Tìm mảnh requestSession() trước đó rồi thêm hit-test vào mảnh đó:

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

Thêm trình tải mô hình

Hiện tại, cảnh này chỉ chứa một khối màu. Để trải nghiệm trở nên thú vị hơn, hãy thêm trình tải mô hình cho phép tải mô hình GLTF.

Trong thẻ <head> của tài liệu, hãy thêm ba.js' GLTFLoader.

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

Tải mô hình GLTF

Sử dụng trình tải mô hình từ bước trước để tải một mục tiêu ngắm và một hoa hướng dương từ web.

Thêm mã này vào phía trên 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) => {

Tạo nguồn kiểm thử lượt nhấn

Để tính toán các giao điểm với các đối tượng trong thực tế, hãy tạo một XRHitTestSource bằng cách sử dụng XRSession.requestHitTestSource(). Tia sáng dùng để kiểm thử lượt nhấn có không gian tham chiếu viewer làm gốc, nghĩa là kiểm thử lượt nhấn được thực hiện từ tâm của khung nhìn.

Để tạo nguồn kiểm thử nhấn, hãy thêm mã sau đây sau khi tạo không gian tham chiếu 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 });

Vẽ một kim ngắm mục tiêu

Để biết rõ vị trí đặt hoa hướng dương, hãy thêm ô nhắm mục tiêu vào cảnh. Dấu ngắm này sẽ xuất hiện trên các bề mặt thực tế, cho biết vị trí hoa hướng dương sẽ được neo.

XRFrame.getHitTestResults trả về một mảng XRHitTestResult và hiển thị các giao điểm với hình học thực tế. Sử dụng các giao điểm này để định vị tâm ngắm mục tiêu trên mọi khung hình.

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

Thêm lượt tương tác khi nhấn

XRSession nhận được các sự kiện select khi người dùng hoàn tất một hành động chính. Trong một phiên AR, thao tác này tương ứng với một lần nhấn vào màn hình.

Tạo một hoa hướng dương mới xuất hiện khi người dùng nhấn vào màn hình bằng cách thêm mã này trong quá trình khởi chạy:

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

Kiểm thử thử nghiệm nhấn

Sử dụng thiết bị di động để chuyển đến trang đó. Sau khi WebXR xây dựng hiểu biết về môi trường, lưới sẽ xuất hiện trên các bề mặt thực tế. Nhấn vào màn hình để đặt một bông hướng dương có thể xem được từ mọi phía.

Các bước tiếp theo