המציאות הווירטואלית מגיעה לאינטרנט

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

Joe Medley
Joe Medley

חוויות סוחפות הגיעו לאינטרנט ב-Chrome 79. ‫WebXR Device API מביא איתו מציאות מדומה, ותמיכה במציאות רבודה מגיעה ב-Chrome 81. בזמן שעדכון ל-GamePad API מרחיב את השימוש המתקדם באמצעי הבקרה ל-VR. בקרוב תהיה תמיכה במפרטים האלה בדפדפנים אחרים, כולל Firefox Reality, ‏ Oculus Browser, ‏ Edge ו-Helio של Magic Leap, ועוד.

המאמר הזה הוא הראשון בסדרה על האינטרנט הסוחף. בחלק הזה נסביר איך להגדיר אפליקציית WebXR בסיסית, ואיך להיכנס לסשן XR ולצאת ממנו. במאמרים הבאים נסביר על לולאת הפריימים (החלק הכי חשוב בחוויית WebXR), על הפרטים הספציפיים של מציאות רבודה ועל WebXR Hit Test API, שמאפשר לזהות משטחים בפעילות AR. אלא אם צוין אחרת, כל מה שמופיע במאמר הזה ובמאמרים הבאים רלוונטי באותה מידה גם ל-AR וגם ל-VR.

מהו האינטרנט המרחבי?

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

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

דוגמאות לחוויות סוחפות:

  • משחקים
  • סרטוני וידאו ב-360 מעלות
  • סרטונים מסורתיים בדו-ממד (או בתלת-ממד) שמוצגים בסביבה סוחפת
  • קניית בית
  • צפייה במוצרים בבית לפני שקונים אותם
  • אומנות סוחפת
  • משהו מגניב שאף אחד עוד לא חשב עליו

מושגים ושימוש

אני אסביר כמה דברים בסיסיים על השימוש ב-WebXR Device API. אם אתם צריכים מידע מפורט יותר ממה שסיפקתי, אתם יכולים לעיין בדוגמאות ל-WebXR של קבוצת העבודה Immersive Web או בחומרי העיון המתעדכנים של MDN. אם אתם מכירים גרסאות מוקדמות של WebXR Device API, כדאי לעיין בכל החומר הזה. בוצעו שינויים.

הקוד במאמר הזה מבוסס על דוגמה בסיסית של קבוצת העבודה Immersive Web (הדגמה, מקור), אבל הוא ערוך לשם הבהרה ופשטות.

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

בקשה להפעלה

כדי להיכנס לסשן XR, נדרשת תנועת משתמש. כדי לקבל את הנתונים האלה, משתמשים בזיהוי תכונות כדי לבדוק את XRSystem (באמצעות navigator.xr) ומבצעים קריאה אל XRSystem.isSessionSupported(). חשוב לדעת שבגרסאות 79 ו-80 של Chrome, האובייקט XRSystem נקרא XR.

בדוגמה שלמטה, ציינתי שאני רוצה סשן מציאות מדומה עם 'immersive-vr' סוג הסשן. סוגי הסשנים האחרים הם 'immersive-ar' ו-'inline'. סשן מוטבע משמש להצגת תוכן בתוך HTML, והוא מיועד בעיקר לתוכן שיווקי. הדוגמה Immersive AR Session מדגימה את זה. אסביר את זה במאמר אחר.

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

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

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

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

שימו לב להיררכיית האובייקטים בקוד הזה. הוא עובר מ-navigator ל-xr למופע XRSession. בגרסאות מוקדמות של ה-API, סקריפט היה צריך לבקש מכשיר לפני בקשת סשן. עכשיו, המכשיר נרכש באופן מרומז.

הזנת סשן

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

אצטרך גם רכיב <canvas> כדי לצייר את הסצנה. הוא צריך להיות WebGLRenderingContext או WebGL2RenderingContext שתואמים ל-XR. כל הציורים מתבצעים באמצעותם או באמצעות מסגרת מבוססת WebGL כמו Three.js.

עכשיו שיש לי מקום לצייר, אני צריך מקור תוכן שאוכל לצייר עליו. לשם כך, אני יוצר מופע של XRWebGLLayer. אני משייך אותו לקנבס באמצעות הקריאה XRSession.updateRenderState().

אחרי שנכנסים לסשן, צריך דרך לקבוע איפה הדברים נמצאים במציאות מדומה. אצטרך מרחב להשוואה. 'local-floor' מרחב ייחוס הוא מרחב שבו נקודת המוצא ממוקמת ליד הצופה, ציר ה-Y הוא 0 ברמת הרצפה והוא לא צפוי לזוז. יש סוגים אחרים של מרחבי הפניה, אבל זה נושא מורכב יותר מכדי שאוכל להסביר עליו כאן. אני שומר את מרחב ההפניה במשתנה כי אצטרך אותו כשאצייר על המסך.

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

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

הפעלת לולאה של פריימים

לולאת הפריימים היא לולאה אינסופית שנשלטת על ידי סוכן משתמש, שבה התוכן מצויר שוב ושוב על המסך. התוכן מוצג בבלוקים נפרדים שנקראים פריימים. רצף הפריימים יוצר אשליה של תנועה. באפליקציות VR, קצב הפריימים לשנייה יכול להיות בין 60 ל-144. ‫AR ב-Android פועל במהירות של 30 פריימים לשנייה. הקוד לא צריך להניח קצב פריימים מסוים.

התהליך הבסיסי של לולאת הפריימים הוא:

  1. התקשרו אל XRSession.requestAnimationFrame(). בתגובה, סוכן המשתמש מפעיל את XRFrameRequestCallback, שמוגדר על ידכם.
  2. בתוך פונקציית הקריאה החוזרת:
    1. צריך להתקשר שוב אל XRSession.requestAnimationFrame().
    2. קבלת תנוחת הצופה.
    3. העברת ('קישור') WebGLFramebuffer מ-XRWebGLLayer אל WebGLRenderingContext.
    4. מבצעים איטרציה על כל אובייקט XRView, מאחזרים את XRViewport מ-XRWebGLLayer ומעבירים אותו אל WebGLRenderingContext.
    5. מציירים משהו ב-framebuffer.

בהמשך המאמר הזה נתאר את שלב 1 וחלק משלב 2, הגדרה והפעלה של XRFrameRequestCallback. הפריטים הנותרים בשלב 2 מוסברים בחלק ב'.

ה-XRFrameRequestCallback

אתם מגדירים את XRFrameRequestCallback. היא מקבלת שני פרמטרים: DOMHighResTimeStamp ומופע של XRFrame. אובייקט XRFrame מספק את המידע שנדרש כדי להציג פריים אחד. הארגומנט DOMHighResTimeStamp שמור לשימוש עתידי.

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

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

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

סיום הסשן

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

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

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

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

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

סיכום

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