WebGL ओवरले व्यू के साथ 3D मैप अनुभव पाएं

1. शुरू करने से पहले

यह कोडलैब आपको बताता है कि वेक्टर मैप पर तीन डाइमेंशन में कंट्रोल करने और रेंडर करने के लिए, Maps JavaScript API की WebGL सुविधाओं के साथ कैसे काम करें.

फ़ाइनल 3D पिन

ज़रूरी बातें

इस कोडलैब से यह माना जाता है कि आपको JavaScript और Maps JavaScript API की पूरी जानकारी है. मैप JS एपीआई के इस्तेमाल की बुनियादी बातें जानने के लिए, अपनी वेबसाइट (JavaScript) कोडलैब में मैप जोड़ें को आज़माएं.

आप इन चीज़ों के बारे में जानेंगे

  • JavaScript के लिए वेक्टर मैप के साथ मैप आईडी जनरेट किया गया.
  • प्रोग्राम के झुकाव और घुमाव की मदद से मैप को कंट्रोल करना.
  • WebGLOverlayView और Three.js से मैप पर 3D ऑब्जेक्ट रेंडर करना.
  • moveCamera के साथ कैमरे की गतिविधियों को ऐनिमेट किया जा रहा है.

आपको इनकी ज़रूरत होगी

  • बिलिंग की सुविधा वाला Google Cloud Platform खाता
  • चालू की गई Google Maps Platform API कुंजी, जिसमें Maps JavaScript API चालू है
  • JavaScript, एचटीएमएल, और सीएसएस का इंटरमीडिएट नॉलेज
  • आपकी पसंद का टेक्स्ट एडिटर या आईडीई
  • Node.js के लिए

2. सेट अप करें

नीचे चालू करने का तरीका पाने के लिए, आपको Maps JavaScript API चालू करना होगा.

Google Maps Platform सेट अप करना

अगर आपके पास पहले से Google Cloud Platform खाता नहीं है और बिलिंग की सुविधा चालू की गई है, तो कृपया बिलिंग खाता और प्रोजेक्ट बनाने के लिए, Google Maps Platform का इस्तेमाल शुरू करना गाइड देखें.

  1. Cloud Console में, प्रोजेक्ट ड्रॉप-डाउन मेन्यू पर क्लिक करें और वह प्रोजेक्ट चुनें जिसे आप इस कोडलैब के लिए इस्तेमाल करना चाहते हैं.

  1. Google Cloud Marketplace में, इस कोडलैब के लिए ज़रूरी Google Maps Platform API और SDK टूल चालू करें. ऐसा करने के लिए, इस वीडियो या इस दस्तावेज़ में दिया गया तरीका अपनाएं.
  2. Cloud Console के क्रेडेंशियल पेज में एपीआई कुंजी जनरेट करें. आप इस वीडियो या इस दस्तावेज़ में दिया गया तरीका अपना सकते हैं. Google Maps Platform पर सभी अनुरोधों के लिए एपीआई कुंजी ज़रूरी है.

Node.js का सेट अप

अगर आपके पास पहले से ##39 नहीं है, तो https://nodejs.org/ पर जाकर अपने कंप्यूटर पर Node.js रनटाइम डाउनलोड और इंस्टॉल करें.

Node.js, npm पैकेज मैनेजर के साथ आता है. आपको इस कोडलैब के लिए डिपेंडेंसी इंस्टॉल करनी होगी.

प्रोजेक्ट स्टार्टर टेंप्लेट डाउनलोड करना

इस कोडलैब का इस्तेमाल शुरू करने से पहले, स्टार्टर प्रोजेक्ट टेंप्लेट डाउनलोड करने के लिए, यह तरीका अपनाएं. साथ ही, पूरा सॉल्यूशन कोड भी डाउनलोड करें:

  1. https://github.com/googlecodelabs/maps-platform-101-webgl/ पर, इस कोडलैब के लिए GitHub repo डाउनलोड या फ़ोर्क करें. स्टार्टर प्रोजेक्ट, /starter डायरेक्ट्री में मौजूद है. इसमें कोडलैब को पूरा करने के लिए ज़रूरी बुनियादी फ़ाइल स्ट्रक्चर शामिल है. आपको जिस भी चीज़ के साथ काम करना है वह /starter/src निर्देशिका में मौजूद है.
  2. स्टार्टर प्रोजेक्ट डाउनलोड करने के बाद, /starter डायरेक्ट्री में npm install चलाएं. यह package.json में दी गई सभी ज़रूरी डिपेंडेंसी इंस्टॉल कर देता है.
  3. डिपेंडेंसी इंस्टॉल होने के बाद, डायरेक्ट्री में npm start चलाएं.

स्टार्टर प्रोजेक्ट को आपके लिए Webpack-dev-server

अगर आप पूरा समाधान कोड देखना चाहते हैं, तो आप ऊपर दी गई /solution डायरेक्ट्री में सेट अप पूरा कर सकते हैं.

अपनी एपीआई कुंजी जोड़ें

स्टार्टर ऐप्लिकेशन में वह सभी कोड शामिल है जो JS एपीआई लोडर से मैप को लोड करने के लिए ज़रूरी है, ताकि आपको सिर्फ़ एपीआई कुंजी और मैप आईडी देना पड़े. JS एपीआई लोडर एक आसान लाइब्रेरी है, जो एचटीएमएल टेंप्लेट में script टैग के साथ Maps JS एपीआई इनलाइन को लोड करने के पारंपरिक तरीके को ऐब्स्ट्रैक्ट करती है, जिससे आप JavaScript कोड में सब कुछ मैनेज कर सकते हैं.

अपनी एपीआई कुंजी जोड़ने के लिए, स्टार्टर प्रोजेक्ट में ये काम करें:

  1. app.js खोलें.
  2. apiOptions ऑब्जेक्ट में, अपनी एपीआई कुंजी को apiOptions.apiKey के मान के तौर पर सेट करें.

3. मैप आईडी जनरेट और इस्तेमाल करना

Maps JavaScript एपीआई की WebGL आधारित सुविधाएं इस्तेमाल करने के लिए, आपको वेक्टर मैप के चालू होने के साथ मैप आईडी की ज़रूरत होगी.

मैप आईडी जनरेट करना

मैप आईडी जनरेट करना

  1. Google Cloud Console में, Google Maps Platform' > [मैप मैनेजमेंट'. पर जाएं.
  2. {0}नया मैप आईडी बनाएं' पर क्लिक करें.
  3. {0}Map name' फ़ील्ड में, अपने Map ID के लिए एक नाम डालें.
  4. ड्रॉपडाउन सूची में, [Map type' चुनें. {0}JavaScript विकल्प' दिखेंगे.
  5. "JavaScript विकल्प' के तहत, "वेक्टर' रेडियो बटन, " टिल्ट' चेकबॉक्स, और 'घुमाएं' चेकबॉक्स को चुनें.
  6. Optional. अपनी कार की जानकारी के लिए, "ब्यौरा' फ़ील्ड में ब्यौरा डालें.
  7. 'आगे बढ़ें' बटन पर क्लिक करें. आपको "मैप आईडी की जानकारी' पेज दिखेगा.

    मैप की ज़्यादा जानकारी वाला पेज
  8. मैप आईडी कॉपी करें. मैप को लोड करने के लिए, अगले चरण में आप इसका इस्तेमाल करेंगे.

मैप आईडी का इस्तेमाल करना

वेक्टर मैप लोड करने के लिए, मैप को इंस्टैंशिएट करते समय, आपको विकल्पों में मैप आईडी को प्रॉपर्टी के तौर पर देना होगा. वैकल्पिक रूप से, मैप JavaScript API लोड करते समय आप वही मैप आईडी भी दे सकते हैं.

अपने मैप आईडी से मैप लोड करने के लिए, ये करें:

  1. अपने मैप आईडी को mapOptions.mapId की वैल्यू के तौर पर सेट करें.

    जब आप मैप को इंस्टैंशिएट करते हैं, तब मैप आईडी देना, Google Maps Platform को बताता है कि किसी खास इंस्टेंस के लिए आपके कौनसे मैप लोड करने हैं. आप एक ही मैप आईडी का इस्तेमाल, एक ही ऐप्लिकेशन में कई ऐप्लिकेशन या एक से ज़्यादा व्यू में कर सकते हैं.
    const mapOptions = {
      "tilt": 0,
      "heading": 0,
      "zoom": 18,
      "center": { lat: 35.6594945, lng: 139.6999859 },
      "mapId": "YOUR_MAP_ID"
    };
    

अपने ब्राउज़र में चल रहे ऐप्लिकेशन की जांच करें. झुकाने और घुमाने की सुविधा वाला वेक्टर मैप लोड हो जाना चाहिए. यह देखने के लिए कि झुकाना और घुमाना चालू है या नहीं, Shift बटन को दबाकर रखें और अपने माउस से खींचें या अपने कीबोर्ड पर ऐरो बटन का इस्तेमाल करें.

अगर मैप लोड नहीं होता है, तो देखें कि आपने apiOptions में एक मान्य एपीआई कुंजी दी है या नहीं. अगर मैप को झुकाने और घुमाने की ज़रूरत नहीं है, तो देखें कि आपने apiOptions और mapOptions में मैप आईडी दिया है, जिसमें झुकाएं और घुमाव चालू हैं.

झुका हुआ मैप

आपकी app.js फ़ाइल अब कुछ ऐसी दिखेगी:

    import { Loader } from '@googlemaps/js-api-loader';

    const apiOptions = {
      "apiKey": 'YOUR_API_KEY',
    };

    const mapOptions = {
      "tilt": 0,
      "heading": 0,
      "zoom": 18,
      "center": { lat: 35.6594945, lng: 139.6999859 },
      "mapId": "YOUR_MAP_ID"
    }

    async function initMap() {
      const mapDiv = document.getElementById("map");
      const apiLoader = new Loader(apiOptions);
      await apiLoader.load();
      return new google.maps.Map(mapDiv, mapOptions);
    }

    function initWebGLOverlayView (map) {
      let scene, renderer, camera, loader;
      // WebGLOverlayView code goes here
    }

    (async () => {
      const map = await initMap();
    })();

4. WebGLOverlayView लागू करें

WebGLOverlayView आपको उसी ग्राफ़िक रेंडरिंग के ऐक्सेस का सीधा ऐक्सेस देता है जिसका इस्तेमाल वेक्टर बेसमैप को रेंडर करने के लिए किया जाता है. इसका मतलब है कि आप सीधे WebGL का इस्तेमाल करके, 2D और 3D ऑब्जेक्ट को मैप पर दिखा सकते हैं. साथ ही, आप WebGL पर आधारित लोकप्रिय ग्राफ़िक लाइब्रेरी का भी इस्तेमाल कर सकते हैं.

WebGLOverlayView, मैप के उस रेंडरिंग पेज के लाइफ़साइकल में पांच हुक दिखाता है जिसका आप इस्तेमाल कर सकते हैं. यहां हर हुक की जानकारी दी गई है. साथ ही, यह भी बताया गया है कि उनके लिए क्या करना चाहिए:

  • onAdd(): जब WebGLOverlayView को setMap पर कॉल करके मैप में ओवरले जोड़ा जाता है, तब इसे कॉल किया जाता है. यहां आपको WebGL से जुड़ा ऐसा कोई भी काम करना चाहिए जिसके लिए WebGL संदर्भ का सीधा ऐक्सेस न हो.
  • onContextRestored(): यह तब कॉल किया जाता है, जब WebGL संदर्भ उपलब्ध हो जाता है, लेकिन किसी भी रेंडर से पहले. यहां आपको ऑब्जेक्ट शुरू करने चाहिए, स्टेट बाइंड करना चाहिए, और ऐसा कोई भी काम करना चाहिए जिसे WebGL संदर्भ का ऐक्सेस चाहिए, लेकिन onDraw() कॉल के बाहर भी किया जा सकता है. यह आपको मैप की वास्तविक रेंडरिंग में अतिरिक्त ओवरहेड जोड़े बिना अपनी ज़रूरत की हर चीज़ सेट करने देता है, जो पहले से ही GPU के लिए इंटेसिव है.
  • onDraw(): जब WebGL मैप को रेंडर करना शुरू कर दे और आपने #39;अनुरोध किया हो, तब हर फ़्रेम के लिए एक बार कॉल किया जाता है. मैप को रेंडर करने में परफ़ॉर्मेंस से जुड़ी समस्या से बचने के लिए, आपको onDraw() में कम से कम काम करना चाहिए.
  • onContextLost(): यह तब कॉल किया जाता है, जब किसी भी वजह से WebGL रेंडरिंग के संदर्भ खो जाते हैं.
  • onRemove(): इसे तब कॉल किया जाता है, जब setMap(null) को WebGLOverlayView के इंस्टेंस पर कॉल करके, मैप से ओवरले हटाया जाता है.

इस कदम में, आप WebGLOverlayView का एक इंस्टेंस बनाएंगे और इसके तीन लाइफ़साइकल हुक लागू करेंगे: onAdd, onContextRestored, और onDraw. चीज़ों को साफ़ और फ़ॉलो करने में आसान बनाने के लिए, ओवरले के सभी कोड को इस कोडलैब के स्टार्टर टेंप्लेट में दिए गए initWebGLOverlayView() फ़ंक्शन में हैंडल किया जाएगा.

  1. WebGLOverlayView() इंस्टेंस बनाएं.

    ओवरले को google.maps.WebGLOverlayView में Maps JS एपीआई से उपलब्ध कराया जाता है. शुरू करने के लिए, नीचे दी गई शर्तों के हिसाब से इंस्टेंस बनाएं: initWebGLOverlayView():
    const webGLOverlayView = new google.maps.WebGLOverlayView();
    
  2. लाइफ़साइकल हुक लागू करें.

    लाइफ़साइकल हुक लागू करने के लिए, इन्हें initWebGLOverlayView() में जोड़ें:
    webGLOverlayView.onAdd = () => {};
    webGLOverlayView.onContextRestored = ({gl}) => {};
    webGLOverlayView.onDraw = ({gl, coordinateTransformer}) => {};
    
  3. मैप में ओवरले इंस्टेंस जोड़ें.

    अब ओवरले इंस्टेंस पर setMap() को कॉल करें और initWebGLOverlayView() में नीचे दी गई जानकारी जोड़कर, मैप को पास करें:
    webGLOverlayView.setMap(map)
    
  4. initWebGLOverlayView पर कॉल करें.

    आखिरी चरण में, initWebGLOverlayView() को एक्ज़ीक्यूट करें. इसके लिए, app.js के निचले हिस्से में दिए गए 'तुरंत शुरू करें' फ़ंक्शन में यह जोड़ें:
    initWebGLOverlayView(map);
    

initWebGLOverlayView और तुरंत शुरू किया गया फ़ंक्शन अब ऐसा दिखना चाहिए:

    async function initWebGLOverlayView (map) {
      let scene, renderer, camera, loader;
      const webGLOverlayView = new google.maps.WebGLOverlayView();

      webGLOverlayView.onAdd = () => {}
      webGLOverlayView.onContextRestored = ({gl}) => {}
      webGLOverlayView.onDraw = ({gl, coordinateTransformer}) => {}
      webGLOverlayView.setMap(map);
    }

    (async () => {
      const map = await initMap();
      initWebGLOverlayView(map);
    })();

आपको बस WebGLOverlayView लागू करना है. इसके बाद, थ्री.js का इस्तेमाल करके मैप पर 3D ऑब्जेक्ट को रेंडर करने के लिए, आपको जो कुछ भी चाहिए वह सेट अप किया जाएगा.

5. तीन.js वाला सीन सेट अप करें

WebGL का उपयोग करना बहुत कठिन हो सकता है, क्योंकि इसके लिए आपको हर ऑब्जेक्ट के सभी पहलूों को मैन्युअल रूप से परिभाषित करना होगा और फिर कुछ को परिभाषित करना होगा. इस कोडलैब के लिए, आप तीन अलग-अलग चीज़ों को आसान बना सकते हैं. इसके लिए, आप #3.js का इस्तेमाल करेंगे, जो एक मशहूर ग्राफ़िक लाइब्रेरी है जो WebGL के ऊपर एक आसान ऐब्स्ट्रैक्शन लेयर देती है. Three.js कई तरह के सुविधा फ़ंक्शन के साथ आता है, जो WebGL रेंडरर बनाने से लेकर सामान्य 2D और 3D ऑब्जेक्ट आकार बनाने से लेकर कैमरे, ऑब्जेक्ट ट्रांसफ़ॉर्मेशन वगैरह को कंट्रोल करने तक, सब कुछ करता है.

Three.js में तीन बुनियादी तरह के ऑब्जेक्ट होते हैं, जो कुछ भी दिखाने के लिए ज़रूरी होते हैं:

  • दृश्य: एक &कोटेशन;कंटेनर जहां सभी ऑब्जेक्ट, रोशनी के स्रोत, बनावट वगैरह रेंडर और दिखाई जाती हैं.
  • कैमरा: कैमरा, सीन को व्यूपॉइंट के तौर पर दिखाता है. कैमरे के एक से ज़्यादा टाइप उपलब्ध हैं. साथ ही, एक या एक से ज़्यादा कैमरे एक ही सीन में जोड़े जा सकते हैं.
  • रेंडर करने वाला: रेंडरर, जो सीन में सभी ऑब्जेक्ट की प्रोसेसिंग और दिखाने का काम संभालता है. लिए. WebGLRenderer

इस चरण में, आप Three.js के लिए ज़रूरी सभी डिपेंडेंसी लोड करेंगे और एक बेसिक सीन सेट अप करेंगे.

  1. Four.js

    लोड करें
    आपको इस कोडलैब के लिए दो डिपेंडेंसी की ज़रूरत होगी: Three.js लाइब्रेरी और GLTF लोडर, जो जीएल ट्रांसमिशन फ़ॉर्मैट (gLTF) में 3D ऑब्जेक्ट लोड करने देता है. Three.js कई अलग-अलग 3D ऑब्जेक्ट फ़ॉर्मैट के लिए खास लोडर देता है, लेकिन हम gLTF का इस्तेमाल करने का सुझाव देते हैं.

    नीचे दिए गए कोड में, पूरी Three.js लाइब्रेरी इंपोर्ट की गई है. हो सकता है कि आप प्रोडक्शन ऐप्लिकेशन में उन क्लास को इंपोर्ट करना चाहें जिनकी आपको ज़रूरत है. हालांकि, इस कोडलैब के लिए, चीज़ों को आसान बनाने के लिए पूरी लाइब्रेरी इंपोर्ट करें. यह भी ध्यान दें कि GLTF लोडर को डिफ़ॉल्ट लाइब्रेरी में शामिल नहीं किया गया है. साथ ही, इसे डिपेंडेंसी में एक अलग पाथ से इंपोर्ट करना ज़रूरी है. यह वह पाथ है जहां आप Three.js से लोड किए गए सभी लोडर को ऐक्सेस कर सकते हैं.

    Three.js और GLTF लोडर को इंपोर्ट करने के लिए, इन्हें app.js में सबसे ऊपर जोड़ें:
    import * as THREE from 'three';
    import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';
    
  2. तीन.js वाला सीन बनाएं.

    सीन बनाने के लिए, Scene
  3. सीन में कैमरा जोड़ें.

    जैसा पहले बताया गया है, कैमरा सीन को देखने का व्यू दिखाता है और तय करता है कि Three.js किसी सीन में ऑब्जेक्ट की विज़ुअल रेंडरिंग को कैसे हैंडल करता है. कैमरे के बिना, सीन प्रभावी तौर पर &देखे नहीं जा सकते. इसका मतलब है कि ऑब्जेक्ट नहीं दिख सकते, क्योंकि वे रेंडर नहीं किए जा सकते.

    Three.js कई तरह के कैमरों की सुविधा देता है, जो इस बात पर असर डालते हैं कि रेंडर करने वाला किस तरह से चीज़ों के नज़रिए से काम करता है, जैसे कि उनका नज़रिया और गहराई. इस सीन में, आप #.3 में PerspectiveCamera का सबसे ज़्यादा इस्तेमाल होने वाला कैमरा टाइप इस्तेमाल करेंगे. इसे इस तरह डिज़ाइन किया गया है कि इंसान, आंख को सीन को सही तरीके से समझ सके. इसका मतलब है कि कैमरे से दूर मौजूद ऑब्जेक्ट, पास के ऑब्जेक्ट से छोटे दिखेंगे. साथ ही, सीन में गायब होने वाली जगह और बहुत कुछ होगा.

    सीन में खास तौर पर बनाया गया कैमरा जोड़ने के लिए, इन्हें onAdd हुक में जोड़ें:
    camera = new THREE.PerspectiveCamera();
    
    PerspectiveCamera के साथ, आप व्यू पॉइंट बनाने वाले एट्रिब्यूट भी कॉन्फ़िगर कर सकते हैं. इनमें अप-टू-डेट प्लेन, आसपेक्ट रेशियो, और फ़ील्ड ऑफ़ विज़न (फ़ॉव) शामिल हैं. सामूहिक रूप से, इन विशेषताओं को एक व्यू फ़्रॉस्टम कहा जाता है, जो 3D में काम करते समय ध्यान देने वाली एक ज़रूरी सिद्धांत है, लेकिन इस कोडलैब के दायरे से बाहर है. डिफ़ॉल्ट PerspectiveCamera कॉन्फ़िगरेशन ही काफ़ी होगा.
  4. सीन में लाइट सोर्स जोड़ें.

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

    Three.js कई तरह की रोशनी देता है, जिसमें से आप दो का इस्तेमाल कर सकते हैं
    :
  5. AmbientLight: यह डिफ़्यूज़ लाइट सोर्स उपलब्ध कराता है, जो सभी कोणों से हर ऑब्जेक्ट को समान रूप से रोशनी देता है. इससे सीन को आधार की रोशनी मिलती है, ताकि सभी ऑब्जेक्ट की बनावट दिख सके.
  6. DirectionalLight: सीन में किसी दिशा से शुरू होने वाली रोशनी देता है. वास्तविक दुनिया में तरंगों की रोशनी की स्थिति कैसी होती है, इसके उलट DirectionalLight से निकलने वाली किरणें सभी पैरलल होती हैं और रोशनी के स्रोत से दूर जाने पर ये अपने-आप नहीं फैलती हैं.

    आप हर लाइट के रंग और इंटेंसिटी को इस तरह कॉन्फ़िगर कर सकते हैं कि रोशनी के पूरे इफ़ेक्ट मिल जाएं. उदाहरण के लिए, नीचे दिए गए कोड में, आस-पास की रोशनी पूरे सीन के लिए सफ़ेद सफ़ेद लाइट उपलब्ध कराती है. वहीं, डायरेक्शनल लाइट एक सेकंडरी लाइट देती है, जो नीचे की ओर वाले ऑब्जेक्ट को हिट करती है. डायरेक्शनल लाइट के मामले में, position.set(x, y ,z) का इस्तेमाल करके ऐंगल सेट किया जाता है, जहां हर वैल्यू अपने-आप एक्सिस के हिसाब से होती है. उदाहरण के लिए, position.set(0,1,0), लाइट को सीधा नीचे की तरफ़ इशारा करते हुए, y-एक्सिस पर सीन के ठीक ऊपर रखेगा.

    लाइट सोर्स को सीन में जोड़ने के लिए, onAdd हुक में इन्हें जोड़ें:
    const ambientLight = new THREE.AmbientLight( 0xffffff, 0.75 );
    scene.add(ambientLight);
    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.25);
    directionalLight.position.set(0.5, -1, 0.5);
    scene.add(directionalLight);
    

आपका onAdd हुक अब ऐसा दिखेगा:

    webGLOverlayView.onAdd = () => {
      scene = new THREE.Scene();
      camera = new THREE.PerspectiveCamera();
      const ambientLight = new THREE.AmbientLight( 0xffffff, 0.75 );
      scene.add(ambientLight);
      const directionalLight = new THREE.DirectionalLight(0xffffff, 0.25);
      directionalLight.position.set(0.5, -1, 0.5);
      scene.add(directionalLight);
    }

अब आपका सीन सेट अप हो गया है और उसे रेंडर किया जा सकता है. इसके बाद, आप WebGL रेंडरर को कॉन्फ़िगर करेंगे और सीन को रेंडर करेंगे.

6. सीन को रेंडर करें

अपने सीन को रेंडर करने का समय आ गया है. इस समय तक, थ्री.js से बनाई गई हर चीज़ को कोड में शुरू किया जाता है. हालांकि, यह मौजूद नहीं है, क्योंकि इसे अब तक WebGL रेंडरिंग के लिए रेंडर नहीं किया गया है. WebGL, कैनवस एपीआई का इस्तेमाल करके, ब्राउज़र में 2D और 3D कॉन्टेंट रेंडर करता है. अगर आपने पहले #39;कैनवस एपीआई का इस्तेमाल किया है, तो इसका मतलब है कि आपcontext के एचटीएमएल एचटीएमएल कैनवस के बारे में जानते हैं. इस कैनवस में सब कुछ रेंडर किया जाता है. आपको यह जानकारी नहीं मिलेगी कि यह एक इंटरफ़ेस है, जो ब्राउज़र में WebGLRenderingContext एपीआई के ज़रिए OpenGL ग्राफ़िक रेंडरिंग कॉन्टेक्स्ट दिखाता है.

WebGL रेंडरर से संपर्क करना आसान बनाने के लिए, Three.js एक रैपर देता है WebGLRenderer, यह WebGL रेंडरिंग के संदर्भ को कॉन्फ़िगर करना आसान बनाता है, ताकि Three.js ब्राउज़र में सीन को रेंडर कर सके. मैप के मामले में, Maps के साथ-साथ ब्राउज़र में Three.js सीन रेंडर करने के लिए यह' काफ़ी नहीं है. Three.js को ठीक उसी तरह रेंडर करने वाले प्रसंग में रेंडर किया जाना चाहिए जैसा कि मैप के ज़रिए किया जाता है, ताकि मैप और Three.js दृश्य की कोई भी चीज़ एक ही दुनिया में रेंडर की जा सके. इससे रेंडरर, मैप पर मौजूद ऑब्जेक्ट और सीन में मौजूद ऑब्जेक्ट के बीच इंटरैक्शन को मैनेज कर सकते हैं. जैसे, 'ऑक्लूकेशन'. यह ऑब्जेक्ट को देखने का ऑब्जेक्ट होने से रोकने का सबसे अच्छा तरीका है.

क्या यह थोड़ा मुश्किल लग रहा है, है न? सबसे अच्छी बात यह है कि Three.js फिर से बचाव के लिए आ गया.

  1. WebGL रेंडरर सेट अप करें.

    जब आप Three.js WebGLRenderer का नया इंस्टेंस बनाते हैं, तो आप उसे वह खास WebGL रेंडरिंग कॉन्टेक्स्ट दे सकते हैं जिसमें आप अपने सीन को रेंडर करना चाहते हैं. gl हुक याद है जो onContextRestored हुक में चला गया है? gl ऑब्जेक्ट, मैप का WebGL रेंडरिंग कॉन्टेक्स्ट है. आपको बस WebGLRenderer इंस्टेंस के लिए संदर्भ, उसका कैनवस, और उसके एट्रिब्यूट देने होंगे. ये सभी gl ऑब्जेक्ट के ज़रिए उपलब्ध होते हैं. इस कोड में, रेंडरर की autoClear प्रॉपर्टी false पर भी सेट है, ताकि रेंडरर हर फ़्रेम को साफ़ नहीं कर सके.

    रेंडरर को कॉन्फ़िगर करने के लिए, इन्हें onContextRestored हुक में जोड़ें:
    renderer = new THREE.WebGLRenderer({
      canvas: gl.canvas,
      context: gl,
      ...gl.getContextAttributes(),
    });
    renderer.autoClear = false;
    
  2. सीन को रेंडर करें.

    रेंडरर कॉन्फ़िगर हो जाने के बाद, WebGLOverlayView इंस्टेंस पर requestRedraw को कॉल करके बताएं कि अगली फ़्रेम रेंडर करते समय फिर से रेडओवर की ज़रूरत है. इसके बाद, रेंडरर को render पर कॉल करें और रेंडर करने के लिए तीन.js सीन और कैमरा पास करें. आखिर में, WebGL रेंडरिंग के बारे में बताएं. यह GL स्थिति के संघर्षों से बचने का एक महत्वपूर्ण चरण है, क्योंकि WebGL ओवरले व्यू का उपयोग, शेयर की गई GL स्थिति पर निर्भर करता है. अगर हर ड्रॉ कॉल के आखिर में स्थिति रीसेट नहीं होती है, तो जीएल स्थिति के विवादों की वजह से रेंडरर काम नहीं कर पाता है.

    ऐसा करने के लिए, इसे onDraw हुक में जोड़ें, ताकि हर फ़्रेम को एक्ज़ीक्यूट किया जा सके:
    webGLOverlayView.requestRedraw();
    renderer.render(scene, camera);
    renderer.resetState();
    

आपके onContextRestored और onDraw हुक अब इस तरह दिखेंगे:

    webGLOverlayView.onContextRestored = ({gl}) => {
      renderer = new THREE.WebGLRenderer({
        canvas: gl.canvas,
        context: gl,
        ...gl.getContextAttributes(),
      });

      renderer.autoClear = false;
    }

    webGLOverlayView.onDraw = ({gl, transformer}) => {
      webGLOverlayView.requestRedraw();
      renderer.render(scene, camera);
      renderer.resetState();
    }

7. मैप पर 3D मॉडल रेंडर करें

ठीक है, आपने सभी चीज़ें पहले से तैयार कर ली हैं. आपने ##99 इसलिए, अब सीन में 3D ऑब्जेक्ट रेंडर करने का समय आ गया है. ऐसा करने के लिए, आप पहले से इंपोर्ट किए गए GLTF लोडर का इस्तेमाल कर पाएंगे'

3D मॉडल कई तरह के फ़ॉर्मैट में होते हैं, लेकिन Three.js के लिए, gLTF फ़ॉर्मैट ही इसके साइज़ और रनटाइम परफ़ॉर्मेंस की वजह से पसंदीदा फ़ॉर्मैट होता है. इस कोडलैब में, आपके लिए सीन में रेंडर करने के लिए एक मॉडल पहले से ही /src/pin.gltf में मौजूद है.

  1. मॉडल लोडर इंस्टेंस बनाएं.

    onAdd में ये चीज़ें जोड़ें:
    loader = new GLTFLoader();
    
  2. 3D मॉडल लोड करें.

    मॉडल लोड होने की प्रक्रिया एसिंक्रोनस है. मॉडल पूरी तरह लोड होने के बाद, कॉलबैक लोड किया जाता है. pin.gltf को लोड करने के लिए, onAdd में ये चीज़ें जोड़ें:
    const source = "pin.gltf";
    loader.load(
      source,
      gltf => {}
    );
    
  3. मॉडल को सीन में जोड़ें.

    अब आप loader कॉलबैक में ये चीज़ें जोड़कर, मॉडल को सीन में जोड़ सकते हैं. ध्यान दें कि gltf.scene जोड़ा जा रहा है, न कि gltf:
    scene.add(gltf.scene);
    
  4. कैमरा प्रोजेक्शन मैट्रिक्स को कॉन्फ़िगर करें.

    आखिरी चीज़ जिसे आपको मैप पर ठीक से रेंडर करने की ज़रूरत है वह थ्री.js सीन में कैमरे के प्रोजेक्शन मैट्रिक्स को सेट करने के लिए है. प्रोजेक्शन मैट्रिक्स को तीन.js Matrix4 अरे के रूप में बताया जाता है, जो रोटेशन, स्यर, स्केल वगैरह जैसे बदलावों के साथ तीन डाइमेंशन वाले स्पेस में एक पॉइंट तय करता है.

    WebGLOverlayView के मामले में, प्रोजेक्शन मैट्रिक्स का इस्तेमाल रेंडर करने वाले को यह बताने के लिए किया जाता है कि बेसमैप के मुकाबले थ्री.js सीन कहां और कैसे रेंडर करना है. हालांकि, एक समस्या है. मैप पर मौजूद जगहें अक्षांश और देशांतर निर्देशांक जोड़ियों के रूप में बताई गई हैं, जबकि Three.js सीन में जगहें Vector3 निर्देशांक हैं. जैसा कि आपने अनुमान लगाया होगा, दोनों सिस्टम के बीच कन्वर्ज़न की गणना करना आसान नहीं है. इसे हल करने के लिए, WebGLOverlayView, coordinateTransformer ऑब्जेक्ट को OnDraw लाइफ़साइकल हुक में पास करता है. इस ऑब्जेक्ट में fromLatLngAltitude नाम का एक फ़ंक्शन शामिल है. fromLatLngAltitude के लिए, LatLngAltitude या LatLngAltitudeLiteral ऑब्जेक्ट लिया जाता है. साथ ही, वैकल्पिक रूप से उन आर्ग्युमेंट का सेट लिया जाता है जो सीन के लिए ट्रांसफ़ॉर्मेशन बदलना चाहते हैं. इसके बाद, उन्हें आपके लिए मॉडल व्यू प्रोजेक्शन (एमवीपी) मैट्रिक्स के तौर पर कवर करता है. आपको बस यह तय करना है कि मैप पर Three.js सीन को कहां रेंडर करना है और उसके बाकी हिस्से को आप कैसे बदलना चाहते हैं, WebGLOverlayView बाकी कर देता है. इसके बाद, आप MVP मैट्रिक्स को three.js Matrix4 श्रेणी में बदलकर, कैमरा प्रोजेक्शन मैट्रिक्स को इस पर सेट कर सकते हैं.

    नीचे दिए गए कोड में, दूसरा तर्क, WebGl ओवरले व्यू को ज़मीन से Three.js सीन 120 मीटर की ऊंचाई सेट करने के लिए कहता है, जिससे मॉडल फ़्लोट होने लगता है.

    कैमरा प्रोजेक्शन मैट्रिक्स को सेट करने के लिए, इन्हें onDraw हुक में जोड़ें:
    const latLngAltitudeLiteral = {
        lat: mapOptions.center.lat,
        lng: mapOptions.center.lng,
        altitude: 120
    }
    const matrix = transformer.fromLatLngAltitude(latLngAltitudeLiteral);
    camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);
    
  5. मॉडल को पूरी तरह बदलें.

    आप देख पाएंगे कि पिन, मैप पर वर्टिकल (ऊपर से नीचे की ओर) नहीं है. 3D ग्राफ़िक में, दुनिया का स्पेस के अलावा, खुद का x, y, और z अक्ष होते हैं, जो ओरिएंटेशन तय करते हैं. हर ऑब्जेक्ट के पास अक्षों के एक स्वतंत्र सेट के साथ अपना ऑब्जेक्ट स्पेस भी होता है.

    इस मॉडल के मामले में, इसे y-अक्ष पर दिखने वाले पिन के अनुसार, "सबसे ऊपर और #39;" के तौर पर नहीं बनाया गया था. इसलिए, आपको ऑब्जेक्ट को दुनिया के हिसाब से सही स्पेस में बदलने के लिए, rotation.set को कॉल करना होगा. ध्यान दें कि Three.js में, घुमाव को रेडियन में दिखाया जाता है, डिग्री को नहीं. आम तौर पर, डिग्री में सोचना आसान होता है, इसलिए फ़ॉर्मूला degrees * Math.PI/180 का इस्तेमाल करके सही कन्वर्ज़न करना होता है.

    साथ ही, मॉडल थोड़ा छोटा है, इसलिए आप scale.set(x, y ,z) को कॉल करके, सभी अक्षों पर बराबरी से इसे स्केल करेंगे.

    मॉडल को घुमाने और स्केल करने के लिए, onAdd से पहले scene.add(gltf.scene) के loader कॉलबैक में इन्हें जोड़ें, जो gLTF को सीन में जोड़ता है:
    gltf.scene.scale.set(25,25,25);
    gltf.scene.rotation.x = 180 * Math.PI/180;
    

अब पिन, मैप के हिसाब से सीधा आ जाता है.

अपराइट पिन

आपके onAdd और onDraw हुक अब इस तरह दिखेंगे:

    webGLOverlayView.onAdd = () => {
      scene = new THREE.Scene();
      camera = new THREE.PerspectiveCamera();
      const ambientLight = new THREE.AmbientLight( 0xffffff, 0.75 ); // soft white light
      scene.add( ambientLight );
      const directionalLight = new THREE.DirectionalLight(0xffffff, 0.25);
      directionalLight.position.set(0.5, -1, 0.5);
      scene.add(directionalLight);

      loader = new GLTFLoader();
      const source = 'pin.gltf';
      loader.load(
        source,
        gltf => {
          gltf.scene.scale.set(25,25,25);
          gltf.scene.rotation.x = 180 * Math.PI/180;
          scene.add(gltf.scene);
        }
      );
    }

    webGLOverlayView.onDraw = ({gl, transformer}) => {
      const latLngAltitudeLiteral = {
        lat: mapOptions.center.lat,
        lng: mapOptions.center.lng,
        altitude: 100
      }

      const matrix = transformer.fromLatLngAltitude(latLngAltitudeLiteral);
      camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);

      webGLOverlayView.requestRedraw();
      renderer.render(scene, camera);
      renderer.resetState();
    }

अब कैमरा ऐनिमेशन देखें!

8. कैमरे को ऐनिमेट करें

अब आपने 'मैप पर एक मॉडल रेंडर कर लिया है और हर तीन को डाइमेंशन के तौर पर ले जा सकता है, अगली चीज़ जो आपको करनी है वह है कि उस प्रोग्राम को प्रोग्राम से कंट्रोल करें. moveCamera फ़ंक्शन आपको मैप के केंद्र, ज़ूम, झुकाने, और शीर्षक प्रॉपर्टी को एक साथ सेट करने की सुविधा देता है. इससे आपको उपयोगकर्ता अनुभव पर बेहतर नियंत्रण मिलता है. इसके अलावा, करीब 60 फ़्रेम प्रति सेकंड की फ़्रेम दर से फ़्रेम के बीच फ़्लूड ट्रांज़िशन बनाने के लिए, ऐनिमेशन लूप में moveCamera को कॉल किया जा सकता है.

  1. मॉडल के लोड होने तक इंतज़ार करें.

    आसानी से उपयोगकर्ता अनुभव पाने के लिए, यह ज़रूरी है कि आप gLTF मॉडल के लोड होने तक, कैमरे को एक जगह से दूसरी जगह ले जाना शुरू करें. ऐसा करने के लिए, लोड करने वाले का #onLoad इवेंट हैंडलर, onContextRestored हुक में जोड़ें:
    loader.manager.onLoad = () => {}
    
  2. ऐनिमेशन लूप बनाएं.

    यहां ऐनिमेशन लूप बनाने के एक से ज़्यादा तरीके हैं, जैसे कि setInterval या requestAnimationFrame का इस्तेमाल करना. इस मामले में, आप 3.js रेंडरर के setAnimationLoop फ़ंक्शन का इस्तेमाल करेंगे. यह फ़ंक्शन हर उस समय के लिए अपने-आप बताए गए कोड को कॉल करेगा, जब Three.js हर नए फ़्रेम को रेंडर करता है. ऐनिमेशन लूप बनाने के लिए, पिछले चरण में onLoad इवेंट हैंडलर में यह जोड़ें:
    renderer.setAnimationLoop(() => {});
    
  3. ऐनिमेशन लूप में कैमरे की स्थिति सेट करें.

    इसके बाद, मैप को अपडेट करने के लिए moveCamera को कॉल करें. यहां, मैप को लोड करने में इस्तेमाल किए गए mapOptions ऑब्जेक्ट से, कैमरे की स्थिति की जानकारी दी गई है:
    map.moveCamera({
      "tilt": mapOptions.tilt,
      "heading": mapOptions.heading,
      "zoom": mapOptions.zoom
    });
    
  4. कैमरे को हर फ़्रेम की जगह अपडेट करें.

    आखिरी चरण! अगले फ़्रेम के लिए, कैमरे की स्थिति सेट करने के लिए, हर फ़्रेम के आखिर में mapOptions ऑब्जेक्ट को अपडेट करें. इस कोड में, 67.5 की अधिकतम झुकाने की वैल्यू तक पहुंचने तक झुकाव को बढ़ाने के लिए if कथन का इस्तेमाल किया जाता है. इसके बाद शीर्षक तब तक हर फ़्रेम में थोड़ा बदला जाता है, जब तक कैमरा पूरा 360 डिग्री घुमाव पूरा नहीं कर लेता. मनचाहा ऐनिमेशन पूरा हो जाने पर, null को ऐनिमेशन रद्द करने के लिए setAnimationLoop के पास भेज दिया जाता है, ताकि वह हमेशा के लिए'न दिखे.
    if (mapOptions.tilt < 67.5) {
      mapOptions.tilt += 0.5
    } else if (mapOptions.heading <= 360) {
      mapOptions.heading += 0.2;
    } else {
      renderer.setAnimationLoop(null)
    }
    

आपका onContextRestored हुक अब ऐसा दिखेगा:

    webGLOverlayView.onContextRestored = ({gl}) => {
      renderer = new THREE.WebGLRenderer({
        canvas: gl.canvas,
        context: gl,
        ...gl.getContextAttributes(),
      });

      renderer.autoClear = false;

      loader.manager.onLoad = () => {
        renderer.setAnimationLoop(() => {
           map.moveCamera({
            "tilt": mapOptions.tilt,
            "heading": mapOptions.heading,
            "zoom": mapOptions.zoom
          });

          if (mapOptions.tilt < 67.5) {
            mapOptions.tilt += 0.5
          } else if (mapOptions.heading <= 360) {
            mapOptions.heading += 0.2;
          } else {
            renderer.setAnimationLoop(null)
          }
        });
      }
    }

9. बधाई हो

अगर सब कुछ प्लान के मुताबिक हुआ, तो अब आपके पास एक बड़ा 3D पिन वाला मैप होगा. इसमें आप कुछ इस तरह से दिखेगा:

फ़ाइनल 3D पिन

आपने क्या सीखा

इस कोडलैब में आपको कई तरह के काम के बारे में पता चला है, यहां इसकी खास बातें देखें:

  • WebGLOverlayView और इसके लाइफ़साइकल हुक को लागू किया जा रहा है.
  • Three.js को मैप में इंटिग्रेट किया जा रहा है.
  • कैमरे और लाइटिंग के साथ, Three.js सीन बनाने की बुनियादी बातें.
  • Three.js का इस्तेमाल करके 3D मॉडल लोड करना और उनमें बदलाव करना.
  • moveCamera का इस्तेमाल करके मैप के लिए कैमरे को कंट्रोल और ऐनिमेशन किया जा रहा है.

आगे क्या करना है?

आम तौर पर, WebGL और कंप्यूटर ग्राफ़िक एक जटिल विषय होते हैं. इसलिए, सीखने के लिए हमेशा कुछ नया होता है. आप इन संसाधनों की मदद से शुरुआत कर सकते हैं: