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

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

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

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

עיבוד בשני שלבים

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

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

כדי להשתמש ב-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, שמדגים דרכים שונות לגשת לנתוני עומק.