1. शुरू करने से पहले
ARCore, मोबाइल डिवाइसों पर ऑगमेंटेड रिएलिटी (एआर) ऐप्लिकेशन बनाने का एक प्लैटफ़ॉर्म है. अलग-अलग एपीआई का इस्तेमाल करके, ARCore किसी व्यक्ति के डिवाइस को उसके आस-पास के माहौल के बारे में जानकारी इकट्ठा करने और उसे पाने की सुविधा देता है. साथ ही, उस जानकारी के साथ इंटरैक्ट करने की सुविधा भी देता है.
इस कोडलैब में, आपको ARCore Depth API का इस्तेमाल करने वाला एक सामान्य एआर ऐप्लिकेशन बनाने की प्रोसेस के बारे में बताया जाएगा.
ज़रूरी शर्तें
यह कोडलैब, एआर के बुनियादी सिद्धांतों के बारे में जानकारी रखने वाले डेवलपर के लिए लिखा गया है.
आपको क्या बनाने को मिलेगा

आपको एक ऐसा ऐप्लिकेशन बनाना होगा जो हर फ़्रेम के लिए डेप्थ इमेज का इस्तेमाल करता हो. इससे सीन की ज्यामिति को विज़ुअलाइज़ किया जा सकेगा. साथ ही, रखी गई वर्चुअल ऐसेट पर ऑक्लूज़न किया जा सकेगा. आपको इन चरणों से गुज़रना होगा:
- फ़ोन पर Depth API की सुविधा काम करती है या नहीं, इसकी जांच की जा रही है
- हर फ़्रेम के लिए डेप्थ इमेज पाना
- डेप्थ की जानकारी को कई तरीकों से विज़ुअलाइज़ करना (ऊपर दिया गया ऐनिमेशन देखें)
- ऑक्लूज़न की सुविधा वाले ऐप्लिकेशन को ज़्यादा रियलिस्टिक बनाने के लिए डेप्थ का इस्तेमाल करना
- Depth API के साथ काम न करने वाले फ़ोन को आसानी से मैनेज करने का तरीका जानें
आपको इन चीज़ों की ज़रूरत होगी
हार्डवेयर की ज़रूरी शर्तें
- ARCore की सुविधा वाला डिवाइस, जो यूएसबी केबल के ज़रिए डेवलपमेंट मशीन से कनेक्ट हो. साथ ही, इस डिवाइस पर Depth API काम करना चाहिए. कृपया उन डिवाइसों की यह सूची देखें जिन पर यह सुविधा काम करती है. Depth API सिर्फ़ Android पर उपलब्ध है.
- इस डिवाइस के लिए, यूएसबी डीबग करने की सुविधा चालू करें.
सॉफ़्टवेयर से जुड़ी ज़रूरी शर्तें
- ARCore SDK 1.31.0 या इसके बाद का वर्शन.
- Android Studio (v3.0 या इसके बाद का वर्शन) वाली डेवलपमेंट मशीन.
2. ARCore और Depth API
Depth API, डेप्थ मैप (इन्हें डेप्थ इमेज भी कहा जाता है) बनाने के लिए, काम करने वाले डिवाइस के RGB कैमरे का इस्तेमाल करता है. डेप्थ मैप से मिली जानकारी का इस्तेमाल करके, वर्चुअल ऑब्जेक्ट को असल दुनिया की वस्तुओं के आगे या पीछे सटीक तरीके से दिखाया जा सकता है. इससे, लोगों को शानदार और असली जैसा अनुभव मिलता है.
ARCore Depth API, ARCore के सेशन से मिले हर फ़्रेम से मेल खाने वाली डेप्थ इमेज का ऐक्सेस देता है. हर पिक्सल, कैमरे से लेकर एनवायरमेंट तक की दूरी को मेज़र करता है. इससे आपके एआर ऐप्लिकेशन को ज़्यादा रियलिस्टिक बनाया जा सकता है.
डेप्थ एपीआई की एक अहम सुविधा ऑक्लूज़न है. यह डिजिटल ऑब्जेक्ट को असल दुनिया के ऑब्जेक्ट के हिसाब से सटीक तरीके से दिखाने की सुविधा देता है. इससे ऑब्जेक्ट ऐसे लगते हैं जैसे वे उपयोगकर्ता के आस-पास मौजूद हों.
इस कोडलैब में, आपको एआर की सुविधा वाला एक सामान्य ऐप्लिकेशन बनाने का तरीका बताया जाएगा. यह ऐप्लिकेशन, डेप्थ इमेज का इस्तेमाल करके, असली दुनिया की सतहों के पीछे मौजूद वर्चुअल ऑब्जेक्ट को छिपाता है. साथ ही, जगह की पहचान की गई ज्यामिति को दिखाता है.
3. सेट अप करें
डेवलपमेंट मशीन सेट अप करना
- यूएसबी केबल की मदद से, अपने ARCore डिवाइस को कंप्यूटर से कनेक्ट करें. पक्का करें कि आपका डिवाइस यूएसबी डीबगिंग की अनुमति देता हो.
- टर्मिनल खोलें और नीचे दिखाए गए तरीके से
adb devicesचलाएं:
adb devices List of devices attached <DEVICE_SERIAL_NUMBER> device
<DEVICE_SERIAL_NUMBER>, आपके डिवाइस के लिए यूनीक स्ट्रिंग होगा. जारी रखने से पहले, पक्का करें कि आपको सिर्फ़ एक डिवाइस दिखे.
Code को डाउनलोड और इंस्टॉल करें
- आपके पास डेटाबेस को क्लोन करने का विकल्प होता है:
git clone https://github.com/googlecodelabs/arcore-depth
इसके अलावा, ZIP फ़ाइल डाउनलोड करके उसे एक्सट्रैक्ट करें:
- Android Studio लॉन्च करें और Android Studio का कोई मौजूदा प्रोजेक्ट खोलें पर क्लिक करें.
- उस डायरेक्ट्री को ढूंढें जहां आपने ऊपर डाउनलोड की गई ZIP फ़ाइल को एक्सट्रैक्ट किया है. इसके बाद,
depth_codelab_io2020डायरेक्ट्री खोलें.
यह कई मॉड्यूल वाला एक Gradle प्रोजेक्ट है. अगर Android Studio में सबसे ऊपर बाईं ओर मौजूद प्रोजेक्ट पैन पहले से ही प्रोजेक्ट पैन में नहीं दिख रहा है, तो ड्रॉप-डाउन मेन्यू में जाकर प्रोजेक्ट पर क्लिक करें.
नतीजा कुछ ऐसा दिखना चाहिए:
| इस प्रोजेक्ट में ये मॉड्यूल शामिल हैं:
|
आपको part0_work मॉड्यूल में काम करना होगा. कोडलैब के हर हिस्से के लिए, पूरे समाधान भी दिए गए हैं. हर मॉड्यूल, एक ऐसा ऐप्लिकेशन होता है जिसे बनाया जा सकता है.
4. स्टार्टर ऐप्लिकेशन चलाना
- चलाएं > चलाएं... > ‘part0_work'. दिखने वाले डिप्लॉयमेंट टारगेट चुनें डायलॉग में, आपका डिवाइस कनेक्ट किए गए डिवाइस में दिखना चाहिए.
- अपना डिवाइस चुनें और ठीक है पर क्लिक करें. Android Studio, शुरुआती ऐप्लिकेशन बनाएगा और उसे आपके डिवाइस पर चलाएगा.
- ऐप्लिकेशन, कैमरे का ऐक्सेस मांगेगा. जारी रखने के लिए, अनुमति दें पर टैप करें.

| ऐप्लिकेशन को इस्तेमाल करने का तरीका
|
फ़िलहाल, आपका ऐप्लिकेशन बहुत सामान्य है और उसे रीयल-वर्ल्ड सीन ज्योमेट्री के बारे में ज़्यादा जानकारी नहीं है.
उदाहरण के लिए, अगर आपने Android की इमेज को कुर्सी के पीछे रखा है, तो रेंडरिंग में वह इमेज कुर्सी के आगे तैरती हुई दिखेगी. ऐसा इसलिए, क्योंकि ऐप्लिकेशन को यह पता नहीं है कि कुर्सी वहां मौजूद है और उसे Android की इमेज को छिपाना चाहिए.

इस समस्या को ठीक करने के लिए, हम Depth API का इस्तेमाल करेंगे. इससे इस ऐप्लिकेशन में ज़्यादा से ज़्यादा लोगों को बेहतर अनुभव मिलेगा और यह ज़्यादा असली लगेगा.
5. देखें कि Depth API काम करता है या नहीं (पहला हिस्सा)
ARCore Depth API, सिर्फ़ उन डिवाइसों पर काम करता है जिन पर ARCore काम करता है. डेप्थ इमेज का इस्तेमाल करके, किसी ऐप्लिकेशन में फ़ंक्शन को इंटिग्रेट करने से पहले, आपको यह पक्का करना होगा कि ऐप्लिकेशन, सुविधा वाले डिवाइस पर चल रहा हो.
DepthCodelabActivity में एक नया प्राइवेट मेंबर जोड़ें. यह एक फ़्लैग के तौर पर काम करता है. इससे यह पता चलता है कि मौजूदा डिवाइस में डेप्थ की सुविधा काम करती है या नहीं:
private boolean isDepthSupported;
हम इस फ़्लैग को onResume() फ़ंक्शन के अंदर से पॉप्युलेट कर सकते हैं. यहां एक नया सेशन बनाया जाता है.
मौजूदा कोड ढूंढें:
// Creates the ARCore session.
session = new Session(/* context= */ this);
कोड को यहां अपडेट करें:
// Creates the ARCore session.
session = new Session(/* context= */ this);
Config config = session.getConfig();
isDepthSupported = session.isDepthModeSupported(Config.DepthMode.AUTOMATIC);
if (isDepthSupported) {
config.setDepthMode(Config.DepthMode.AUTOMATIC);
} else {
config.setDepthMode(Config.DepthMode.DISABLED);
}
session.configure(config);
अब एआर सेशन को सही तरीके से कॉन्फ़िगर कर दिया गया है. साथ ही, आपके ऐप्लिकेशन को यह पता चल गया है कि वह डेप्थ पर आधारित सुविधाओं का इस्तेमाल कर सकता है या नहीं.
आपको उपयोगकर्ता को यह भी बताना चाहिए कि इस सेशन के लिए डेप्थ का इस्तेमाल किया गया है या नहीं.
स्नैकबार में एक और मैसेज जोड़ें. यह स्क्रीन पर सबसे नीचे दिखेगा:
// Add this line at the top of the file, with the other messages.
private static final String DEPTH_NOT_AVAILABLE_MESSAGE = "[Depth not supported on this device]";
onDrawFrame() में जाकर, इस मैसेज को अपनी ज़रूरत के हिसाब से दिखाया जा सकता है:
// Add this if-statement above messageSnackbarHelper.showMessage(this, messageToShow).
if (!isDepthSupported) {
messageToShow += "\n" + DEPTH_NOT_AVAILABLE_MESSAGE;
}
अगर आपका ऐप्लिकेशन ऐसे डिवाइस पर चलता है जिस पर डेप्थ की सुविधा काम नहीं करती है, तो अभी जोड़ा गया मैसेज सबसे नीचे दिखता है:

इसके बाद, ऐप्लिकेशन को अपडेट करके Depth API को कॉल किया जाएगा. साथ ही, हर फ़्रेम के लिए डेप्थ इमेज वापस पाई जाएंगी.
6. डेप्थ इमेज वापस पाना (दूसरा हिस्सा)
Depth API, डिवाइस के आस-पास के माहौल की 3D इमेज कैप्चर करता है. साथ ही, उस डेटा के साथ डेप्थ इमेज को आपके ऐप्लिकेशन पर भेजता है. डेप्थ इमेज में मौजूद हर पिक्सल, डिवाइस के कैमरे से लेकर उसके आस-पास के माहौल तक की दूरी को दिखाता है.
अब इन डेप्थ इमेज का इस्तेमाल करके, ऐप्लिकेशन में रेंडरिंग और विज़ुअलाइज़ेशन को बेहतर बनाया जा सकता है. पहला चरण, हर फ़्रेम के लिए डेप्थ इमेज को वापस पाना और उस टेक्सचर को बाइंड करना है, ताकि GPU उसका इस्तेमाल कर सके.
सबसे पहले, अपने प्रोजेक्ट में एक नई क्लास जोड़ें.DepthTextureHandler, दिए गए ARCore फ़्रेम के लिए डेप्थ इमेज को वापस पाने के लिए ज़िम्मेदार है.
यह फ़ाइल जोड़ें:

src/main/java/com/google/ar/core/codelab/depth/DepthTextureHandler.java
package com.google.ar.core.codelab.depth;
import static android.opengl.GLES20.GL_CLAMP_TO_EDGE;
import static android.opengl.GLES20.GL_TEXTURE_2D;
import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
import static android.opengl.GLES20.GL_TEXTURE_WRAP_S;
import static android.opengl.GLES20.GL_TEXTURE_WRAP_T;
import static android.opengl.GLES20.GL_UNSIGNED_BYTE;
import static android.opengl.GLES20.glBindTexture;
import static android.opengl.GLES20.glGenTextures;
import static android.opengl.GLES20.glTexImage2D;
import static android.opengl.GLES20.glTexParameteri;
import static android.opengl.GLES30.GL_LINEAR;
import static android.opengl.GLES30.GL_RG;
import static android.opengl.GLES30.GL_RG8;
import android.media.Image;
import com.google.ar.core.Frame;
import com.google.ar.core.exceptions.NotYetAvailableException;
/** Handle RG8 GPU texture containing a DEPTH16 depth image. */
public final class DepthTextureHandler {
private int depthTextureId = -1;
private int depthTextureWidth = -1;
private int depthTextureHeight = -1;
/**
* Creates and initializes the depth texture. This method needs to be called on a
* thread with a EGL context attached.
*/
public void createOnGlThread() {
int[] textureId = new int[1];
glGenTextures(1, textureId, 0);
depthTextureId = textureId[0];
glBindTexture(GL_TEXTURE_2D, depthTextureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
/**
* Updates the depth texture with the content from acquireDepthImage16Bits().
* This method needs to be called on a thread with an EGL context attached.
*/
public void update(final Frame frame) {
try {
Image depthImage = frame.acquireDepthImage16Bits();
depthTextureWidth = depthImage.getWidth();
depthTextureHeight = depthImage.getHeight();
glBindTexture(GL_TEXTURE_2D, depthTextureId);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RG8,
depthTextureWidth,
depthTextureHeight,
0,
GL_RG,
GL_UNSIGNED_BYTE,
depthImage.getPlanes()[0].getBuffer());
depthImage.close();
} catch (NotYetAvailableException e) {
// This normally means that depth data is not available yet.
}
}
public int getDepthTexture() {
return depthTextureId;
}
public int getDepthWidth() {
return depthTextureWidth;
}
public int getDepthHeight() {
return depthTextureHeight;
}
}
अब आपको इस क्लास का एक इंस्टेंस DepthCodelabActivity में जोड़ना होगा. इससे यह पक्का किया जा सकेगा कि आपके पास हर फ़्रेम के लिए डेप्थ इमेज की एक ऐसी कॉपी हो जिसे आसानी से ऐक्सेस किया जा सके.
DepthCodelabActivity.java में, हमारी नई क्लास का इंस्टेंस, प्राइवेट मेंबर वैरिएबल के तौर पर जोड़ें:
private final DepthTextureHandler depthTexture = new DepthTextureHandler();
इसके बाद, इस टेक्सचर को शुरू करने के लिए onSurfaceCreated() तरीके को अपडेट करें, ताकि इसका इस्तेमाल हमारे जीपीयू शेडर कर सकें:
// Put this at the top of the "try" block in onSurfaceCreated().
depthTexture.createOnGlThread();
आखिर में, आपको हर फ़्रेम में इस टेक्सचर को सबसे नई डेप्थ इमेज के साथ पॉप्युलेट करना होगा. इसके लिए, आपको session से फ़ेच किए गए सबसे नए फ़्रेम पर, ऊपर बनाया गया update() तरीका कॉल करना होगा.
इस ऐप्लिकेशन के लिए, डेप्थ सपोर्ट की सुविधा का इस्तेमाल करना ज़रूरी नहीं है. इसलिए, इस कॉल का इस्तेमाल सिर्फ़ तब करें, जब डेप्थ का इस्तेमाल किया जा रहा हो.
// Add this just after "frame" is created inside onDrawFrame().
if (isDepthSupported) {
depthTexture.update(frame);
}
अब आपके पास डेप्थ इमेज है, जो हर फ़्रेम के साथ अपडेट होती है. अब इसका इस्तेमाल आपके शेडर कर सकते हैं.
हालांकि, ऐप्लिकेशन के व्यवहार में अब तक कोई बदलाव नहीं हुआ है. अब अपने ऐप्लिकेशन को बेहतर बनाने के लिए, डेप्थ इमेज का इस्तेमाल करें.
7. डेप्थ इमेज रेंडर करना (तीसरा हिस्सा)
अब आपके पास डेप्थ इमेज है. इसलिए, आपको यह देखना होगा कि यह कैसी दिखती है. इस सेक्शन में, आपको ऐप्लिकेशन में एक बटन जोड़ना होगा. इससे हर फ़्रेम के लिए डेप्थ रेंडर की जा सकेगी.
नए शेडर जोड़ना
डेप्थ इमेज को कई तरीकों से देखा जा सकता है. नीचे दिए गए शेडर, कलर मैपिंग का आसान विज़ुअलाइज़ेशन उपलब्ध कराते हैं.
| नया .vert शेडर जोड़नाAndroid Studio में:
|
नई फ़ाइल में, यह कोड जोड़ें:
src/main/assets/shaders/background_show_depth_map.vert
attribute vec4 a_Position;
attribute vec2 a_TexCoord;
varying vec2 v_TexCoord;
void main() {
v_TexCoord = a_TexCoord;
gl_Position = a_Position;
}
ऊपर दिए गए चरणों को दोहराकर, उसी डायरेक्ट्री में फ़्रैगमेंट शेडर बनाएं और उसका नाम background_show_depth_map.frag रखें.
इस नई फ़ाइल में यह कोड जोड़ें:
src/main/assets/shaders/background_show_depth_map.frag
precision mediump float;
uniform sampler2D u_Depth;
varying vec2 v_TexCoord;
const highp float kMaxDepth = 20000.0; // In millimeters.
float GetDepthMillimeters(vec4 depth_pixel_value) {
return 255.0 * (depth_pixel_value.r + depth_pixel_value.g * 256.0);
}
// Returns an interpolated color in a 6 degree polynomial interpolation.
vec3 GetPolynomialColor(in float x,
in vec4 kRedVec4, in vec4 kGreenVec4, in vec4 kBlueVec4,
in vec2 kRedVec2, in vec2 kGreenVec2, in vec2 kBlueVec2) {
// Moves the color space a little bit to avoid pure red.
// Removes this line for more contrast.
x = clamp(x * 0.9 + 0.03, 0.0, 1.0);
vec4 v4 = vec4(1.0, x, x * x, x * x * x);
vec2 v2 = v4.zw * v4.z;
return vec3(
dot(v4, kRedVec4) + dot(v2, kRedVec2),
dot(v4, kGreenVec4) + dot(v2, kGreenVec2),
dot(v4, kBlueVec4) + dot(v2, kBlueVec2)
);
}
// Returns a smooth Percept colormap based upon the Turbo colormap.
vec3 PerceptColormap(in float x) {
const vec4 kRedVec4 = vec4(0.55305649, 3.00913185, -5.46192616, -11.11819092);
const vec4 kGreenVec4 = vec4(0.16207513, 0.17712472, 15.24091500, -36.50657960);
const vec4 kBlueVec4 = vec4(-0.05195877, 5.18000081, -30.94853351, 81.96403246);
const vec2 kRedVec2 = vec2(27.81927491, -14.87899417);
const vec2 kGreenVec2 = vec2(25.95549545, -5.02738237);
const vec2 kBlueVec2 = vec2(-86.53476570, 30.23299484);
const float kInvalidDepthThreshold = 0.01;
return step(kInvalidDepthThreshold, x) *
GetPolynomialColor(x, kRedVec4, kGreenVec4, kBlueVec4,
kRedVec2, kGreenVec2, kBlueVec2);
}
void main() {
vec4 packed_depth = texture2D(u_Depth, v_TexCoord.xy);
highp float depth_mm = GetDepthMillimeters(packed_depth);
highp float normalized_depth = depth_mm / kMaxDepth;
vec4 depth_color = vec4(PerceptColormap(normalized_depth), 1.0);
gl_FragColor = depth_color;
}
इसके बाद, BackgroundRenderer क्लास को अपडेट करें, ताकि src/main/java/com/google/ar/core/codelab/common/rendering/BackgroundRenderer.java में मौजूद इन नए शेडर का इस्तेमाल किया जा सके.
क्लास में सबसे ऊपर, शेडर के फ़ाइल पाथ जोड़ें:
// Add these under the other shader names at the top of the class.
private static final String DEPTH_VERTEX_SHADER_NAME = "shaders/background_show_depth_map.vert";
private static final String DEPTH_FRAGMENT_SHADER_NAME = "shaders/background_show_depth_map.frag";
BackgroundRenderer क्लास में ज़्यादा सदस्य वैरिएबल जोड़ें, क्योंकि यह दो शेडर चलाएगा:
// Add to the top of file with the rest of the member variables.
private int depthProgram;
private int depthTextureParam;
private int depthTextureId = -1;
private int depthQuadPositionParam;
private int depthQuadTexCoordParam;
इन फ़ील्ड में डेटा भरने के लिए, नया तरीका जोड़ें:
// Add this method below createOnGlThread().
public void createDepthShaders(Context context, int depthTextureId) throws IOException {
int vertexShader =
ShaderUtil.loadGLShader(
TAG, context, GLES20.GL_VERTEX_SHADER, DEPTH_VERTEX_SHADER_NAME);
int fragmentShader =
ShaderUtil.loadGLShader(
TAG, context, GLES20.GL_FRAGMENT_SHADER, DEPTH_FRAGMENT_SHADER_NAME);
depthProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(depthProgram, vertexShader);
GLES20.glAttachShader(depthProgram, fragmentShader);
GLES20.glLinkProgram(depthProgram);
GLES20.glUseProgram(depthProgram);
ShaderUtil.checkGLError(TAG, "Program creation");
depthTextureParam = GLES20.glGetUniformLocation(depthProgram, "u_Depth");
ShaderUtil.checkGLError(TAG, "Program parameters");
depthQuadPositionParam = GLES20.glGetAttribLocation(depthProgram, "a_Position");
depthQuadTexCoordParam = GLES20.glGetAttribLocation(depthProgram, "a_TexCoord");
this.depthTextureId = depthTextureId;
}
इस तरीके को जोड़ें. इसका इस्तेमाल हर फ़्रेम पर इन शेडर से ड्रॉ करने के लिए किया जाता है:
// Put this at the bottom of the file.
public void drawDepth(@NonNull Frame frame) {
if (frame.hasDisplayGeometryChanged()) {
frame.transformCoordinates2d(
Coordinates2d.OPENGL_NORMALIZED_DEVICE_COORDINATES,
quadCoords,
Coordinates2d.TEXTURE_NORMALIZED,
quadTexCoords);
}
if (frame.getTimestamp() == 0 || depthTextureId == -1) {
return;
}
// Ensure position is rewound before use.
quadTexCoords.position(0);
// No need to test or write depth, the screen quad has arbitrary depth, and is expected
// to be drawn first.
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
GLES20.glDepthMask(false);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, depthTextureId);
GLES20.glUseProgram(depthProgram);
GLES20.glUniform1i(depthTextureParam, 0);
// Set the vertex positions and texture coordinates.
GLES20.glVertexAttribPointer(
depthQuadPositionParam, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, quadCoords);
GLES20.glVertexAttribPointer(
depthQuadTexCoordParam, TEXCOORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, quadTexCoords);
// Draws the quad.
GLES20.glEnableVertexAttribArray(depthQuadPositionParam);
GLES20.glEnableVertexAttribArray(depthQuadTexCoordParam);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
GLES20.glDisableVertexAttribArray(depthQuadPositionParam);
GLES20.glDisableVertexAttribArray(depthQuadTexCoordParam);
// Restore the depth state for further drawing.
GLES20.glDepthMask(true);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
ShaderUtil.checkGLError(TAG, "BackgroundRendererDraw");
}
टॉगल बटन जोड़ना
अब आपके पास डेप्थ मैप रेंडर करने की सुविधा है, तो इसका इस्तेमाल करें! एक ऐसा बटन जोड़ें जो इस रेंडरिंग को चालू और बंद करता हो.
बटन का इस्तेमाल करने के लिए, DepthCodelabActivity फ़ाइल में सबसे ऊपर एक इंपोर्ट जोड़ें:
import android.widget.Button;
गहराई से रेंडर करने की सुविधा चालू है या नहीं, यह बताने के लिए क्लास को अपडेट करें. इसके लिए, एक बूलियन मेंबर जोड़ें. यह सुविधा डिफ़ॉल्ट रूप से बंद होती है:
private boolean showDepthMap = false;
इसके बाद, onCreate() मेथड के आखिर में, showDepthMap बूलियन को कंट्रोल करने वाला बटन जोड़ें:
final Button toggleDepthButton = (Button) findViewById(R.id.toggle_depth_button);
toggleDepthButton.setOnClickListener(
view -> {
if (isDepthSupported) {
showDepthMap = !showDepthMap;
toggleDepthButton.setText(showDepthMap ? R.string.hide_depth : R.string.show_depth);
} else {
showDepthMap = false;
toggleDepthButton.setText(R.string.depth_not_available);
}
});
res/values/strings.xml में ये स्ट्रिंग जोड़ें:
<string translatable="false" name="show_depth">Show Depth</string>
<string translatable="false" name="hide_depth">Hide Depth</string>
<string translatable="false" name="depth_not_available">Depth Not Available</string>
res/layout/activity_main.xml में, ऐप्लिकेशन लेआउट में सबसे नीचे यह बटन जोड़ें:
<Button
android:id="@+id/toggle_depth_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:gravity="center"
android:text="@string/show_depth"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"/>
अब यह बटन, बूलियन showDepthMap की वैल्यू को कंट्रोल करता है. इस फ़्लैग का इस्तेमाल करके यह कंट्रोल किया जा सकता है कि डेप्थ मैप रेंडर हो या नहीं.
DepthCodelabActivity में onDrawFrame() तरीके का इस्तेमाल करके, यह जानकारी जोड़ें:
// Add this snippet just under backgroundRenderer.draw(frame);
if (showDepthMap) {
backgroundRenderer.drawDepth(frame);
}
backgroundRenderer में यह लाइन जोड़कर, डेप्थ टेक्सचर को backgroundRenderer पर पास करें:onSurfaceCreated()
// Add to onSurfaceCreated() after backgroundRenderer.createonGlThread(/*context=*/ this);
backgroundRenderer.createDepthShaders(/*context=*/ this, depthTexture.getDepthTexture());
अब स्क्रीन पर सबसे ऊपर दाईं ओर मौजूद बटन को दबाकर, हर फ़्रेम की डेप्थ इमेज देखी जा सकती है.
|
| ||
डेप्थ एपीआई की सुविधा के बिना चल रहा है | डेप्थ एपीआई के साथ काम करने वाला | ||
[ज़रूरी नहीं] डेप्थ ऐनिमेशन
फ़िलहाल, ऐप्लिकेशन सीधे तौर पर डेप्थ मैप दिखाता है. लाल पिक्सल, आस-पास के इलाकों को दिखाते हैं. नीले पिक्सल, दूर की जगहों को दिखाते हैं.
|
|
डेप्थ की जानकारी देने के कई तरीके हैं. इस सेक्शन में, आपको शेडर में बदलाव करके, समय-समय पर डेप्थ को पल्स करना होगा. इसके लिए, शेडर में बदलाव करके, सिर्फ़ उन बैंड में डेप्थ दिखाएं जो बार-बार कैमरे से दूर जाते हैं.
background_show_depth_map.frag के सबसे ऊपर इन वैरिएबल को जोड़कर शुरुआत करें:
uniform float u_DepthRangeToRenderMm;
const float kDepthWidthToRenderMm = 350.0;
- इसके बाद, इन वैल्यू का इस्तेमाल करके यह फ़िल्टर करें कि शेडर के
main()फ़ंक्शन में, किन पिक्सल को डेप्थ वैल्यू के साथ कवर करना है:
// Add this line at the end of main().
gl_FragColor.a = clamp(1.0 - abs((depth_mm - u_DepthRangeToRenderMm) / kDepthWidthToRenderMm), 0.0, 1.0);
इसके बाद, इन शेडर पैरामीटर को बनाए रखने के लिए, BackgroundRenderer.java अपडेट करें. क्लास में सबसे ऊपर ये फ़ील्ड जोड़ें:
private static final float MAX_DEPTH_RANGE_TO_RENDER_MM = 20000.0f;
private float depthRangeToRenderMm = 0.0f;
private int depthRangeToRenderMmParam;
createDepthShaders() तरीके में, इन पैरामीटर को शेडर प्रोग्राम से मैच करने के लिए, यह कोड जोड़ें:
depthRangeToRenderMmParam = GLES20.glGetUniformLocation(depthProgram, "u_DepthRangeToRenderMm");
- आखिर में,
drawDepth()तरीके का इस्तेमाल करके, समय के साथ इस रेंज को कंट्रोल किया जा सकता है. नीचे दिया गया कोड जोड़ें. इससे हर बार फ़्रेम बनाने पर, यह रेंज बढ़ जाती है:
// Enables alpha blending.
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
// Updates range each time draw() is called.
depthRangeToRenderMm += 50.0f;
if (depthRangeToRenderMm > MAX_DEPTH_RANGE_TO_RENDER_MM) {
depthRangeToRenderMm = 0.0f;
}
// Passes latest value to the shader.
GLES20.glUniform1f(depthRangeToRenderMmParam, depthRangeToRenderMm);
अब डेप्थ को एक ऐनिमेटेड पल्स के तौर पर दिखाया जाता है, जो आपके सीन में दिखती है.

यहां दी गई वैल्यू में बदलाव करके, पल्स को धीमा, तेज़, चौड़ा, पतला वगैरह बनाया जा सकता है. इसके अलावा, गहराई की जानकारी दिखाने के लिए, शेडर में बदलाव करने के नए तरीके भी आज़माए जा सकते हैं!
8. ऑक्लूज़न के लिए Depth API का इस्तेमाल करना (चौथा हिस्सा)
अब आपको अपने ऐप्लिकेशन में ऑब्जेक्ट के छिपने की समस्या को ठीक करना होगा.
ऑक्लूज़न का मतलब है कि वर्चुअल ऑब्जेक्ट को पूरी तरह से रेंडर नहीं किया जा सकता, क्योंकि वर्चुअल ऑब्जेक्ट और कैमरे के बीच असली ऑब्जेक्ट मौजूद होते हैं. एआर के अनुभव को बेहतर बनाने के लिए, ऑक्लूज़न को मैनेज करना ज़रूरी है.
वर्चुअल ऑब्जेक्ट को रीयल टाइम में सही तरीके से रेंडर करने से, ऑगमेंटेड सीन ज़्यादा असली और भरोसेमंद लगता है. ज़्यादा उदाहरणों के लिए, कृपया Depth API की मदद से, असली और नकली चीज़ों को एक साथ दिखाने वाला हमारा वीडियो देखें.
इस सेक्शन में, आपको अपने ऐप्लिकेशन को अपडेट करना होगा. इससे, सिर्फ़ तब वर्चुअल ऑब्जेक्ट शामिल किए जा सकेंगे, जब डेप्थ की जानकारी उपलब्ध हो.
नए ऑब्जेक्ट शेडर जोड़ना
पिछले सेक्शन की तरह, डेप्थ की जानकारी देने के लिए नए शेडर जोड़े जाएंगे. इस बार, मौजूदा ऑब्जेक्ट शेडर कॉपी किए जा सकते हैं और ऑक्लूज़न की सुविधा जोड़ी जा सकती है.
ऑब्जेक्ट शेडर के दोनों वर्शन को बनाए रखना ज़रूरी है, ताकि आपका ऐप्लिकेशन यह तय कर सके कि डेप्थ की सुविधा को चालू करना है या नहीं.
src/main/assets/shaders डायरेक्ट्री में, object.vert और object.frag शेडर फ़ाइलों की कॉपी बनाएं.
|
|
occlusion_object.vert में, main() के ऊपर यह वैरिएबल जोड़ें:
varying vec3 v_ScreenSpacePosition;
इस वैरिएबल को main() के सबसे नीचे सेट करें:
v_ScreenSpacePosition = gl_Position.xyz / gl_Position.w;
फ़ाइल में सबसे ऊपर मौजूद main() के ऊपर, इन वैरिएबल को जोड़कर occlusion_object.frag को अपडेट करें:
varying vec3 v_ScreenSpacePosition;
uniform sampler2D u_Depth;
uniform mat3 u_UvTransform;
uniform float u_DepthTolerancePerMm;
uniform float u_OcclusionAlpha;
uniform float u_DepthAspectRatio;
- गहराई की जानकारी को आसानी से मैनेज करने के लिए, शेडर में
main()के ऊपर इन हेल्पर फ़ंक्शन को जोड़ें:
float GetDepthMillimeters(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(u_Depth, depth_uv).xyz;
return dot(packedDepthAndVisibility.xy, vec2(255.0, 256.0 * 255.0));
}
// Returns linear interpolation position of value between min and max bounds.
// E.g., InverseLerp(1100, 1000, 2000) returns 0.1.
float InverseLerp(in float value, in float min_bound, in float max_bound) {
return clamp((value - min_bound) / (max_bound - min_bound), 0.0, 1.0);
}
// Returns a value between 0.0 (not visible) and 1.0 (completely visible)
// Which represents how visible or occluded is the pixel in relation to the
// depth map.
float GetVisibility(in vec2 depth_uv, in float asset_depth_mm) {
float depth_mm = GetDepthMillimeters(depth_uv);
// Instead of a hard z-buffer test, allow the asset to fade into the
// background along a 2 * u_DepthTolerancePerMm * asset_depth_mm
// range centered on the background depth.
float visibility_occlusion = clamp(0.5 * (depth_mm - asset_depth_mm) /
(u_DepthTolerancePerMm * asset_depth_mm) + 0.5, 0.0, 1.0);
// Depth close to zero is most likely invalid, do not use it for occlusions.
float visibility_depth_near = 1.0 - InverseLerp(
depth_mm, /*min_depth_mm=*/150.0, /*max_depth_mm=*/200.0);
// Same for very high depth values.
float visibility_depth_far = InverseLerp(
depth_mm, /*min_depth_mm=*/17500.0, /*max_depth_mm=*/20000.0);
float visibility =
max(max(visibility_occlusion, u_OcclusionAlpha),
max(visibility_depth_near, visibility_depth_far));
return visibility;
}
अब occlusion_object.frag में main() को अपडेट करें, ताकि वह डेप्थ के बारे में जान सके और ऑक्लूज़न लागू कर सके. फ़ाइल के सबसे नीचे ये लाइनें जोड़ें:
const float kMToMm = 1000.0;
float asset_depth_mm = v_ViewPosition.z * kMToMm * -1.;
vec2 depth_uvs = (u_UvTransform * vec3(v_ScreenSpacePosition.xy, 1)).xy;
gl_FragColor.a *= GetVisibility(depth_uvs, asset_depth_mm);
अब आपके पास ऑब्जेक्ट शेडर का नया वर्शन है. इसलिए, रेंडरर कोड में बदलाव किया जा सकता है.
ऑब्जेक्ट के सामने आने की वजह से रेंडरिंग में होने वाली रुकावट
इसके बाद, src/main/java/com/google/ar/core/codelab/common/rendering/ObjectRenderer.java में मौजूद ObjectRenderer क्लास की कॉपी बनाएं.
ObjectRendererक्लास चुनें- राइट क्लिक करें > कॉपी करें
- rendering फ़ोल्डर चुनें
- राइट क्लिक करें > चिपकाएं

- क्लास का नाम बदलकर
OcclusionObjectRendererकर दो

बदला गया नाम अब उसी फ़ोल्डर में दिखना चाहिए:

नई बनाई गई OcclusionObjectRenderer.java फ़ाइल खोलें और फ़ाइल में सबसे ऊपर दिए गए शेडर पाथ बदलें:
private static final String VERTEX_SHADER_NAME = "shaders/occlusion_object.vert";
private static final String FRAGMENT_SHADER_NAME = "shaders/occlusion_object.frag";
- गहराई से जुड़ी इन सदस्य वैरिएबल को क्लास के सबसे ऊपर मौजूद अन्य वैरिएबल के साथ जोड़ें. इन वैरिएबल से, ओक्लूज़न बॉर्डर की शार्पनेस को अडजस्ट किया जा सकेगा.
// Shader location: depth texture
private int depthTextureUniform;
// Shader location: transform to depth uvs
private int depthUvTransformUniform;
// Shader location: depth tolerance property
private int depthToleranceUniform;
// Shader location: maximum transparency for the occluded part.
private int occlusionAlphaUniform;
private int depthAspectRatioUniform;
private float[] uvTransform = null;
private int depthTextureId;
क्लास में सबसे ऊपर, डिफ़ॉल्ट वैल्यू के साथ ये सदस्य वैरिएबल बनाएं:
// These values will be changed each frame based on the distance to the object.
private float depthAspectRatio = 0.0f;
private final float depthTolerancePerMm = 0.015f;
private final float occlusionsAlpha = 0.0f;
createOnGlThread() तरीके में, शेडर के लिए यूनिफ़ॉर्म पैरामीटर शुरू करें:
// Occlusions Uniforms. Add these lines before the first call to ShaderUtil.checkGLError
// inside the createOnGlThread() method.
depthTextureUniform = GLES20.glGetUniformLocation(program, "u_Depth");
depthUvTransformUniform = GLES20.glGetUniformLocation(program, "u_UvTransform");
depthToleranceUniform = GLES20.glGetUniformLocation(program, "u_DepthTolerancePerMm");
occlusionAlphaUniform = GLES20.glGetUniformLocation(program, "u_OcclusionAlpha");
depthAspectRatioUniform = GLES20.glGetUniformLocation(program, "u_DepthAspectRatio");
draw()तरीके को अपडेट करके, पक्का करें कि ये वैल्यू हर बार अपडेट की जाती हैं:
// Add after other GLES20.glUniform calls inside draw().
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, depthTextureId);
GLES20.glUniform1i(depthTextureUniform, 1);
GLES20.glUniformMatrix3fv(depthUvTransformUniform, 1, false, uvTransform, 0);
GLES20.glUniform1f(depthToleranceUniform, depthTolerancePerMm);
GLES20.glUniform1f(occlusionAlphaUniform, occlusionsAlpha);
GLES20.glUniform1f(depthAspectRatioUniform, depthAspectRatio);
रेंडरिंग में ब्लेंड-मोड चालू करने के लिए, draw() में ये लाइनें जोड़ें. इससे वर्चुअल ऑब्जेक्ट के ढके होने पर, उन पर पारदर्शिता लागू की जा सकेगी:
// Add these lines just below the code-block labeled "Enable vertex arrays"
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
// Add these lines just above the code-block labeled "Disable vertex arrays"
GLES20.glDisable(GLES20.GL_BLEND);
GLES20.glDepthMask(true);
- यहां दिए गए तरीके जोड़ें, ताकि
OcclusionObjectRendererको कॉल करने वाले लोग ज़्यादा जानकारी दे सकें:
// Add these methods at the bottom of the OcclusionObjectRenderer class.
public void setUvTransformMatrix(float[] transform) {
uvTransform = transform;
}
public void setDepthTexture(int textureId, int width, int height) {
depthTextureId = textureId;
depthAspectRatio = (float) width / (float) height;
}
ऑब्जेक्ट के सामने आने की वजह से बनने वाली छाया को कंट्रोल करना
अब आपके पास नया OcclusionObjectRenderer है. इसे अपने DepthCodelabActivity में जोड़ा जा सकता है. साथ ही, यह चुना जा सकता है कि ऑक्लूज़न रेंडरिंग का इस्तेमाल कब और कैसे करना है.
इस लॉजिक को चालू करने के लिए, गतिविधि में OcclusionObjectRenderer का एक इंस्टेंस जोड़ें, ताकि ObjectRenderer और OcclusionObjectRenderer, दोनों DepthCodelabActivity के सदस्य हों:
// Add this include at the top of the file.
import com.google.ar.core.codelab.common.rendering.OcclusionObjectRenderer;
// Add this member just below the existing "virtualObject", so both are present.
private final OcclusionObjectRenderer occludedVirtualObject = new OcclusionObjectRenderer();
- आपके पास यह कंट्रोल करने का विकल्प होता है कि इस
occludedVirtualObjectका इस्तेमाल कब किया जाए. यह इस बात पर निर्भर करता है कि मौजूदा डिवाइस, Depth API के साथ काम करता है या नहीं.onSurfaceCreatedतरीके में, इन लाइनों कोvirtualObjectके कॉन्फ़िगरेशन के नीचे जोड़ें:
if (isDepthSupported) {
occludedVirtualObject.createOnGlThread(/*context=*/ this, "models/andy.obj", "models/andy.png");
occludedVirtualObject.setDepthTexture(
depthTexture.getDepthTexture(),
depthTexture.getDepthWidth(),
depthTexture.getDepthHeight());
occludedVirtualObject.setMaterialProperties(0.0f, 2.0f, 0.5f, 6.0f);
}
जिन डिवाइसों पर डेप्थ की सुविधा काम नहीं करती है उन पर occludedVirtualObject इंस्टेंस बन जाता है, लेकिन इसका इस्तेमाल नहीं किया जाता. डेप्थ की सुविधा वाले फ़ोन पर, दोनों वर्शन शुरू किए जाते हैं. इसके बाद, रेंडरर के किस वर्शन का इस्तेमाल करना है, यह फ़ैसला रन-टाइम में लिया जाता है.
onDrawFrame() तरीके में, मौजूदा कोड ढूंढें:
virtualObject.updateModelMatrix(anchorMatrix, scaleFactor);
virtualObject.draw(viewmtx, projmtx, colorCorrectionRgba, OBJECT_COLOR);
इस कोड की जगह यह कोड डालें:
if (isDepthSupported) {
occludedVirtualObject.updateModelMatrix(anchorMatrix, scaleFactor);
occludedVirtualObject.draw(viewmtx, projmtx, colorCorrectionRgba, OBJECT_COLOR);
} else {
virtualObject.updateModelMatrix(anchorMatrix, scaleFactor);
virtualObject.draw(viewmtx, projmtx, colorCorrectionRgba, OBJECT_COLOR);
}
आखिर में, पक्का करें कि डेप्थ इमेज को आउटपुट रेंडरिंग पर सही तरीके से मैप किया गया हो. डेप्थ इमेज का रिज़ॉल्यूशन और आसपेक्ट रेशियो, आपकी स्क्रीन से अलग हो सकता है. इसलिए, टेक्सचर कोऑर्डिनेट, डेप्थ इमेज और कैमरे की इमेज के बीच अलग-अलग हो सकते हैं.
- फ़ाइल के सबसे नीचे, हेल्पर मेथड
getTextureTransformMatrix()जोड़ें. यह तरीका, एक ट्रांसफ़ॉर्मेशन मैट्रिक्स दिखाता है. इसे लागू करने पर, स्क्रीन स्पेस यूवी, क्वाड टेक्सचर कोऑर्डिनेट से सही तरीके से मैच करते हैं. इनका इस्तेमाल, कैमरे के फ़ीड को रेंडर करने के लिए किया जाता है. इसमें डिवाइस के ओरिएंटेशन को भी ध्यान में रखा जाता है.
private static float[] getTextureTransformMatrix(Frame frame) {
float[] frameTransform = new float[6];
float[] uvTransform = new float[9];
// XY pairs of coordinates in NDC space that constitute the origin and points along the two
// principal axes.
float[] ndcBasis = {0, 0, 1, 0, 0, 1};
// Temporarily store the transformed points into outputTransform.
frame.transformCoordinates2d(
Coordinates2d.OPENGL_NORMALIZED_DEVICE_COORDINATES,
ndcBasis,
Coordinates2d.TEXTURE_NORMALIZED,
frameTransform);
// Convert the transformed points into an affine transform and transpose it.
float ndcOriginX = frameTransform[0];
float ndcOriginY = frameTransform[1];
uvTransform[0] = frameTransform[2] - ndcOriginX;
uvTransform[1] = frameTransform[3] - ndcOriginY;
uvTransform[2] = 0;
uvTransform[3] = frameTransform[4] - ndcOriginX;
uvTransform[4] = frameTransform[5] - ndcOriginY;
uvTransform[5] = 0;
uvTransform[6] = ndcOriginX;
uvTransform[7] = ndcOriginY;
uvTransform[8] = 1;
return uvTransform;
}
getTextureTransformMatrix() को फ़ाइल के सबसे ऊपर यह इंपोर्ट करना होगा:
import com.google.ar.core.Coordinates2d;
आपको स्क्रीन का टेक्सचर बदलने पर, इन टेक्सचर कोऑर्डिनेट के बीच के ट्रांसफ़ॉर्म का हिसाब लगाना है. जैसे, स्क्रीन रोटेट होने पर. यह सुविधा कुछ शर्तों के साथ उपलब्ध है.
फ़ाइल में सबसे ऊपर यह फ़्लैग जोड़ें:
// Add this member at the top of the file.
private boolean calculateUVTransform = true;
onDrawFrame()में जाकर देखें कि फ़्रेम और कैमरा बनाने के बाद, सेव किए गए ट्रांसफ़ॉर्मेशन को फिर से कंप्यूट करने की ज़रूरत है या नहीं:
// Add these lines inside onDrawFrame() after frame.getCamera().
if (frame.hasDisplayGeometryChanged() || calculateUVTransform) {
calculateUVTransform = false;
float[] transform = getTextureTransformMatrix(frame);
occludedVirtualObject.setUvTransformMatrix(transform);
}
इन बदलावों के बाद, अब ऐप्लिकेशन को वर्चुअल ऑब्जेक्ट ऑक्लूज़न के साथ इस्तेमाल किया जा सकता है!
अब आपका ऐप्लिकेशन सभी फ़ोन पर ठीक से काम करेगा. साथ ही, यह सुविधा उपलब्ध होने पर, अपने-आप डेप्थ-फ़ॉर-ओक्लूज़न का इस्तेमाल करेगा.
|
| ||
डेप्थ एपीआई के साथ काम करने वाला ऐप्लिकेशन | ऐसे ऐप्लिकेशन जो Depth API के साथ काम नहीं करते | ||
9. [ज़रूरी नहीं] अक्लूज़न की क्वालिटी को बेहतर बनाएं
ऊपर लागू किए गए डेप्थ-बेस्ड ऑक्लूज़न के तरीके से, तीक्ष्ण सीमाओं वाला ऑक्लूज़न मिलता है. कैमरे को ऑब्जेक्ट से दूर ले जाने पर, डेप्थ मेज़रमेंट कम सटीक हो सकते हैं. इससे विज़ुअल आर्टफ़ैक्ट दिख सकते हैं.
हम इस समस्या को कम कर सकते हैं. इसके लिए, हमें ऑक्लूज़न टेस्ट में ज़्यादा ब्लर जोड़ना होगा. इससे छिपे हुए वर्चुअल ऑब्जेक्ट के किनारे ज़्यादा स्मूद हो जाते हैं.
occlusion_object.frag
occlusion_object.frag में सबसे ऊपर यह यूनिफ़ॉर्म वैरिएबल जोड़ें:
uniform float u_OcclusionBlurAmount;
इस हेल्पर फ़ंक्शन को शेडर में main() के ठीक ऊपर जोड़ें. यह फ़ंक्शन, ऑक्लूज़न सैंपलिंग पर कर्नल ब्लर लागू करता है:
float GetBlurredVisibilityAroundUV(in vec2 uv, in float asset_depth_mm) {
// Kernel used:
// 0 4 7 4 0
// 4 16 26 16 4
// 7 26 41 26 7
// 4 16 26 16 4
// 0 4 7 4 0
const float kKernelTotalWeights = 269.0;
float sum = 0.0;
vec2 blurriness = vec2(u_OcclusionBlurAmount,
u_OcclusionBlurAmount * u_DepthAspectRatio);
float current = 0.0;
current += GetVisibility(uv + vec2(-1.0, -2.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(+1.0, -2.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(-1.0, +2.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(+1.0, +2.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(-2.0, +1.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(+2.0, +1.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(-2.0, -1.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(+2.0, -1.0) * blurriness, asset_depth_mm);
sum += current * 4.0;
current = 0.0;
current += GetVisibility(uv + vec2(-2.0, -0.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(+2.0, +0.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(+0.0, +2.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(-0.0, -2.0) * blurriness, asset_depth_mm);
sum += current * 7.0;
current = 0.0;
current += GetVisibility(uv + vec2(-1.0, -1.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(+1.0, -1.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(-1.0, +1.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(+1.0, +1.0) * blurriness, asset_depth_mm);
sum += current * 16.0;
current = 0.0;
current += GetVisibility(uv + vec2(+0.0, +1.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(-0.0, -1.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(-1.0, -0.0) * blurriness, asset_depth_mm);
current += GetVisibility(uv + vec2(+1.0, +0.0) * blurriness, asset_depth_mm);
sum += current * 26.0;
sum += GetVisibility(uv , asset_depth_mm) * 41.0;
return sum / kKernelTotalWeights;
}
main() में मौजूद इस लाइन को बदलें:
gl_FragColor.a *= GetVisibility(depth_uvs, asset_depth_mm);
इस लाइन से बदलें:
gl_FragColor.a *= GetBlurredVisibilityAroundUV(depth_uvs, asset_depth_mm);
शेडर की इस नई सुविधा का फ़ायदा पाने के लिए, रेंडरर को अपडेट करें.
OcclusionObjectRenderer.java
क्लास में सबसे ऊपर, ये सदस्य वैरिएबल जोड़ें:
private int occlusionBlurUniform;
private final float occlusionsBlur = 0.01f;
createOnGlThread तरीके में यह जोड़ें:
// Add alongside the other calls to GLES20.glGetUniformLocation.
occlusionBlurUniform = GLES20.glGetUniformLocation(program, "u_OcclusionBlurAmount");
draw तरीके में यह जोड़ें:
// Add alongside the other calls to GLES20.glUniform1f.
GLES20.glUniform1f(occlusionBlurUniform, occlusionsBlur);
| विज़ुअल की तुलनाइन बदलावों के बाद, अब ऑक्लूज़न बाउंड्री ज़्यादा बेहतर दिखेगी. |
10. बनाएं-चलाएं-जांच करें
ऐप्लिकेशन बनाना और उसे चलाना
- किसी Android डिवाइस को यूएसबी केबल से कनेक्ट करें.
- फ़ाइल > बनाएं और चलाएं चुनें.
- इस रूप में सेव करें: ARCodeLab.apk.
- ऐप्लिकेशन के बनने और आपके डिवाइस पर डिप्लॉय होने तक इंतज़ार करें.
जब ऐप्लिकेशन को पहली बार अपने डिवाइस पर डिप्लॉय किया जाता है, तब:
- आपको डिवाइस पर यूएसबी डीबगिंग की अनुमति देनी होगी. जारी रखने के लिए, 'ठीक है' चुनें.
- आपसे पूछा जाएगा कि ऐप्लिकेशन को डिवाइस का कैमरा इस्तेमाल करने की अनुमति है या नहीं. एआर की सुविधा का इस्तेमाल जारी रखने के लिए, ऐक्सेस करने की अनुमति दें.
अपने ऐप्लिकेशन की जांच करना
ऐप्लिकेशन को चलाने के दौरान, उसके बुनियादी व्यवहार की जांच की जा सकती है. इसके लिए, अपने डिवाइस को पकड़ें, अपने आस-पास घूमें, और किसी जगह को धीरे-धीरे स्कैन करें. कम से कम 10 सेकंड का डेटा इकट्ठा करें. साथ ही, अगले चरण पर जाने से पहले, आस-पास की जगह को कई दिशाओं से स्कैन करें.
समस्या का हल
डेवलपमेंट के लिए, Android डिवाइस सेट अप करना
- यूएसबी केबल की मदद से, अपने डिवाइस को डेवलपमेंट मशीन से कनेक्ट करें. अगर Windows का इस्तेमाल करके डेवलपमेंट किया जा रहा है, तो आपको अपने डिवाइस के लिए सही यूएसबी ड्राइवर इंस्टॉल करना पड़ सकता है.
- डेवलपर के लिए सेटिंग और टूल विंडो में यूएसबी डीबग करना चालू करने के लिए, यह तरीका अपनाएं:
- Settings ऐप्लिकेशन खोलें.
- अगर आपके डिवाइस में Android v8.0 या इसके बाद का वर्शन है, तो सिस्टम को चुनें. अगर ऐसा नहीं है, तो अगले चरण पर जाएं.
- नीचे तक स्क्रोल करें और फ़ोन के बारे में जानकारी को चुनें.
- सबसे नीचे तक स्क्रोल करें और बिल्ड नंबर पर सात बार टैप करें.
- पिछली स्क्रीन पर वापस जाएं. इसके बाद, सबसे नीचे तक स्क्रोल करें और डेवलपर के लिए सेटिंग और टूल पर टैप करें.
- डेवलपर के लिए सेटिंग और टूल विंडो में, नीचे की ओर स्क्रोल करके यूएसबी डीबग करना ढूंढें और इसे चालू करें.
इस प्रोसेस के बारे में ज़्यादा जानकारी के लिए, Google की Android डेवलपर वेबसाइट पर जाएं.
लाइसेंस से जुड़ी बिल्ड की समस्याएं

अगर आपको लाइसेंस से जुड़ी कोई समस्या (Failed to install the following Android SDK packages as some licences have not been accepted) आती है, तो इन लाइसेंस की समीक्षा करने और उन्हें स्वीकार करने के लिए, इन कमांड का इस्तेमाल करें:
cd <path to Android SDK>
tools/bin/sdkmanager --licenses
11. बधाई हो
बधाई हो! आपने Google के ARCore Depth API का इस्तेमाल करके, डेप्थ पर आधारित अपना पहला ऑगमेंटेड रिएलिटी ऐप्लिकेशन बना लिया है और उसे चला लिया है!












