Depth API עוזר למצלמה של המכשיר להבין את הגודל והצורה של האובייקטים האמיתיים בסצנה. הוא משתמש במצלמה כדי ליצור תמונות עומק או מפות עומק, וכך להוסיף לאפליקציות שכבת ריאליזם של AR. אפשר להשתמש במידע שמתקבל מתמונת עומק כדי להציג אובייקטים וירטואליים בצורה מדויקת מול או מאחורי אובייקטים בעולם האמיתי, וכך לספק חוויות משתמש immersive וריאליסטיות.
נתוני העומק מחושבים על סמך תנועה, ויכול להיות שיושלמו במידע מחישן עומק בחומרה, כמו חיישן זמן תעופה (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
נווט אל Edit > Project Settings > XR Plug-in Management > ARCore.
בתפריט הנפתח 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.
}
}
כדי לקבל גמישות רבה יותר, אפשר להמיר את קובץ האימג' הגולמי של המעבד ל-RawImage
. דוגמה לכך מופיעה בדוגמאות ל-ARFoundation של Unity.
הסבר על ערכי עומק
בהינתן נקודה A
בגיאומטריה הנצפית בעולם האמיתי ונקודה דו-ממדית a
שמייצגת את אותה נקודה בתמונה של העומק, הערך שמקבלים מ-Depth API ב-a
שווה לאורך של CA
שמוצג על הציר הראשי.
אפשר גם להתייחס לזה כקואורדינטת z של A
ביחס למקור המצלמה C
. כשעובדים עם Depth API, חשוב להבין שערכי העומק הם לא אורך קרן האור CA
עצמה, אלא הקרנה שלה.
חסימה של אובייקטים וירטואליים והצגה חזותית של נתוני עומק
בפוסט הזה בבלוג של Unity מופיעה סקירה כללית על נתוני עומק ועל האופן שבו אפשר להשתמש בהם כדי להסתיר תמונות וירטואליות. בנוסף, בדוגמאות של ARFoundation ב-Unity מוצגות תמונות וירטואליות עם חסימה והצגה חזותית של נתוני עומק.
אפשר לבצע רינדור של חסימות באמצעות רינדור בשני מעברים או רינדור קדימה לכל אובייקט. היעילות של כל גישה תלויה במורכבות הסצנה ובשיקולים אחרים שספציפיים לאפליקציה.
רינדור קדימה לכל אובייקט
עיבוד נתונים (render) קדימה לכל אובייקט קובע את החסימה של כל פיקסל באובייקט בשיחזור החומר שלו. אם הפיקסלים לא גלויים, הם נחתכים, בדרך כלל באמצעות מיזוג אלפא, וכך מתבצעת הדמיה של חסימת ראייה במכשיר של המשתמש.
רינדור בשני שלבים
כשמשתמשים ברינדור בשני מעברים, במעבר הראשון כל התוכן הווירטואלי מומר למאגר ביניים. במעבר השני, הסצינה הווירטואלית משולבת ברקע על סמך ההבדל בין העומק בעולם האמיתי לעומק של הסצינה הווירטואלית. הגישה הזו לא דורשת עבודה נוספת על שגיאות ספציפיות לאובייקטים, ובדרך כלל היא מניבה תוצאות אחידות יותר מאשר השיטה של מעבר קדימה.
חילוץ המרחק מתמונת עומק
כדי להשתמש ב-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.
- מומלץ לעיין בשיעור ה-Lab בנושא עומק ב-ARCore, שבו מוצגות דרכים שונות לגשת לנתוני עומק.