मोबाइल WebGL की मदद से, मध्य-धरती को ज़िंदा करना
मोबाइल और टैबलेट पर, इंटरैक्टिव, वेब-आधारित, और मल्टीमीडिया से जुड़े बेहतर अनुभव देना हमेशा से एक चुनौती रहा है. मुख्य समस्याएं परफ़ॉर्मेंस, एपीआई की उपलब्धता, डिवाइसों पर HTML5 ऑडियो की सीमाएं, और आसानी से इनलाइन वीडियो चलाने की सुविधा का न होना हैं.
इस साल की शुरुआत में, हमने Google और Warner Bros. के साथ मिलकर एक प्रोजेक्ट शुरू किया था. इसका मकसद, Hobbit की नई फ़िल्म The Hobbit: The Desolation of Smaug के लिए, मोबाइल-फ़र्स्ट वेब अनुभव बनाना था. मल्टीमीडिया के ज़्यादा इस्तेमाल वाले मोबाइल के लिए, Chrome एक्सपेरिमेंट बनाना वाकई में एक प्रेरणादायक और चुनौती भरा काम रहा.
यह सुविधा, नए Nexus डिवाइसों पर Chrome for Android के लिए ऑप्टिमाइज़ की गई है. इन डिवाइसों पर, अब हमारे पास WebGL और Web Audio का ऐक्सेस है. हालांकि, हार्डवेयर की मदद से तेज़ी से कॉम्पोज़ करने की सुविधा और सीएसएस ऐनिमेशन की मदद से, इस अनुभव का ज़्यादातर हिस्सा वेबजीएल के अलावा अन्य डिवाइसों और ब्राउज़र पर भी ऐक्सेस किया जा सकता है.
यह पूरा अनुभव, मिडल-अर्थ के मैप और हॉबिट फ़िल्मों की जगहों और किरदारों पर आधारित है. WebGL का इस्तेमाल करके, हमने 'हॉबिट' ट्रिलॉजी की शानदार दुनिया को दर्शकों के सामने ज़्यादा दिलचस्प तरीके से पेश किया. साथ ही, उन्हें इस अनुभव को कंट्रोल करने का विकल्प भी दिया.
मोबाइल डिवाइसों पर WebGL के इस्तेमाल से जुड़ी समस्याएं
सबसे पहले, "मोबाइल डिवाइस" शब्द का मतलब बहुत बड़ा है. डिवाइसों की खास बातें अलग-अलग होती हैं. इसलिए, डेवलपर के तौर पर आपको यह तय करना होगा कि आपको कम जटिल अनुभव के साथ ज़्यादा डिवाइसों पर काम करना है या इस मामले में हमने किया है, उन डिवाइसों पर काम करना है जो ज़्यादा असली 3D दुनिया दिखा सकते हैं. “Journey through Middle-earth” के लिए, हमने Nexus डिवाइसों और पांच लोकप्रिय Android स्मार्टफ़ोन पर फ़ोकस किया.
प्रयोग में, हमने three.js का इस्तेमाल किया, जैसा कि हमने अपने कुछ पिछले WebGL प्रोजेक्ट के लिए किया था. हमने Trollshaw गेम का शुरुआती वर्शन बनाकर, इसे लागू करना शुरू किया. यह वर्शन, Nexus 10 टैबलेट पर अच्छी तरह से चलता है. डिवाइस पर कुछ शुरुआती जांच करने के बाद, हमारे पास ऑप्टिमाइज़ेशन की एक सूची थी, जो कम स्पेसिफ़िकेशन वाले लैपटॉप के लिए आम तौर पर इस्तेमाल की जाती है:
- कम पॉली मॉडल का इस्तेमाल करना
- कम रिज़ॉल्यूशन वाले टेक्सचर का इस्तेमाल करना
- ज्यामिति को मर्ज करके, ड्रॉकॉल की संख्या को ज़्यादा से ज़्यादा कम करें
- कॉन्टेंट में इस्तेमाल किए गए कॉन्टेंट और लाइटिंग को आसान बनाएं
- पोस्ट इफ़ेक्ट हटाना और ऐंटी-ऐलिऐसिंग बंद करना
- JavaScript की परफ़ॉर्मेंस को ऑप्टिमाइज़ करना
- WebGL कैनवस को आधे साइज़ में रेंडर करना और सीएसएस की मदद से उसे बड़ा करना
गेम के शुरुआती वर्शन में ये ऑप्टिमाइज़ेशन लागू करने के बाद, हमें 30FPS का फ़्रेम रेट मिला. इससे हम काफ़ी खुश थे. उस समय हमारा लक्ष्य, फ़्रेम रेट पर बुरा असर डाले बिना विज़ुअल को बेहतर बनाना था. हमने कई तरह की कोशिशें कीं: कुछ की वजह से परफ़ॉर्मेंस पर असर पड़ा, लेकिन कुछ का असर उतना नहीं हुआ जितना हम चाहते थे.
कम पॉली मॉडल का इस्तेमाल करना
चलिए, मॉडल से शुरू करते हैं. कम पॉली मॉडल का इस्तेमाल करने से, डाउनलोड होने में लगने वाले समय के साथ-साथ सीन को शुरू करने में लगने वाले समय में भी कमी आती है. हमें पता चला कि परफ़ॉर्मेंस पर ज़्यादा असर डाले बिना, हम कॉम्प्लेक्सिटी को काफ़ी बढ़ा सकते हैं. इस गेम में हम करीब 5 हज़ार चेहरों के ट्रोल मॉडल और 40 हज़ार चेहरों के सीन का इस्तेमाल करते हैं. यह गेम ठीक से काम करता है.

इस सुविधा के लिए, हमने एक और जगह (अभी रिलीज़ नहीं हुई है) पर पॉलीगॉन की संख्या कम की. इससे हमें परफ़ॉर्मेंस पर ज़्यादा असर देखने को मिला. ऐसे में, हमने डेस्कटॉप के लिए लोड किए गए ऑब्जेक्ट के मुकाबले, मोबाइल डिवाइसों के लिए कम पॉलीगॉन वाले ऑब्जेक्ट लोड किए. 3D मॉडल के अलग-अलग सेट बनाने के लिए, कुछ अतिरिक्त काम करना पड़ता है. हालांकि, ऐसा हमेशा ज़रूरी नहीं होता. यह इस बात पर निर्भर करता है कि आपके मॉडल कितने जटिल हैं.
कई ऑब्जेक्ट वाले बड़े सीन पर काम करते समय, हमने यह तय करने की कोशिश की कि ज्यामिति को कैसे बांटें. इससे, हम कम ज़रूरी मेश को तुरंत चालू और बंद कर पाए. इससे हमें सभी मोबाइल डिवाइसों के लिए काम करने वाली सेटिंग मिल गई. इसके बाद, हम डाइनैमिक ऑप्टिमाइज़ेशन के लिए, रनटाइम पर JavaScript में ज्यामिति को मर्ज कर सकते हैं. इसके अलावा, अनुरोधों को सेव करने के लिए, इसे प्री-प्रोडक्शन में मर्ज किया जा सकता है.
कम रिज़ॉल्यूशन वाले टेक्सचर का इस्तेमाल करना
मोबाइल डिवाइसों पर लोड होने में लगने वाले समय को कम करने के लिए, हमने अलग-अलग टेक्सचर लोड करने का विकल्प चुना. ये टेक्सचर, डेस्कटॉप पर इस्तेमाल होने वाले टेक्सचर के आधे साइज़ के थे. ऐसा लगता है कि सभी डिवाइस 2048x2048 पिक्सल तक के टेक्स्चर साइज़ को हैंडल कर सकते हैं. ज़्यादातर डिवाइस 4096x4096 पिक्सल तक के टेक्स्चर साइज़ को हैंडल कर सकते हैं. अलग-अलग टेक्सचर को जीपीयू पर अपलोड करने के बाद, उन पर टेक्सचर लुकअप करने में कोई समस्या नहीं होती. टेक्सचर का कुल साइज़, जीपीयू मेमोरी में फ़िट होना चाहिए, ताकि टेक्सचर को लगातार अपलोड और डाउनलोड न करना पड़े. हालांकि, ज़्यादातर वेब-एक्सपीरियंस के लिए, यह कोई बड़ी समस्या नहीं है. हालांकि, ड्रॉकॉल की संख्या कम करने के लिए, टेक्सचर को ज़्यादा से ज़्यादा स्प्राइटशीट में जोड़ना ज़रूरी है. मोबाइल डिवाइसों पर परफ़ॉर्मेंस पर इसका काफ़ी असर पड़ता है.

(ओरिजनल साइज़ 512x512 पिक्सल)
कॉन्टेंट में इस्तेमाल किए गए कॉन्टेंट और लाइटिंग को आसान बनाएं
कॉन्टेंट में इस्तेमाल किए गए कॉन्टेंट के टाइप से भी परफ़ॉर्मेंस पर काफ़ी असर पड़ सकता है. इसलिए, मोबाइल पर कॉन्टेंट को ध्यान से मैनेज करना चाहिए. हमने परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के लिए, three.js में MeshPhongMaterial
(हर टेक्सल लाइट कैलकुलेशन) के बजाय MeshLambertMaterial
(हर वर्टिक्स लाइट कैलकुलेशन) का इस्तेमाल किया है. हमने ज़्यादा से ज़्यादा रोशनी के कैलकुलेशन के साथ, आसान शेडर का इस्तेमाल करने की कोशिश की है.
यह देखने के लिए कि इस्तेमाल किए गए मटीरियल से सीन की परफ़ॉर्मेंस पर क्या असर पड़ता है, MeshBasicMaterial
का इस्तेमाल करके सीन के मटीरियल बदले जा सकते हैं . इससे आपको बेहतर तुलना करने में मदद मिलेगी.
scene.overrideMaterial = new THREE.MeshBasicMaterial({color:0x333333, wireframe:true});
JavaScript की परफ़ॉर्मेंस को ऑप्टिमाइज़ करना
मोबाइल के लिए गेम बनाते समय, जीपीयू हमेशा सबसे बड़ी समस्या नहीं होती. सीपीयू पर काफ़ी समय लगता है. खास तौर पर, फ़िज़िक्स और स्केलेटल ऐनिमेशन पर. सिम्युलेशन के हिसाब से, कभी-कभी एक तरकीब से मदद मिलती है. यह तरकीब यह है कि इन महंगी गणनाओं को हर दूसरे फ़्रेम में ही चलाया जाए. ऑब्जेक्ट पूल करने, कचरा इकट्ठा करने, और ऑब्जेक्ट बनाने के लिए, JavaScript ऑप्टिमाइज़ेशन की उपलब्ध तकनीकों का भी इस्तेमाल किया जा सकता है.
नए ऑब्जेक्ट बनाने के बजाय, पहले से तय किए गए ऑब्जेक्ट को लूप में अपडेट करना एक अहम कदम है. इससे गेम के दौरान, गै़रबेज कलेक्शन से जुड़ी "समस्याओं" से बचा जा सकता है.
उदाहरण के लिए, इस तरह का कोड देखें:
var currentPos = new THREE.Vector3();
function gameLoop() {
currentPos = new THREE.Vector3(0+offsetX,100,0);
}
इस लूप के बेहतर वर्शन से, ऐसे नए ऑब्जेक्ट बनाने से बचा जा सकता है जिन्हें गै़रबेज कलेक्शन की ज़रूरत होती है:
var originPos = new THREE.Vector3(0,100,0);
var currentPos = new THREE.Vector3();
function gameLoop() {
currentPos.copy(originPos).x += offsetX;
//or
currentPos.set(originPos.x+offsetX,originPos.y,originPos.z);
}
जहां तक हो सके, इवेंट हैंडलर को सिर्फ़ प्रॉपर्टी अपडेट करनी चाहिए. साथ ही, requestAnimationFrame
रेंडर-लूप को स्टेज अपडेट करने की अनुमति देनी चाहिए.
एक और सलाह यह है कि रे-कास्टिंग ऑपरेशन को ऑप्टिमाइज़ करें और/या पहले से कैलकुलेट करें. उदाहरण के लिए, अगर आपको स्टैटिक पाथ पर किसी ऑब्जेक्ट को किसी मेश से अटैच करना है, तो एक लूप के दौरान पोज़िशन "रिकॉर्ड" की जा सकती हैं. इसके बाद, मेश के लिए रे-कास्टिंग करने के बजाय, इस डेटा को पढ़ा जा सकता है. इसके अलावा, Rivendell एक्सपीरियंस में हम रे-कास्ट का इस्तेमाल करते हैं. इससे, माउस के इंटरैक्शन को देखने के लिए, कम पॉली वाले आसान और न दिखने वाले मेश का इस्तेमाल किया जाता है. हाई-पॉली मेश पर, टक्कर की जांच करने में काफ़ी समय लगता है. इसलिए, आम तौर पर गेम-लूप में ऐसा करने से बचना चाहिए.
WebGL कैनवस को आधे साइज़ में रेंडर करना और सीएसएस की मदद से उसे बड़ा करना
WebGL कैनवस का साइज़, शायद सबसे असरदार पैरामीटर है. परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के लिए, इसमें बदलाव किया जा सकता है. 3D सीन बनाने के लिए जितने बड़े कैनवस का इस्तेमाल किया जाता है, उतने ही ज़्यादा पिक्सल हर फ़्रेम पर डालने पड़ते हैं. इससे परफ़ॉर्मेंस पर असर पड़ता है.Nexus 10 के हाई-डेंसिटी 2560x1600 पिक्सल डिसप्ले को, कम-डेंसिटी वाले टैबलेट के मुकाबले चार गुना ज़्यादा पिक्सल दिखाने होते हैं. इसे मोबाइल के लिए ऑप्टिमाइज़ करने के लिए, हम एक ट्रिक का इस्तेमाल करते हैं. इसमें हम कैनवस को आधे साइज़ (50%) पर सेट करते हैं. इसके बाद, हार्डवेयर से तेज़ किए गए सीएसएस 3D ट्रांसफ़ॉर्म की मदद से, इसे अपने ज़रूरी साइज़ (100%) पर स्केल करते हैं. इसका नुकसान यह है कि पिक्सल वाली इमेज में पतली लाइनों को देखने में समस्या आ सकती है. हालांकि, हाई रिज़ॉल्यूशन वाली स्क्रीन पर इसका असर इतना बुरा नहीं होता. ज़्यादा परफ़ॉर्मेंस के लिए, यह ज़रूरी है.

बिल्डिंग ब्लॉक के तौर पर ऑब्जेक्ट
Dol Guldur कैसल की बड़ी भूलभुलैया और Rivendell की कभी न खत्म होने वाली घाटी बनाने के लिए, हमने बिल्डिंग ब्लॉक के 3D मॉडल का एक सेट बनाया. हम इनका फिर से इस्तेमाल करते हैं. ऑब्जेक्ट का फिर से इस्तेमाल करने से, हमें यह पक्का करने में मदद मिलती है कि ऑब्जेक्ट को इस्तेमाल करने के दौरान ही इंस्टैंशिएट और अपलोड किया जाए, न कि बीच में.

Rivendell में हमारे पास ज़मीन के कई सेक्शन हैं, जिन्हें हम उपयोगकर्ता के सफ़र के दौरान, Z-डेप्थ में लगातार बदलते रहते हैं. जब उपयोगकर्ता सेक्शन को पार कर जाता है, तो उन्हें दूर की दूरी पर फिर से पोज़िशन किया जाता है.
Dol Guldur castle के लिए, हम चाहते थे कि हर गेम के लिए, मैज़ फिर से जनरेट हो. इसके लिए, हमने एक स्क्रिप्ट बनाई है, जो मैज़ को फिर से जनरेट करती है.
शुरुआत से ही पूरे स्ट्रक्चर को एक बड़े मेश में मर्ज करने पर, बहुत बड़ा सीन बनता है और परफ़ॉर्मेंस खराब होती है. इस समस्या को हल करने के लिए, हमने बिल्डिंग ब्लॉक को छिपाने और दिखाने का फ़ैसला लिया है. यह इस बात पर निर्भर करेगा कि वे आपके नज़र में हैं या नहीं. शुरू से ही, हमारे पास 2D रेकास्टर स्क्रिप्ट का इस्तेमाल करने का आइडिया था. हालांकि, आखिर में हमने three.js में पहले से मौजूद फ़्रस्ट्रम कलिंग का इस्तेमाल किया. हमने रेकास्टर स्क्रिप्ट का फिर से इस्तेमाल किया, ताकि प्लेयर को खतरे की जानकारी देने वाली इमेज को ज़ूम इन किया जा सके.
अगला अहम चरण, उपयोगकर्ता के इंटरैक्शन को मैनेज करना है. डेस्कटॉप पर, माउस और कीबोर्ड इनपुट का इस्तेमाल किया जाता है. वहीं, मोबाइल डिवाइसों पर उपयोगकर्ता टच, स्वाइप, पिंच, डिवाइस ओरिएंटेशन वगैरह का इस्तेमाल करके इंटरैक्ट करते हैं.
मोबाइल वेब अनुभवों में टच इंटरैक्शन का इस्तेमाल करना
टच सपोर्ट जोड़ना मुश्किल नहीं है. इस विषय के बारे में पढ़ने के लिए, शानदार लेख मौजूद हैं. हालांकि, कुछ छोटी-मोटी बातों की वजह से यह प्रोसेस ज़्यादा मुश्किल हो सकती है.
आपके पास टच और माउस, दोनों का विकल्प होता है. Chromebook Pixel और टच की सुविधा वाले अन्य लैपटॉप पर, माउस और टच, दोनों काम करते हैं. एक आम गलती यह है कि डिवाइस पर टच की सुविधा चालू है या नहीं, यह देखने के बाद सिर्फ़ टच इवेंट लिसनर जोड़ें और माउस के लिए कोई इवेंट लिसनर न जोड़ें.
इवेंट लिसनर में रेंडरिंग को अपडेट न करें. इसके बजाय, टच इवेंट को वैरिएबल में सेव करें और requestAnimationFrame रेंडर लूप में उन पर प्रतिक्रिया दें. इससे परफ़ॉर्मेंस बेहतर होती है और एक-दूसरे से मेल न खाने वाले इवेंट को एक साथ जोड़ा जा सकता है. पक्का करें कि आपने इवेंट लिसनर में नए ऑब्जेक्ट बनाने के बजाय, मौजूदा ऑब्जेक्ट का फिर से इस्तेमाल किया हो.
याद रखें कि यह मल्टीटच है: event.touches सभी टच का कलेक्शन है. कुछ मामलों में, event.targetTouches या event.changedTouches को देखना ज़्यादा दिलचस्प होता है. साथ ही, सिर्फ़ उन टच पर प्रतिक्रिया दें जिनमें आपकी दिलचस्पी है. टैप और स्वाइप को अलग-अलग करने के लिए, हम कुछ देर इंतज़ार करते हैं. इसके बाद, यह देखा जाता है कि टच मूव हुआ है या नहीं (स्वाइप) या टच एक ही जगह पर है (टैप). पिंच करने के लिए, हम शुरुआती दो टच के बीच की दूरी और समय के साथ उसमें होने वाले बदलाव को मेज़र करते हैं.
3D वर्ल्ड में, आपको यह तय करना होता है कि आपका कैमरा माउस और स्वाइप ऐक्शन पर कैसे प्रतिक्रिया देगा. कैमरे की मूवमेंट जोड़ने का एक सामान्य तरीका यह है कि माउस की मूवमेंट को फ़ॉलो किया जाए. ऐसा, माउस की पोज़िशन का इस्तेमाल करके सीधे कंट्रोल करने या डेल्टा मूवमेंट (पोज़िशन में बदलाव) की मदद से किया जा सकता है. ऐसा हो सकता है कि आपको मोबाइल डिवाइस पर, डेस्कटॉप ब्राउज़र जैसा व्यवहार न चाहिए. हमने कई तरह के टेस्ट किए, ताकि यह तय किया जा सके कि हर वर्शन के लिए कौनसा विकल्प सही है.
छोटी स्क्रीन और टचस्क्रीन का इस्तेमाल करते समय, आपको पता चलेगा कि उपयोगकर्ता के उंगलियों और यूज़र इंटरफ़ेस (यूआई) इंटरैक्शन के ग्राफ़िक, अक्सर उस चीज़ के रास्ते में आ जाते हैं जिसे आपको दिखाना है. नेटिव ऐप्लिकेशन डिज़ाइन करते समय, हम इस बात का ध्यान रखते हैं. हालांकि, वेब पर इस बात का ध्यान नहीं रखा जाता था. यह डिज़ाइनर और UX डिज़ाइनर के लिए एक असल चुनौती है.
खास जानकारी
इस प्रोजेक्ट से हमें पता चला है कि मोबाइल पर WebGL काफ़ी अच्छा काम करता है. खास तौर पर, नए और बेहतर डिवाइसों पर. परफ़ॉर्मेंस के मामले में, ऐसा लगता है कि पॉलीगॉन की संख्या और टेक्स्चर के साइज़ का डाउनलोड और शुरू होने में लगने वाले समय पर ज़्यादा असर पड़ता है. साथ ही, मोबाइल पर परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के लिए, मेटीरियल, शेडर, और WebGL कैनवस का साइज़ सबसे ज़रूरी हिस्सा है. हालांकि, परफ़ॉर्मेंस पर इन सभी चीज़ों का असर पड़ता है. इसलिए, ऑप्टिमाइज़ करने के लिए जो भी किया जा सकता है, करें.
मोबाइल डिवाइसों को टारगेट करने का मतलब यह भी है कि आपको टच इंटरैक्शन के बारे में सोचने की आदत डालनी होगी. यह सिर्फ़ पिक्सल साइज़ के बारे में नहीं है, बल्कि स्क्रीन के फ़िज़िकल साइज़ के बारे में भी है. कुछ मामलों में, हमें 3D कैमरे को ज़्यादा करीब ले जाकर यह देखना पड़ा कि क्या हो रहा है.
यह एक्सपेरिमेंट लॉन्च हो गया है और यह एक शानदार सफ़र रहा. उम्मीद है कि आपको यह पसंद आएगा!
क्या आप इसे आज़माना है? मिडिल अर्थ की यात्रा पर जाएं.