تساعد واجهة Depth API كاميرا الجهاز على فهم حجم وشكل العناصر الحقيقية في المشهد. فهو يستخدم الكاميرا لإنشاء صور بعمق أو خرائط العمق، مما يضيف طبقة من الواقع المعزّز إلى تطبيقاتك. يمكنك استخدام المعلومات التي تقدّمها صورة العمق لعرض العناصر الافتراضية بدقة أمام أجسام في العالم الحقيقي أو خلفها، ما يوفّر تجربة مستخدم غامرة وواقعية.
يتم احتساب معلومات العمق من الحركة، وقد يتم دمجها مع معلومات من جهاز استشعار عمق الجهاز، مثل أداة استشعار مدة الرحلة (ToF)، في حال توفّرها. لا يحتاج الجهاز إلى أداة استشعار ToF ليتوافق مع Depth API.
المتطلبات الأساسية
احرص على فهم مفاهيم الواقع المعزّز الأساسية. وكيفية ضبط جلسة ARCore قبل المتابعة.
حظر الوصول إلى الأجهزة المتوافقة مع ميزة Depath
إذا كان تطبيقك يتطلب دعم واجهة برمجة التطبيقات Depth API، إما لأن جزءًا أساسيًا من
تعتمد تجربة الواقع المعزّز على العمق، أو لأنه لا يوجد احتياطي سلس
من التطبيق تستخدم العمق، يمكنك اختيار تقييد توزيع
في متجر Google Play
الأجهزة التي تتوافق مع واجهة Depth API من خلال إضافة
السطر التالي إلى AndroidManifest.xml
، بالإضافة إلى
تم وصف AndroidManifest.xml
من التغييرات في
دليل تفعيل ARCore:
<uses-feature android:name="com.google.ar.core.depth" />
تفعيل العمق
في جلسة ARCore جديدة، تحقَّق مما إذا كان جهاز المستخدم يتوافق مع ميزة Depth. لا تتيح بعض الأجهزة المتوافقة مع ARCore استخدام واجهة Depth API بسبب قيود طاقة المعالجة. لحفظ الموارد، يتم إيقاف ميزة "العمق" تلقائيًا على ARCore. عليك تفعيل وضع العمق لكي يستخدم تطبيقك واجهة برمجة التطبيقات Depth API.
// Check whether the user's device supports the Depth API. int32_t is_depth_supported = 0; ArSession_isDepthModeSupported(ar_session, AR_DEPTH_MODE_AUTOMATIC, &is_depth_supported); // Configure the session for AR_DEPTH_MODE_AUTOMATIC. ArConfig* ar_config = NULL; ArConfig_create(ar_session, &ar_config); if (is_depth_supported) { ArConfig_setDepthMode(ar_session, ar_config, AR_DEPTH_MODE_AUTOMATIC); } CHECK(ArSession_configure(ar_session, ar_config) == AR_SUCCESS); ArConfig_destroy(ar_config);
الحصول على صور في العمق
يمكنك طلب ArFrame_acquireDepthImage16Bits()
للحصول على صورة العمق للإطار الحالي.
// Retrieve the depth image for the current frame, if available. ArImage* depth_image = NULL; // If a depth image is available, use it here. if (ArFrame_acquireDepthImage16Bits(ar_session, ar_frame, &depth_image) != AR_SUCCESS) { // No depth image received for this frame. // This normally means that depth data is not available yet. // Depth data will not be available if there are no tracked // feature points. This can happen when there is no motion, or when the // camera loses its ability to track objects in the surrounding // environment. return; }
توفّر الصورة المعروضة المخزن المؤقت للصور غير المنسّق، والذي يمكن تمريره إلى أداة تظليل الأجزاء لاستخدامها على وحدة معالجة الرسومات (GPU) لكل عنصر يتم عرضه. وهو موجّه باللغة AR_COORDINATES_2D_OPENGL_NORMALIZED_DEVICE_COORDINATES
ويمكن تغييره إلى AR_COORDINATES_2D_TEXTURE_NORMALIZED
عن طريق الاتصال بالرقم ArFrame_transformCoordinates2d()
. وبعد الوصول إلى صورة العمق من خلال أداة تظليل العناصر، يمكن الوصول إلى قياسات العمق هذه مباشرةً للتعامل مع التظليل.
فهم قيم العمق
تحديد النقطة A
على الهندسة الفعلية المرصودة ونقطة ثنائية الأبعاد a
تمثل النقطة نفسها في صورة العمق، وهي القيمة المحددة من خلال
تساوي واجهة برمجة التطبيقات في a
طول CA
المتوقع على المحور الرئيسي.
ويمكن أيضًا الإشارة إلى ذلك بالإحداثي z الذي يبلغ A
بالنسبة إلى الكاميرا.
الأصل C
. عند العمل باستخدام واجهة برمجة التطبيقات Depth API، من المهم معرفة أن
قيم العمق ليست طول الشعاع CA
نفسه، بل هي قيمة الإسقاط
منه.
استخدام أدوات التظليل
تحليل معلومات عمق الإطار الحالي
استخدِم دالتَي المساعدة DepthGetMillimeters()
وDepthGetVisibility()
في أداة تظليل الأجزاء للوصول إلى معلومات العمق لتحديد موضع الشاشة الحالي. بعد ذلك، استخدِم هذه المعلومات لإخفاء أجزاء من العنصر المعروض بشكل انتقائي.
// Use DepthGetMillimeters() and DepthGetVisibility() to parse the depth image
// for a given pixel, and compare against the depth of the object to render.
float DepthGetMillimeters(in sampler2D depth_texture, in vec2 depth_uv) {
// Depth is packed into the red and green components of its texture.
// The texture is a normalized format, storing millimeters.
vec3 packedDepthAndVisibility = texture2D(depth_texture, depth_uv).xyz;
return dot(packedDepthAndVisibility.xy, vec2(255.0, 256.0 * 255.0));
}
// Return a value representing how visible or occluded a pixel is relative
// to the depth image. The range is 0.0 (not visible) to 1.0 (completely
// visible).
float DepthGetVisibility(in sampler2D depth_texture, in vec2 depth_uv,
in float asset_depth_mm) {
float depth_mm = DepthGetMillimeters(depth_texture, depth_uv);
// Instead of a hard Z-buffer test, allow the asset to fade into the
// background along a 2 * kDepthTolerancePerMm * asset_depth_mm
// range centered on the background depth.
const float kDepthTolerancePerMm = 0.015f;
float visibility_occlusion = clamp(0.5 * (depth_mm - asset_depth_mm) /
(kDepthTolerancePerMm * asset_depth_mm) + 0.5, 0.0, 1.0);
// Use visibility_depth_near to set the minimum depth value. If using
// this value for occlusion, avoid setting it too close to zero. A depth value
// of zero signifies that there is no depth data to be found.
float visibility_depth_near = 1.0 - InverseLerp(
depth_mm, /*min_depth_mm=*/150.0, /*max_depth_mm=*/200.0);
// Use visibility_depth_far to set the maximum depth value. If the depth
// value is too high (outside the range specified by visibility_depth_far),
// the virtual object may get inaccurately occluded at further distances
// due to too much noise.
float visibility_depth_far = InverseLerp(
depth_mm, /*min_depth_mm=*/7500.0, /*max_depth_mm=*/8000.0);
const float kOcclusionAlpha = 0.0f;
float visibility =
max(max(visibility_occlusion, kOcclusionAlpha),
max(visibility_depth_near, visibility_depth_far));
return visibility;
}
إخفاء العناصر الافتراضية
يمكنك حجب العناصر الافتراضية في نص أداة تظليل الأجزاء. عدِّل قناة ألفا للكائن بناءً على عمقه. سيؤدي هذا إلى عرض كائن محجوب.
// Occlude virtual objects by updating the object’s alpha channel based on its depth.
const float kMetersToMillimeters = 1000.0;
float asset_depth_mm = v_ViewPosition.z * kMetersToMillimeters * -1.;
// Compute the texture coordinates to sample from the depth image.
vec2 depth_uvs = (u_DepthUvTransform * vec3(v_ScreenSpacePosition.xy, 1)).xy;
gl_FragColor.a *= DepthGetVisibility(u_DepthTexture, depth_uvs, asset_depth_mm);
يمكنك عرض التظليل باستخدام العرض بمرتين أو العرض لكل كائن أو تمرير الأمام. وتعتمد فعالية كل أسلوب على مدى تعقيد المشهد واعتبارات أخرى خاصة بالتطبيق.
عرض التمرير الأمامي لكل كائن
يحدد عرض التمرير الأمامي لكل كائن، ما إذا تم حجب كل وحدة بكسل من العنصر في أداة تظليل المواد. إذا لم تكن وحدات البكسل مرئية، يتم اقتصاصها، عادةً من خلال مزج ألفا، وبالتالي محاكاة التظليل على جهاز المستخدم.
العرض بمرّتين
مع العرض بتمريرتين، تعرض البطاقة الأولى كل المحتوى الافتراضي في مخزن وسيط مؤقتًا. تدمج الشريحة الثانية المشهد الافتراضي في الخلفية بناءً على الفرق بين العمق الواقعي والعمق الافتراضي للمشهد. لا يتطلب هذا الأسلوب عمل أداة تظليل إضافية خاصة بالكائن، وتنتج بشكل عام نتائج ذات مظهر موحد أكثر من طريقة التمرير الأمامي.
تحويل الإحداثيات بين صور الكاميرا وصور العمق
قد تختلف نسبة العرض إلى الارتفاع للصور التي تم الحصول عليها باستخدام ArFrame_acquireCameraImage()
مقارنةً بالصور في عمقها.
في هذه الحالة، تكون صورة العمق عبارة عن اقتصاص لصورة الكاميرا، ولا يكون لدى كل وحدات البكسل في صورة الكاميرا تقدير صالح للعمق.
للحصول على إحداثيات صورة عمقها في صورة وحدة المعالجة المركزية (CPU):
const float cpu_image_coordinates[] = {(float)cpu_coordinate_x, (float)cpu_coordinate_y}; float texture_coordinates[2]; ArFrame_transformCoordinates2d( ar_session, ar_frame, AR_COORDINATES_2D_IMAGE_PIXELS, 1, cpu_image_coordinates, AR_COORDINATES_2D_TEXTURE_NORMALIZED, texture_coordinates); if (texture_coordinates[0] < 0 || texture_coordinates[1] < 0) { // There are no valid depth coordinates, because the coordinates in the CPU // image are in the cropped area of the depth image. } else { int depth_image_width = 0; ArImage_getWidth(ar_session, depth_image, &depth_image_width); int depth_image_height = 0; ArImage_getHeight(ar_session, depth_image, &depth_image_height); int depth_coordinate_x = (int)(texture_coordinates[0] * depth_image_width); int depth_coordinate_y = (int)(texture_coordinates[1] * depth_image_height); }
للحصول على إحداثيات صورة وحدة المعالجة المركزية (CPU) لإحداثيات عمق الصورة:
int depth_image_width = 0; ArImage_getWidth(ar_session, depth_image, &depth_image_width); int depth_image_height = 0; ArImage_getHeight(ar_session, depth_image, &depth_image_height); float texture_coordinates[] = { (float)depth_coordinate_x / (float)depth_image_width, (float)depth_coordinate_y / (float)depth_image_height}; float cpu_image_coordinates[2]; ArFrame_transformCoordinates2d( ar_session, ar_frame, AR_COORDINATES_2D_TEXTURE_NORMALIZED, 1, texture_coordinates, AR_COORDINATES_2D_IMAGE_PIXELS, cpu_image_coordinates); int cpu_image_coordinate_x = (int)cpu_image_coordinates[0]; int cpu_image_coordinate_y = (int)cpu_image_coordinates[1];
اختبار العمق
تتيح اختبارات النتائج للمستخدمين وضع عناصر في موقع واقعي في المشهد. في السابق، كان لا يمكن إجراء اختبارات النتائج إلا على الطائرات المرصودة، وتقتصر المواقع الجغرافية على الأسطح الكبيرة المستوية، كما هو الحال في النتائج التي تعرضها أجهزة Android الخضراء. تستفيد اختبارات النتائج العمق من معلومات العمق المتجانسة والأولية لتقديم نتائج نتائج أكثر دقة، حتى على الأسطح غير المستوية والمنخفضة الزخرفة. ويظهر هذا الرمز مع أجهزة Android الحمراء.
لاستخدام اختبارات النتائج المستندة إلى العمق، اتصل بالرقم ArFrame_hitTest()
وابحث عن AR_TRACKABLE_DEPTH_POINT
في قائمة الإرجاع.
// Create a hit test using the Depth API. ArHitResultList* hit_result_list = NULL; ArHitResultList_create(ar_session, &hit_result_list); ArFrame_hitTest(ar_session, ar_frame, hit_x, hit_y, hit_result_list); int32_t hit_result_list_size = 0; ArHitResultList_getSize(ar_session, hit_result_list, &hit_result_list_size); ArHitResult* ar_hit_result = NULL; for (int32_t i = 0; i < hit_result_list_size; ++i) { ArHitResult* ar_hit = NULL; ArHitResult_create(ar_session, &ar_hit); ArHitResultList_getItem(ar_session, hit_result_list, i, ar_hit); ArTrackable* ar_trackable = NULL; ArHitResult_acquireTrackable(ar_session, ar_hit, &ar_trackable); ArTrackableType ar_trackable_type = AR_TRACKABLE_NOT_VALID; ArTrackable_getType(ar_session, ar_trackable, &ar_trackable_type); // Creates an anchor if a plane or an oriented point was hit. if (AR_TRACKABLE_DEPTH_POINT == ar_trackable_type) { // Do something with the hit result. } ArTrackable_release(ar_trackable); ArHitResult_destroy(ar_hit); } ArHitResultList_destroy(hit_result_list);
الخطوات التالية
- تفعيل استشعار دقة أكبر باستخدام Raw Depth API
- يمكنك الاطّلاع على معمل ARCore Depth Lab الذي يعرض طرقًا مختلفة للوصول إلى البيانات المتعمّقة.