Depth API, cihaz kamerasının sahnedeki gerçek nesnelerin boyutunu ve şeklini anlamasına yardımcı olur. Kamerayı kullanarak derinlik görüntüleri veya derinlik haritaları oluşturur, böylece uygulamalarınıza bir artırılmış gerçeklik (AR) katmanı ekler. Derinlik resminin sağladığı bilgileri kullanarak sanal nesnelerin gerçek dünyadaki nesnelerin önünde veya arkasında doğru şekilde görünmesini sağlayabilir, böylece sürükleyici ve gerçekçi bir kullanıcı deneyimi sağlayabilirsiniz.
Derinlik bilgileri harekete göre hesaplanır ve varsa uçuş süresi (ToF) sensörü gibi bir donanım derinlik sensöründen alınan bilgilerle birleştirilebilir. Cihazların Depth API'yi desteklemek için ToF sensörü olması gerekmez.
Ön koşullar
Temel artırılmış gerçeklik kavramlarını anladığınızdan emin olun ve devam etmeden önce ARCore oturumunun nasıl yapılandırılacağı hakkında daha fazla bilgi edinin.
Derinlik destekli cihazlara erişimi kısıtlayın
Uygulamanız,
Artırılmış gerçeklik (AR) deneyimi derinliğe dayalı olduğundan ya da
derinlik kullanan kısımları varsa bunların dağıtımını kısıtlamayı
Google Play Store'daki
Depth API'yi destekleyen cihazlara eklemek için
aşağıdaki satıra ek olarak, AndroidManifest.xml
AndroidManifest.xml
değişiklik
ARCore'u etkinleştirme rehberi:
<uses-feature android:name="com.google.ar.core.depth" />
Derinliği etkinleştir
Yeni bir ARCore oturumunda, kullanıcının cihazının Derinliği destekleyip desteklemediğini kontrol edin. İşlem gücü kısıtlamaları nedeniyle ARCore uyumlu cihazların hepsi Depth API'yi desteklemez. Kaynaklardan tasarruf etmek için ARCore'da derinlik varsayılan olarak devre dışıdır. Uygulamanızın Depth API'yi kullanması için derinlik modunu etkinleştirin.
// 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);
Derinlikli görüntüler edinme
Geçerli karenin derinlik görüntüsünü almak için ArFrame_acquireDepthImage16Bits()
numaralı telefonu arayın.
// 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; }
Döndürülen görüntü, ham resim arabelleğini sağlar. Bu arabellek, işlenecek her bir nesne için GPU'da kullanılmak üzere parça gölgelendiriciye geçirilebilir. AR_COORDINATES_2D_OPENGL_NORMALIZED_DEVICE_COORDINATES
ülkesindedir ve ArFrame_transformCoordinates2d()
çağrısı yapılarak AR_COORDINATES_2D_TEXTURE_NORMALIZED
olarak değiştirilebilir. Derinlik resmine nesne gölgelendirici içinde erişildiğinde kapama işleme için bu derinlik ölçümlerine doğrudan erişilebilir.
Derinlik değerlerini anlama
Gözlemlenen gerçek dünya geometrisinde A
noktası ve 2D a
noktası verilir.
derinlik resminde aynı noktayı temsil eden, Derinlik
a
konumundaki API, ana eksene tahmin edilen CA
uzunluğuna eşit.
Bu, kameraya göre A
işlevinin z koordinatı olarak da adlandırılabilir
kaynak: C
. Depth API ile çalışırken, makine öğreniminin
derinlik değerleri ışınının CA
uzunluğu değil, projeksiyon
öğreneceğiz.
Gölgelendiricilerde derinlik kullan
Geçerli kare için derinlik bilgilerini ayrıştır
Geçerli ekran konumunun derinlik bilgilerine erişmek için parça gölgelendiricide DepthGetMillimeters()
ve DepthGetVisibility()
yardımcı işlevlerini kullanın. Daha sonra, bu bilgileri kullanarak oluşturulan nesnenin bazı bölümlerini seçmeli olarak kapatın.
// 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;
}
Sanal nesneleri kaplama
Sanal nesneleri parça gölgelendiricinin gövdesinde tutun. Nesnenin alfa kanalını derinliğine göre günceller. Bu işlem, kapalı bir nesneyi oluşturur.
// 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);
Kapatmayı iki geçişli oluşturmayı veya nesne başına, ileri geçişli oluşturmayı kullanarak oluşturabilirsiniz. Her yaklaşımın verimliliği, sahnenin karmaşıklığına ve uygulamaya özgü diğer hususlara bağlıdır.
Nesne başına, ileriye dönük oluşturma
Nesne başına ileri geçiş oluşturma, malzeme gölgelendiricisinde nesnenin her pikselinin kapsanmasını belirler. Pikseller görünmüyorsa genellikle alfa karıştırma ile kırpılır ve böylece kullanıcının cihazında tıkanma simülasyonu yapılır.
İki geçişli oluşturma
İki geçişli oluşturmada, ilk geçiş, sanal içeriğin tamamını ara arabelleğe alır. İkinci geçişte, gerçek dünya derinliği ile sanal sahne derinliği arasındaki fark temel alınarak sanal sahneyi arka planla birleştiriyor. Bu yaklaşım, nesneye özel ek gölgelendirici çalışması gerektirmez ve genellikle ileri geçiş yönteminden daha tek tip görünümlü sonuçlar üretir.
Kamera görüntüleri ile derinlikli görüntüler arasındaki koordinatları dönüştürme
ArFrame_acquireCameraImage()
kullanılarak elde edilen görüntülerin en boy oranları, derinlikli resimlere göre farklı olabilir.
Bu durumda derinlik resmi, kamera görüntüsünün kesilmesidir ve kamera görüntüsündeki tüm piksellere karşılık gelen geçerli bir derinlik tahmini yoktur.
CPU görüntüsü üzerindeki koordinatlara ilişkin derinlik görüntü koordinatlarını almak için:
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); }
Derinlik resim koordinatları için CPU görüntü koordinatlarını almak üzere:
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];
Derinlik isabet testi
İsabet testleri, kullanıcıların nesneleri sahnedeki gerçek bir konuma yerleştirmesine olanak tanır. Daha önce, isabet testleri yalnızca algılanan uçaklarda yürütülebiliyor ve konumları yeşil Android'lerin gösterdiği sonuçlar gibi büyük ve düz yüzeylerle sınırlandırılıyordu. Derinlik vuruş testleri, düzlemsel olmayan ve düşük dokulu yüzeylerde bile daha doğru isabet sonuçları sağlamak için hem düzgün hem de ham derinlik bilgilerinden yararlanır. Bu simge, kırmızı Android ile gösteriliyor.
Derinlik etkin isabet testlerini kullanmak için ArFrame_hitTest()
yöntemini çağırın ve dönüş listesinde AR_TRACKABLE_DEPTH_POINT
olup olmadığını kontrol edin.
// 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);
Sırada ne var?
- Raw Depth API ile daha doğru algılama sağlayın.
- Derinlik verilerine erişmenin farklı yollarını gösteren ARCore Depth Lab'e göz atın.