वर्चुअल ऑब्जेक्ट को असल दुनिया के व्यू में दिखाना

हिट टेस्ट एपीआई की मदद से, वर्चुअल आइटम को असल दुनिया के व्यू में दिखाया जा सकता है.

जो मेडली
जो मेडली

पिछली बार Chrome 79 में, WebXR Device API भेजा गया था. जैसा कि बताया गया है, Chrome में एपीआई को लागू करने का काम जारी है. Chrome को यह बताते हुए खुशी हो रही है कि कुछ काम पूरा हो गया है. Chrome 81 में दो नई सुविधाएं उपलब्ध हैं:

इस लेख में WebXR हिट टेस्ट एपीआई के बारे में बताया गया है. इसका मतलब है कि वर्चुअल ऑब्जेक्ट को असल कैमरे के व्यू में रखा जाता है.

इस लेख में, मुझे लगता है कि आपको ऑगमेंटेड रिएलिटी (एआर) सेशन बनाने का तरीका पहले से पता है. साथ ही, आपको फ़्रेम लूप चलाने का तरीका भी पता है. अगर आपको इन सिद्धांतों के बारे में जानकारी नहीं है, तो आपको इस सीरीज़ के पिछले लेख पढ़ लेने चाहिए.

इमर्सिव एआर सेशन सैंपल

इस लेख में दिया गया कोड, इमर्सिव वेब वर्किंग ग्रुप के हिट टेस्ट सैंपल (डेमो, सोर्स) में मौजूद कोड पर आधारित है. हालांकि, यह कोड उसके जैसा नहीं है. इस उदाहरण में, वर्चुअल सूरजमुखी को असल दुनिया की सतहों पर लगाने की सुविधा दी गई है.

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

इस सर्कल को रेटिकल कहा जाता है. यह एक अस्थायी इमेज है, जो किसी चीज़ को ऑगमेंटेड रिएलिटी (एआर) में रखने में मदद करती है. स्क्रीन पर टैप करने से, सतह पर सूरजमुखी को रेटिकल की जगह और रेटिकल पॉइंट की ओरिएंटेशन (स्क्रीन की दिशा) पर रखा जाता है, चाहे आपने स्क्रीन को कहीं भी टैप किया हो. रेटिकल आपके डिवाइस के साथ चलता रहता है.

कॉन्टेक्स्ट के हिसाब से दीवार, लैक्स या स्ट्रिक्ट पर रेंडर किया गया रेटिकल
रेटिकल कुछ समय के लिए दिखने वाली एक इमेज है, जिसकी मदद से किसी चीज़ को ऑगमेंटेड रिएलिटी (एआर) में रखा जा सकता है.

रेटिकल बनाएं

आपको खुद ही रेटिकल इमेज बनानी होगी, क्योंकि यह ब्राउज़र या एपीआई से उपलब्ध नहीं कराई गई है. इसे लोड करने और बनाने का तरीका, फ़्रेमवर्क के हिसाब से ही होता है. अगर सीधे WebGL या WebGL2 का इस्तेमाल करके ड्रॉइंग नहीं बनाई जा रही, तो अपने फ़्रेमवर्क दस्तावेज़ की मदद लें. इसलिए, मैं आपको इस बारे में पूरी जानकारी नहीं दूंगा कि सैंपल में रेटिकल को कैसे तैयार किया जाता है. नीचे इसकी एक लाइन सिर्फ़ एक वजह से दिखाई गई है: इससे बाद के कोड सैंपल में, reticle वैरिएबल का इस्तेमाल करते समय आपको पता चल जाएगा कि मैं क्या कह रहा हूं.

let reticle = new Gltf2Node({url: 'media/gltf/reticle/reticle.gltf'});

सेशन का अनुरोध करें

सेशन का अनुरोध करते समय, आपको नीचे दिखाए गए तरीके के मुताबिक, requiredFeatures कलेक्शन में 'hit-test' के लिए अनुरोध करना होगा.

navigator.xr.requestSession('immersive-ar', {
  requiredFeatures: ['local', 'hit-test']
})
.then((session) => {
  // Do something with the session
});

सत्र में प्रवेश करना

पिछले लेखों में, मैंने XR सेशन में जाने के लिए कोड दिया था. मैंने नीचे कुछ सुविधाओं के साथ इसका एक वर्शन दिखाया है. पहले मैंने select इवेंट लिसनर जोड़ा है. जब कोई व्यक्ति स्क्रीन पर टैप करेगा, तब कैमरे के व्यू में एक फूल दिखेगा, जो रेटिकल की पोज़ के हिसाब से दिखेगा. मैं इवेंट लिसनर के बारे में आगे बताऊँगी.

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);
  xrSession.addEventListener('select', onSelect);

  let canvas = document.createElement('canvas');
  gl = canvas.getContext('webgl', { xrCompatible: true });

  xrSession.updateRenderState({
    baseLayer: new XRWebGLLayer(session, gl)
  });

  xrSession.requestReferenceSpace('viewer').then((refSpace) => {
    xrViewerSpace = refSpace;
    xrSession.requestHitTestSource({ space: xrViewerSpace })
    .then((hitTestSource) => {
      xrHitTestSource = hitTestSource;
    });
  });

  xrSession.requestReferenceSpace('local').then((refSpace) => {
    xrRefSpace = refSpace;
    xrSession.requestAnimationFrame(onXRFrame);
  });
}

एक से ज़्यादा रेफ़रंस स्पेस

ध्यान दें कि हाइलाइट किया गया कोड XRSession.requestReferenceSpace() दो बार कॉल करता है. शुरुआत में मुझे यह समझ नहीं आया. मैंने पूछा कि हिट टेस्ट कोड किसी ऐनिमेशन फ़्रेम का अनुरोध क्यों नहीं करता (फ़्रेम लूप शुरू करना) और फ़्रेम लूप में हिट टेस्ट शामिल क्यों नहीं होते. ग़लतफ़हमी की वजह रेफ़रंस स्पेस की गलत जानकारी थी. रेफ़रंस स्पेस, किसी ऑरिजिन और दुनिया के बीच का संबंध दिखाते हैं.

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

इस सैंपल में, व्यूअर और कंट्रोलर का डिवाइस एक ही है. लेकिन मेरी एक समस्या है. पर्यावरण के मामले में, मेरा बनाया गया डेटा एक जैसा होना चाहिए. हालांकि, जिस 'कंट्रोलर' का इस्तेमाल किया जा रहा है वह घूम रहा है.

इमेज ड्रॉइंग के लिए, मैं local रेफ़रंस स्पेस का इस्तेमाल करती हूं, जिससे मुझे एनवायरमेंट के हिसाब से स्थिरता मिलती है. यह मिलने के बाद मैं requestAnimationFrame() को कॉल करके फ़्रेम लूप शुरू करती हूं.

हिट की जांच करने के लिए, मैं viewer रेफ़रंस स्पेस का इस्तेमाल करता/करती हूं, जो हिट टेस्ट के समय डिवाइस के पोज़ पर आधारित होता है. इस संदर्भ में लेबल 'व्यूअर' कुछ हद तक उलझन भरा है, क्योंकि मैं कंट्रोलर के बारे में बात कर रहा हूं. अगर आप नियंत्रक को एक इलेक्ट्रॉनिक दर्शक मानते हैं, तो यह बात सही है. इसे मिलने के बाद, मैं xrSession.requestHitTestSource() को कॉल करता हूं, जो हिट टेस्ट डेटा का सोर्स बनाता है, जिसका इस्तेमाल मैं ड्रॉइंग करते समय करूंगा.

फ़्रेम लूप चलाना

हिट की जांच करने के लिए, requestAnimationFrame() कॉलबैक को नया कोड भी मिलता है.

डिवाइस को हिलाने-डुलाने पर, रेटिकल को उसके साथ हिलना होगा, क्योंकि वह सतहों को ढूंढने की कोशिश करता है. मूवमेंट का भ्रम पैदा करने के लिए, हर फ़्रेम में रेटिकल फिर से ड्रॉ करें. हालांकि, अगर हिट की जांच नहीं हो पाती है, तो रेटिकल न दिखाएं. इसलिए, मैंने पहले जो रिटिकल बनाया था, उसके लिए मैंने visible प्रॉपर्टी को false पर सेट किया है.

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);

  reticle.visible = false;

  // Reminder: the hitTestSource was acquired during onSessionStart()
  if (xrHitTestSource && xrViewerPose) {
    let hitTestResults = xrFrame.getHitTestResults(xrHitTestSource);
    if (hitTestResults.length > 0) {
      let pose = hitTestResults[0].getPose(xrRefSpace);
      reticle.visible = true;
      reticle.matrix = pose.transform.matrix;
    }
  }

  // Draw to the screen
}

एआर में कुछ भी ड्रॉ करने के लिए, मुझे यह जानना होगा कि दर्शक कहां है और वह कहां देख रहा है. इसलिए मैं जांच करता हूं कि hitTestSource और xrViewerPose अब भी मान्य हैं.

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);

  reticle.visible = false;

  // Reminder: the hitTestSource was acquired during onSessionStart()
  if (xrHitTestSource && xrViewerPose) {
    let hitTestResults = xrFrame.getHitTestResults(xrHitTestSource);
    if (hitTestResults.length > 0) {
      let pose = hitTestResults[0].getPose(xrRefSpace);
      reticle.visible = true;
      reticle.matrix = pose.transform.matrix;
    }
  }

  // Draw to the screen
}

अब मैं getHitTestResults() को कॉल करता हूं. यह hitTestSource को तर्क के तौर पर लेता है और HitTestResult इंस्टेंस का अरे दिखाता है. हिट की जांच में कई प्लैटफ़ॉर्म मिल सकते हैं. कैटगरी में से पहला विकल्प, कैमरे के सबसे करीब है. ज़्यादातर मामलों में आप इसका इस्तेमाल करेंगे, लेकिन बेहतर इस्तेमाल के मामलों के लिए एक अरे दिखता है. उदाहरण के लिए, मान लें कि आपका कैमरा, फ़र्श पर मौजूद टेबल पर मौजूद बॉक्स पर फ़ोकस किया गया है. यह हो सकता है कि हिट की जांच करने पर, ऐरे में सभी तीन प्लैटफ़ॉर्म दिखें. ज़्यादातर मामलों में, मुझे अपने काम का बॉक्स ही चुनना होगा. अगर दिखाए गए कलेक्शन की लंबाई 0 है, तो दूसरे शब्दों में, अगर कोई हिट टेस्ट नहीं दिखता है, तो आगे बढ़ें. अगले फ़्रेम में फिर से कोशिश करें.

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);

  reticle.visible = false;

  // Reminder: the hitTestSource was acquired during onSessionStart()
  if (xrHitTestSource && xrViewerPose) {
    let hitTestResults = xrFrame.getHitTestResults(xrHitTestSource);
    if (hitTestResults.length > 0) {
      let pose = hitTestResults[0].getPose(xrRefSpace);
      reticle.visible = true;
      reticle.matrix = pose.transform.matrix;
    }
  }

  // Draw to the screen
}

आखिर में, मुझे हिट की जांच के नतीजों को प्रोसेस करना है. बुनियादी प्रक्रिया यह है. हिट की जांच के नतीजे से एक पोज़ लें, रेटिकल इमेज को हिट टेस्ट पोज़िशन में बदलें (मूव) करें, फिर उसकी visible प्रॉपर्टी को सही पर सेट करें. मुद्रा किसी सतह पर किसी बिंदु के पोज़ को दिखाती है.

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);

  reticle.visible = false;

  // Reminder: the hitTestSource was acquired during onSessionStart()
  if (xrHitTestSource && xrViewerPose) {
    let hitTestResults = xrFrame.getHitTestResults(xrHitTestSource);
    if (hitTestResults.length > 0) {
      let pose = hitTestResults[0].getPose(xrRefSpace);
      reticle.matrix = pose.transform.matrix;
      reticle.visible = true;

    }
  }

  // Draw to the screen
}

कोई चीज़ रखने के बारे में

जब उपयोगकर्ता स्क्रीन पर टैप करता है, तब उसे एआर (ऑगमेंटेड रिएलिटी) में रखा जाता है. मैंने सेशन में पहले ही select इवेंट हैंडलर जोड़ लिया है. (ऊपर देखें.)

इस चरण में सबसे ज़रूरी यह जानना है कि इसे कहां रखना है. मूविंग रेटिकल से आपको हिट टेस्ट का लगातार सोर्स मिलता है. इसलिए, किसी ऑब्जेक्ट को रखने का सबसे आसान तरीका उसे आखिरी हिट टेस्ट में रेटिकल की जगह पर बनाना है.

function onSelect(event) {
  if (reticle.visible) {
    // The reticle should already be positioned at the latest hit point,
    // so we can just use its matrix to save an unnecessary call to
    // event.frame.getHitTestResults.
    addARObjectAt(reticle.matrix);
  }
}

नतीजा

इसे मैनेज करने का सबसे अच्छा तरीका, सैंपल कोड देखना या कोडलैब आज़माना है. उम्मीद है कि मैंने आपको काफ़ी बैकग्राउंड दिया है, जिससे आप दोनों को समझ पाएंगे.

हमने ध्यान खींचने वाले वेब एपीआई बनाने का काम पूरा नहीं किया है, न कि बहुत लंबे समय तक. जैसे-जैसे हम आगे बढ़ेंगे वैसे-वैसे नए लेख यहां पब्लिश करते जाएंगे.

Unsplash पर डैनियल फ़्रैंक की फ़ोटो