בדף הזה נסביר איך יוצרים אפליקציית 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>
אתחול של three.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);
הגדרת עיבוד באמצעות three.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()
כדי לקבל את תנוחת הצופה ביחס למרחב הקואורדינטות המקומי.
המידע הזה משמש לעדכון המצלמה בסצנה, ומשנה את אופן הצפייה של המשתמש בעולם הווירטואלי לפני שהמעבד מצייר את הסצנה באמצעות המצלמה המעודכנת.
מוסיפים את הקוד הזה לתחתית הפונקציה 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>
של המסמך, מוסיפים את 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>
טעינת מודלים של 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()
.
המקור של קרן האור שמשמש לבדיקת ההיט הוא מרחב העזר 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 יבין את הסביבה, כוורת הראייה אמורה להופיע על משטחים בעולם האמיתי. מקישים על המסך כדי להציב חמנית שאפשר לראות מכל הכיוונים.