שימוש ב'עומק' באפליקציית AR Foundation ל-Android

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

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

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

חשוב לוודא שאתם מבינים את המושגים הבסיסיים של AR ואיך להגדיר סשן ARCore לפני שממשיכים.

הגדרת האפליקציה ל-Depth Required או ל-Depth Optional (Android בלבד)

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

הגדרת האפליקציה כ-Depth Required

נווט אל Edit > Project Settings > XR Plug-in Management > ARCore.

כברירת המחדל, Depth מוגדר כ-Required.

הגדרת האפליקציה כ-Depth Optional

  1. נווט אל Edit > Project Settings > XR Plug-in Management > ARCore.

  2. בתפריט הנפתח Depth, בוחרים באפשרות Optional כדי להגדיר את תכונת העומק כאופציונלית.

הפעלת העומק

כדי לחסוך במשאבים, ARCore לא מפעיל את Depth API כברירת מחדל. כדי לקחת את היתרון של העומק במכשירים נתמכים, עליך להוסיף באופן ידני את AROcclusionManager רכיב לאובייקט המשחק של מצלמת AR עם Camera רכיב ARCameraBackground. צפייה הסתרה אוטומטית במסמכי התיעוד של Unity לקבלת מידע נוסף.

בסשן ARCore חדש, צריך לבדוק אם המכשיר של המשתמש תומך בעומק וב-Depth API, באופן הבא:

// Reference to AROcclusionManager that should be added to the AR Camera
// game object that contains the Camera and ARCameraBackground components.
var occlusionManager = …

// Check whether the user's device supports the Depth API.
if (occlusionManager.descriptor?.supportsEnvironmentDepthImage)
{
    // If depth mode is available on the user's device, perform
    // the steps you want here.
}

איתור תמונות עומק

אפשר לקבל את תמונת העומק העדכנית ביותר של הסביבה AROcclusionManager

// Reference to AROcclusionManager that should be added to the AR Camera
// game object that contains the Camera and ARCameraBackground components.
var occlusionManager = …

if (occlusionManager.TryAcquireEnvironmentDepthCpuImage(out XRCpuImage image))
{
    using (image)
    {
        // Use the texture.
    }
}

אפשר להמיר את התמונה הגולמית של המעבד (CPU) לRawImage לקבלת גמישות רבה יותר. דוגמה לאופן שבו עושים את זה נמצאת בדוגמאות ARFoundation של Unity.

הסבר על ערכי עומק

נקודה נתון A על הגיאומטריה שנמדדה בעולם האמיתי ונקודה דו-ממדית a שמייצג את אותה נקודה בתמונת העומק, הערך שניתן בשדה העומק API ב-a שווה לאורך של CA הצפוי לציר הראשי. אפשר להתייחס אליו גם כקואורדינטת z של A ביחס למצלמה מקור C. כשעובדים עם Depth API, חשוב להבין ערכי העומק הם לא האורך של הקרן CA עצמה, אלא של ההיטל מתוכו.

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

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

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

עיבוד מעבר לאובייקט, העברה קדימה

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

רינדור בשני מעברים

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

חילוץ מרחק מתמונת עומק

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

Texture2D _depthTexture;
short[] _depthArray;

void UpdateEnvironmentDepthImage()
{
  if (_occlusionManager &&
        _occlusionManager.TryAcquireEnvironmentDepthCpuImage(out XRCpuImage image))
    {
        using (image)
        {
            UpdateRawImage(ref _depthTexture, image, TextureFormat.R16);
            _depthWidth = image.width;
            _depthHeight = image.height;
        }
    }
  var byteBuffer = _depthTexture.GetRawTextureData();
  Buffer.BlockCopy(byteBuffer, 0, _depthArray, 0, byteBuffer.Length);
}

// Obtain the depth value in meters at a normalized screen point.
public static float GetDepthFromUV(Vector2 uv, short[] depthArray)
{
    int depthX = (int)(uv.x * (DepthWidth - 1));
    int depthY = (int)(uv.y * (DepthHeight - 1));

    return GetDepthFromXY(depthX, depthY, depthArray);
}

// Obtain the depth value in meters at the specified x, y location.
public static float GetDepthFromXY(int x, int y, short[] depthArray)
{
    if (!Initialized)
    {
        return InvalidDepthValue;
    }

    if (x >= DepthWidth || x < 0 || y >= DepthHeight || y < 0)
    {
        return InvalidDepthValue;
    }

    var depthIndex = (y * DepthWidth) + x;
    var depthInShort = depthArray[depthIndex];
    var depthInMeters = depthInShort * MillimeterToMeter;
    return depthInMeters;
}

מה השלב הבא?

  • הפעלת חישה מדויקת יותר באמצעות Raw Depth API
  • כדאי לנסות את ARCore Depth Lab, שמדגים דרכים שונות לגשת לנתוני עומק.