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

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

Joe Medley
Joe Medley

חוויות immersive הגיעו לאינטרנט בגרסה 79 של Chrome. 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.

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

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

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

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

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

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

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

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

שליחת בקשה לפגישה

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

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

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

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, סקריפט היה צריך לבקש מכשיר לפני ששלח בקשה לסשן. עכשיו המכשיר נרכש באופן משתמע.

כניסה לסשן

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

אצטרך גם רכיב <canvas> כדי לצייר את הסצנה. הוא צריך להיות WebGLRenderingContext או WebGL2RenderingContext תואם-XR. כל השרטוט מתבצע באמצעותם או באמצעות framework מבוססת-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. התכונה 'מציאות מדומה ל-Android' פועלת במהירות של 30 פריימים לשנייה. הקוד לא צריך להניח שום קצב פריימים ספציפי.

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

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

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

תמונה של JESHOOTS.COM ב-Unsplash