מציאות רבודה: ייתכן שכבר אתם יודעים אותה

אם כבר השתמשת ב-WebXR Device API, עברת את רוב הדרך שם.

Joe Medley
Joe Medley

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

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

למידע על בדיקת היטים, קראו את המאמר הנלווה מיקום אובייקטים וירטואליים בתצוגות מציאות. הקוד במאמר הזה מבוסס על הטעימה של התכונה Immersive AR Session (הדגמה מקור) מ-WebXR Device API של Immersive Web Work Group.

לפני שמתחילים להתנסות בקוד, כדאי להשתמש בדוגמה לסשנים של AR Immersive AR לפחות פעם אחת. נדרש טלפון Android מודרני עם Chrome 81 ואילך.

איך הוא שימושי?

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

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

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

בקשת פגישה

הבקשה לפגישה דומה מאוד לבקשה שראית בעבר. קודם כול, מבררים אם סוג הסשן הרצוי זמין במכשיר הנוכחי, באמצעות xr.isSessionSupported(). במקום לבקש 'immersive-vr' כמו קודם, צריך לבקש 'immersive-ar'.

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

כמו קודם, פעולה זו מפעילה לחצן 'Enter AR'. כשהמשתמש לוחץ עליו, מבוצע קריאה ל-xr.requestSession() ומעביר גם את 'immersive-ar'.

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

נכס נוחות

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

כניסה לסשן

כדי לזכור איך נראה המאמר הקודם onSessionStarted():

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

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

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

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

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

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

  if (session.isImmersive) {
    removeBackground();
  }

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

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

  refSpaceType = xrSession.isImmersive ? 'local' : 'viewer';
  xrSession.requestReferenceSpace(refSpaceType).then((refSpace) => {
    xrSession.requestAnimationFrame(onXRFrame);
  });

}

הפניות למרחבים משותפים

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

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

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

בכל מרחבי ההפניה, קואורדינטת ה-X מבטאת שמאלה וימינה, ה-Y מבטאת למעלה ולמטה ו-Z מבטאת קדימה ואחורה. הערכים החיוביים הם ימין, למעלה ואחורה, בהתאמה.

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

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

  if (session.isImmersive) {
    removeBackground();
  }

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

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

  refSpaceType = xrSession.isImmersive ? 'local' : 'viewer';
  xrSession.requestReferenceSpace(refSpaceType).then((refSpace) => {
    xrSession.requestAnimationFrame(onXRFrame);
  });
}

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

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

viewer - משמש לעתים קרובות יותר לתוכן שמוצג בתוך הדף, האזור הזה עוקב אחרי מכשיר הצפייה. כשמעבירים אותו ל-getViewerPose, הוא לא מספק מעקב, ולכן הוא תמיד מדווח על תנוחה במקור, אלא אם האפליקציה משנה אותה באמצעות XRReferenceSpace.getOffsetReferenceSpace(). בדוגמה הזו נעשה שימוש כדי לאפשר תזוזה מבוססת מגע של המצלמה.

הפעלת לולאת מסגרת

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

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  let xrViewerPose = xrFrame.getViewerPose(refSpaceType);
  if (xrViewerPose) {
    // Render based on the pose.
  }
}

סיכום

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

תמונה מאת David Grandmougin ב-UnFlood