Thực tế ảo xuất hiện trên web

Một số kiến thức cơ bản giúp bạn chuẩn bị cho nhiều trải nghiệm sống động: thực tế ảo, thực tế tăng cường và các tính năng khác.

Joe Medley
Joe Medley

Trải nghiệm sống động đến với web trong Chrome 79. WebXR Device API mang đến thực tế ảo mang thực tế ảo, đồng thời hỗ trợ thực tế tăng cường trong Chrome 81. Trong khi bản cập nhật cho API GamePad sẽ mở rộng việc sử dụng các chế độ điều khiển nâng cao cho Thực tế ảo (VR). Các trình duyệt khác sẽ sớm hỗ trợ những thông số kỹ thuật này, bao gồm cả trình duyệt Firefox thực tế, trình duyệt Oculus, Edge và trình duyệt Helio của Magic Leap, cùng các trình duyệt khác.

Bài viết này bắt đầu một loạt bài viết về web sống động. Phần này bao gồm việc thiết lập ứng dụng WebXR cơ bản, cũng như nhập và thoát khỏi phiên XR. Các bài viết sau này sẽ đề cập đến vòng lặp khung (công việc của trải nghiệm WebXR), thông tin cụ thể về thực tế tăng cường và WebXR Hit Test API (API Kiểm thử lượt truy cập) WebXR, một phương tiện để phát hiện các khu vực trong phiên AR. Trừ phi có quy định khác, mọi nội dung tôi đề cập trong bài viết này và các bài viết thành công đều áp dụng như nhau cho cả Thực tế tăng cường (AR) và Thực tế ảo (VR).

Web sống động là gì?

Mặc dù chúng tôi dùng hai thuật ngữ để mô tả các trải nghiệm sống động – thực tế tăng cường và thực tế ảo – nhiều người nghĩ về chúng trên một loạt các trải nghiệm, từ thực tế hoàn toàn đến thực tế ảo hoàn toàn, với các mức độ đắm chìm giữa các mức độ. Chữ 'X' trong XR nhằm phản ánh tư duy đó bằng cách trở thành một loại biến đại số đại diện cho bất kỳ thứ gì trong nhiều trải nghiệm sống động.

Biểu đồ minh hoạ các trải nghiệm hình ảnh từ thực tế hoàn toàn đến hoàn toàn sống động.
Nhiều trải nghiệm sống động

Sau đây là một số ví dụ về trải nghiệm sống động:

  • Trò chơi
  • Video 360°
  • Video 2D (hoặc 3D) truyền thống được trình bày trong môi trường sống động
  • Mua nhà
  • Xem sản phẩm trong nhà trước khi mua
  • Nghệ thuật sống động
  • Nội dung thú vị chưa ai nghĩ đến

Khái niệm và cách sử dụng

Tôi sẽ giải thích một vài khái niệm cơ bản về việc sử dụng WebXR Device API. Nếu bạn cần nhiều chiều sâu hơn những gì tôi đã cung cấp, hãy xem mẫu WebXR của Nhóm làm việc tích hợp web sống động hoặc tài liệu tham chiếu ngày càng phát triển của MN. Nếu bạn quen thuộc với các phiên bản ban đầu của API thiết bị WebXR, bạn nên xem qua tất cả tài liệu này. Đã có một số thay đổi.

Mã trong bài viết này dựa trên mẫu cơ bản của Nhóm hoạt động web sống động (demo, source) nhưng đã được chỉnh sửa để đảm bảo tính rõ ràng và đơn giản.

Một phần trong quá trình tạo thông số kỹ thuật WebXR đã tăng cường các biện pháp bảo mật và quyền riêng tư để bảo vệ người dùng. Do đó, quá trình triển khai phải tuân thủ một số yêu cầu nhất định. Trang web hoặc ứng dụng phải đang hoạt động và tập trung trước khi có thể yêu cầu bất kỳ nội dung nhạy cảm nào từ người xem. Trang web hoặc ứng dụng phải được phân phát qua HTTPS. Bản thân API này được thiết kế để bảo vệ thông tin thu được từ các cảm biến và camera cần có để hoạt động.

Yêu cầu phiên

Bạn cần có cử chỉ của người dùng để tham gia phiên XR. Để có được điều đó, hãy sử dụng chế độ phát hiện tính năng để kiểm thử XRSystem (thông qua navigator.xr) và thực hiện lệnh gọi đến XRSystem.isSessionSupported(). Xin lưu ý rằng trong Chrome phiên bản 79 và 80, đối tượng XRSystem được gọi là XR.

Trong ví dụ bên dưới, tôi đã cho biết rằng tôi muốn có một phiên thực tế ảo với loại phiên 'immersive-vr'. Các loại phiên khác'immersive-ar''inline'. Phiên cùng dòng dùng để trình bày nội dung trong HTML và chủ yếu dùng cho nội dung quảng cáo xem trước video. Mẫu Phiên thực tế tăng cường sống động minh hoạ việc này. Tôi sẽ giải thích điều đó trong một bài viết sau.

Sau khi biết rằng các phiên thực tế ảo được hỗ trợ, tôi sẽ bật một nút cho phép tôi thực hiện cử chỉ của người dùng.

if (navigator.xr) {
  const supported = await navigator.xr.isSessionSupported('immersive-vr');
  if (supported) {
    xrButton.addEventListener('click', onButtonClicked);
    xrButton.textContent = 'Enter VR';
    xrButton.enabled = supported; // supported is Boolean
  }
}

Sau khi bật nút này, tôi sẽ đợi một sự kiện nhấp chuột rồi yêu cầu một phiên.

let xrSession = null;
function onButtonClicked() {
  if (!xrSession) {
    navigator.xr.requestSession('immersive-vr')
    .then((session) => {
      xrSession = session;
      xrButton.textContent = 'Exit XR';
      onSessionStarted(xrSession);
    });
  } else {
    xrSession.end();
  }
}

Hãy lưu ý hệ phân cấp đối tượng trong mã này. Nó di chuyển từ navigator sang xr sang một thực thể XRSession. Trong các phiên bản đầu tiên của API, tập lệnh phải yêu cầu một thiết bị trước khi yêu cầu phiên. Giờ đây, thiết bị sẽ được tiếp nhận ngầm.

Tham gia phiên

Sau khi nhận được một phiên, tôi cần khởi động và nhập phiên đó. Nhưng trước tiên, tôi cần thiết lập một vài thứ. Một phiên cần có trình xử lý sự kiện onend để có thể đặt lại ứng dụng hoặc trang web khi người dùng thoát.

Tôi cũng cần có phần tử <canvas> để vẽ cảnh của mình. Giao diện này phải là một WebGLRenderingContext hoặc WebGL2RenderingContext tương thích với XR. Toàn bộ quá trình vẽ đều được thực hiện bằng cách sử dụng các đối tượng này hoặc một khung dựa trên WebGL, chẳng hạn như Three.js.

Bây giờ, khi đã có một nơi để vẽ, tôi cần một nguồn nội dung để vẽ trên đó. Để làm được việc đó, tôi tạo một phiên bản của XRWebGLLayer. Tôi liên kết nó với canvas bằng cách gọi XRSession.updateRenderState().

Khi đang tham gia một phiên hoạt động, tôi cần một cách để xác định vị trí của mọi thứ trong thực tế ảo. Tôi cần một không gian tham chiếu. Không gian tham chiếu 'local-floor' là không gian mà điểm gốc nằm gần trình xem và trục y là 0 ở cấp độ tầng và dự kiến sẽ không di chuyển. Có các loại không gian tham chiếu khác, nhưng đó là chủ đề phức tạp hơn tôi có thể trình bày ở đây. Tôi lưu không gian tham chiếu vào một biến vì tôi sẽ cần đến nó khi vẽ lên màn hình.

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);

  let canvas = document.createElement('canvas');
  webGLRenContext = canvas.getContext('webgl', { xrCompatible: true });

  xrSession.updateRenderState({
    baseLayer: new XRWebGLLayer(xrSession, webGLRenContext)
  });

  xrSession.requestReferenceSpace('local-floor')
  .then((refSpace) => {
    xrRefSpace = refSpace;
    xrSession.requestAnimationFrame(onXRFrame);
  });
}

Sau khi có không gian tham chiếu, tôi sẽ gọi XRSession.requestAnimationFrame(). Đây là điểm bắt đầu của quá trình trình bày nội dung ảo, được thực hiện trong vòng lặp khung.

Chạy vòng lặp khung

Vòng lặp khung là một vòng lặp vô hạn do tác nhân người dùng kiểm soát, trong đó nội dung được vẽ lặp lại lên màn hình. Nội dung được vẽ trong các khối riêng biệt được gọi là khung. Liên tục các khung hình tạo ra ảo giác về chuyển động. Đối với các ứng dụng thực tế ảo, khung hình/giây có thể nằm trong khoảng từ 60 đến 144. AR cho Android chạy ở tốc độ 30 khung hình/giây. Mã của bạn không được giả định bất kỳ tốc độ khung hình cụ thể nào.

Quy trình cơ bản của vòng lặp khung là:

  1. Gọi cho XRSession.requestAnimationFrame(). Để phản hồi, tác nhân người dùng sẽ gọi XRFrameRequestCallback do bạn xác định.
  2. Bên trong hàm callback:
    1. Gọi lại cho XRSession.requestAnimationFrame().
    2. Xem tư thế của người xem.
    3. Truyền "liên kết" WebGLFramebuffer từ XRWebGLLayer vào WebGLRenderingContext.
    4. Lặp lại trên từng đối tượng XRView, truy xuất XRViewport của đối tượng đó từ XRWebGLLayer rồi truyền đối tượng đó vào WebGLRenderingContext.
    5. Vẽ nội dung nào đó vào vùng đệm khung.

Phần còn lại của bài viết này mô tả bước 1 và một phần của bước 2, hãy thiết lập và gọi XRFrameRequestCallback. Các mục còn lại của bước 2 được đề cập trong phần II.

XRFrameRequestCallback

XRFrameRequestCallback là do bạn xác định. Phương thức này sẽ nhận 2 tham số: thực thể DOMHighResTimeStampXRFrame. Đối tượng XRFrame cung cấp thông tin cần thiết để kết xuất một khung duy nhất lên màn hình. Đối số DOMHighResTimeStamp sẽ được sử dụng trong tương lai.

Trước khi làm bất cứ điều gì khác, tôi sẽ yêu cầu khung ảnh động tiếp theo. Như đã nêu trước đây, thời gian kết xuất khung hình do tác nhân người dùng xác định dựa trên phần cứng cơ bản. Trước tiên, việc yêu cầu khung tiếp theo sẽ đảm bảo rằng vòng lặp khung sẽ tiếp tục nếu có vấn đề trong khi gọi lại trả về lỗi.

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  // Render a frame.
}

Đã đến lúc vẽ một nội dung nào đó cho người xem. Đó là nội dung thảo luận trong phần II. Trước khi chuyển sang phần này, hãy để tôi hướng dẫn bạn cách kết thúc một phiên.

Kết thúc phiên

Một phiên sống động có thể kết thúc vì một số lý do, trong đó có việc kết thúc bằng mã của riêng bạn thông qua lệnh gọi đến XRSession.end(). Các nguyên nhân khác bao gồm tai nghe bị ngắt kết nối hoặc một ứng dụng khác đang kiểm soát tai nghe đó. Đây là lý do tại sao một ứng dụng hoạt động tốt nên theo dõi sự kiện end. Khi phiên hoạt động này xảy ra, hãy loại bỏ phiên đó và các đối tượng kết xuất có liên quan. Bạn không thể tiếp tục một phiên sống động đã kết thúc. Để vào lại trải nghiệm sống động, ứng dụng của tôi cần bắt đầu một phiên mới.

Hãy nhớ lại từ bài viết Nhập một phiên, trong quá trình thiết lập, tôi đã thêm một trình xử lý sự kiện onend.

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);
  // More setup…
}

Bên trong trình xử lý sự kiện, hãy khôi phục trạng thái của ứng dụng trước khi người dùng bước vào một phiên hoạt động.

function onSessionEnded(event) {
  xrSession = null;
  xrButton.textContent = 'Enter VR';
}

Kết luận

Tôi chưa giải thích mọi thứ bạn cần để viết ứng dụng Web XR hoặc AR. Hy vọng là tôi đã cung cấp đủ cho bạn đủ thông tin để tự mình bắt đầu hiểu được ý nghĩa của đoạn mã, cũng như đủ để bắt đầu thử nghiệm. Trong bài viết tiếp theo, tôi sẽ giải thích vòng lặp khung, là nơi vẽ nội dung lên màn hình.

Ảnh chụp của JESHOOTS.COM trên Unsplash