יצירת פעילות AR סוחפת באמצעות WebXR

בדף הזה מוסבר איך ליצור אפליקציית AR פשוטה וסוחפת באמצעות WebXR.

כדי להתחיל, נדרשת סביבת פיתוח תואמת ל-WebXR.

יצירת דף HTML

כדי להתחיל סשן ב-WebXR, נדרשת אינטראקציה עם המשתמש. יש ליצור לחצן שמתקשר אל activateXR(). לאחר טעינת הדף, המשתמש יוכל להשתמש בלחצן הזה כדי להתחיל את חוויית ה-AR.

יוצרים קובץ חדש בשם index.html ומוסיפים לו את קוד ה-HTML הבא:

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

אתחול שלושה.js

לא יקרה הרבה כשלוחצים על הלחצן 'התחלה'. כדי להגדיר סביבה בתלת-ממד, אפשר להשתמש בספריית עיבוד להצגת סצנה.

בדוגמה הזו נשתמש ב-three.js, ספריית עיבוד תלת-ממד של JavaScript שמספקת מעבד WebGL. Three.js מטפל בעיבוד, במצלמות ובגרפים של סצנות כדי להקל על הצגת תוכן בתלת-ממד באינטרנט.

יצירת סצנה

בדרך כלל, המודל של סביבה תלת-ממדית מתואר כסצנה. יוצרים רכיב THREE.Scene שמכיל רכיבי AR. הקוד הבא מאפשר לכם לראות תיבה צבעונית לא מוארת ב-AR.

מוסיפים את הקוד הבא בחלק התחתון של הפונקציה 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);

הגדרת רינדור באמצעות שלושה.js

כדי לצפות בסצנה הזו ב-AR, צריך כלי לעיבוד ומצלמה. הכלי לעיבוד משתמש ב-WebGL כדי לשרטט את הסצנה במסך. המצלמה מתארת את אזור התצוגה שממנו נראית הסצנה.

מוסיפים את הקוד הבא בחלק התחתון של הפונקציה 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;

יצירת XRSession

נקודת הכניסה אל WebXR היא דרך XRSystem.requestSession(). צריך להשתמש במצב immersive-ar כדי לאפשר הצגה של תוכן שעבר רינדור בסביבה בעולם האמיתי.

ב-XRReferenceSpace מתוארת מערכת הקואורדינטות שמשמשת לאובייקטים בעולם הווירטואלי. מצב 'local' מתאים בצורה הטובה ביותר לחוויית AR, עם מרחב הפניה שמקורו בסמוך לצופה ומעקב יציב.

כדי ליצור XRSession ו-XRReferenceSpace, יש להוסיף את הקוד הבא בחלק התחתון של הפונקציה 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');

עיבוד הסצנה

עכשיו אפשר לעבד את הסצנה. XRSession.requestAnimationFrame() מתזמנת קריאה חוזרת (callback) שמתבצעת כשהדפדפן מוכן לשרטט מסגרת.

במהלך הקריאה החוזרת (callback) של המסגרת של האנימציה, צריך לבצע קריאה ל-XRFrame.getViewerPose() כדי למצוא את תנוחת הצופה ביחס לשטח הקואורדינטות המקומי. עדכון זה משמש לעדכון המצלמה במיקום ולשינוי האופן שבו המשתמש צופה בעולם הווירטואלי לפני שה-Renderer מצייר את הסצנה באמצעות המצלמה המעודכנת.

מוסיפים את הקוד הבא בחלק התחתון של הפונקציה 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);

הרצת Hello WebXR

עוברים לקובץ WebXR במכשיר. אמורה להופיע קובייה צבעונית מכל הצדדים.

הוספת בדיקת היט

אחת הדרכים הנפוצות לאינטראקציה עם עולם ה-AR היא באמצעות בדיקת היט, שמוצאת צומת בין קרניים לבין גיאומטריה בעולם האמיתי. ב-Hello WebXR, עליך להציב חמנייה בעולם הווירטואלי באמצעות בדיקה של חמנייה.

הסרה של קוביית ההדגמה

מסירים את הקובייה הלא מוארת ומחליפים אותה בסצנה שכוללת תאורה:

const scene = new THREE.Scene();

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

שימוש בתכונה hit-test

כדי לאתחל את הפונקציונליות של בדיקת ההיט, צריך לבקש סשן עם התכונה hit-test. מחפשים את הקטע הקודם של requestSession() ומוסיפים לו hit-test:

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

הוספת טוען מודלים

בשלב הזה, הסצנה מכילה רק קובייה צבעונית. כדי שהחוויה תהיה מעניינת יותר, תוכלו להוסיף טוען מודלים שמאפשר לטעון דגמי GLTF.

בתג <head> של המסמך, מוסיפים שלושת.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>

טעינת מודלים של GLTF

השתמש בטוען הדגם מהשלב הקודם כדי לטעון רשת מיקוד וחמנייה מהאינטרנט.

מוסיפים את הקוד הזה מעל 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) => {

יצירת מקור לבדיקת היטים

כדי לחשב הצטלבויות עם אובייקטים בעולם האמיתי, צריך ליצור XRHitTestSource באמצעות XRSession.requestHitTestSource(). ב-ray שמשמשת לבדיקת ההיט מוגדר מרחב ההפניות viewer בתור המקור, כלומר שבדיקת ההיט מתבצעת מהמרכז של אזור התצוגה.

כדי ליצור מקור לבדיקת היט, צריך להוסיף את הקוד הבא אחרי שיוצרים את המרחב המשותף של 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 });

משרטטים רשת מיקוד

כדי להבהיר היכן תוצב החמנייה, הוסיפו רשת מיקוד לסצנה. נראה שרשת זו נצמדת למשטחים בעולם האמיתי, ומציינות את המיקום שבו תעוגל החמנייה.

XRFrame.getHitTestResults מחזירה מערך של XRHitTestResult וחושפת צמתים עם גיאומטריה מהעולם האמיתי. השתמש בצמתים אלה כדי למקם את רשת המיקוד בכל מסגרת.

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

הוספת אינטראקציות בהקשה

הפרמטר XRSession מקבל אירועים מסוג select כשהמשתמש משלים פעולה ראשית. בסשן AR, הפעולה הזו תואמת להקשה על המסך.

אפשר לגרום לחמנייה חדשה להופיע כשהמשתמש מקיש על המסך על ידי הוספת הקוד הבא במהלך האתחול:

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

בדיקת ההיט

צריך להשתמש במכשיר הנייד כדי לנווט לדף. לאחר ש-WebXR מבינה את הסביבה, הרשת צריכה להופיע על פני משטחים בעולם האמיתי. מקישים על המסך כדי למקם חמנייה. אפשר לראות אותה מכל הצדדים.

השלבים הבאים