ब्लर को ऐनिमेट करना

यी गु
यी गु

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

बहुत ज़्यादा शब्द हैं, पढ़ा नहीं गया

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

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

समस्या

मार्कअप को सीपीयू की मदद से
टेक्सचर में बदल दिया जाता है. टेक्सचर को जीपीयू पर अपलोड किया जाता है. जीपीयू, शेडर का इस्तेमाल करके इन टेक्सचर को फ़्रेमबफ़र में ड्रॉ करता है. शेडर में धुंधलापन होता है.

फ़िलहाल, हम वीडियो को धुंधला करने वाले इफ़ेक्ट को बेहतर तरीके से ऐनिमेट नहीं कर सकते. हालांकि, हम ऐसा समाधान खोज सकते हैं जो काफ़ी अच्छा लगे, लेकिन तकनीकी तौर पर कहा जाए, तो यह ऐनिमेशन वाला ब्लर नहीं है. सबसे पहले यह जानते हैं कि ऐनिमेशन वाला धुंधलापन क्यों बढ़ रहा है. वेब पर एलिमेंट को धुंधला करने के दो तरीके हैं: सीएसएस filter प्रॉपर्टी और SVG फ़िल्टर. बेहतर सहायता और इस्तेमाल में आसानी की वजह से आम तौर पर सीएसएस फ़िल्टर इस्तेमाल किए जाते हैं. माफ़ करें, अगर आपके लिए Internet Explorer का इस्तेमाल करना ज़रूरी है, तो आपके पास IE 10 और 11 के लिए SVG फ़िल्टर का इस्तेमाल करने के अलावा, सीएसएस फ़िल्टर के बजाय SVG फ़िल्टर का इस्तेमाल करने का कोई विकल्प नहीं है. अच्छी खबर यह है कि फ़ोटो या वीडियो के बैकग्राउंड को ऐनिमेट करने का हमारा तरीका, दोनों तकनीकों के साथ काम करता है. आइए, DevTools में देखकर अटखट ढूंढने की कोशिश करते हैं.

अगर आप DevTools में "पेंट फ़्लैशिंग" को चालू करते हैं, तो आपको कोई भी फ़्लैश नहीं दिखेगा. लगता है कि कोई रीपेंट नहीं किया जा रहा है. तकनीकी तौर पर यह बात सही है, क्योंकि "रीपेंट" करने का मतलब है कि सीपीयू को प्रमोट किए गए एलिमेंट के टेक्सचर को फिर से पेंट करना होता है. जब किसी एलिमेंट को प्रमोट किया गया और दोनों धुंधला किया जाता है, तो जीपीयू शेडर का इस्तेमाल करके, धुंधला किया जाता है.

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

यहीं पर समस्या है, तो हम हर फ़्रेम में काफ़ी महंगा जीपीयू ऑपरेशन चलाते हैं, जिससे हमारा फ़्रेम बजट 16 मि॰से॰ का हो जाता है, जिससे यह 60 एफ़पीएस (फ़्रेम प्रति सेकंड) से भी कम हो जाता है.

रैबिट होल

इसे बिना किसी रुकावट के पूरा करने के लिए, हम क्या कर सकते हैं? हम हाथ की सफ़ाई का इस्तेमाल कर सकते हैं! धुंधलेपन की असल वैल्यू (ब्लर का दायरा) का ऐनिमेशन बनाने के बजाय, हम धुंधली कॉपी के एक जोड़े का पहले से हिसाब लगाते हैं. इसमें ब्लर करने की वैल्यू बहुत तेज़ी से बढ़ती है. इसके बाद, opacity का इस्तेमाल करके धुंधली कॉपी के बीच में क्रॉस-फ़ेड हो जाता है.

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

हमारे प्रयोगों में, हर स्टेज पर धुंधले दायरे को बढ़ाने से सबसे अच्छे विज़ुअल नतीजे मिले. उदाहरण: अगर हमारे पास ब्लर करने के चार स्टेज हैं, तो हर चरण में filter: blur(2^n) को लागू किया जाएगा. उदाहरण के लिए, चरण 0: 1 पिक्सल, स्टेज 1: 2 पिक्सल, स्टेज 2: 4 पिक्सल और चरण 3: 8 पिक्सल. अगर हम will-change: transform का इस्तेमाल करके, धुंधली की गई हर कॉपी को उसकी अपनी लेयर पर लागू करते हैं (इसे "प्रोमोटिंग" कहते हैं), तो इन एलिमेंट की ओपैसिटी में बदलाव कम-ज़्यादा होना चाहिए. सैद्धांतिक तौर पर, इसकी मदद से हम धुंधला करने के खर्चे को कम कर पाएंगे. जिससे पता चलता है कि लॉजिक सही नहीं है. यह डेमो चलाने पर, आपको दिखेगा कि फ़्रेमरेट अब भी 60 FPS (फ़्रेम प्रति सेकंड) से कम है. साथ ही, धुंधला होने की दर पहले की तुलना में बहुत खराब है.

DevTools
  यह ऐसा ट्रेस दिखाता है जिसमें जीपीयू को काफ़ी देर तक व्यस्त रखा गया है.

DevTools पर नज़र डालने से पता चलता है कि जीपीयू अब भी बहुत व्यस्त है और यह हर फ़्रेम को ~90 मि॰से॰ तक बढ़ा देता है. लेकिन क्यों? हम अब ब्लर वैल्यू में बदलाव नहीं कर रहे हैं, सिर्फ़ ओपैसिटी में बदलाव कर रहे हैं, तो क्या हो रहा है? धुंधला करने के इफ़ेक्ट में समस्या एक बार फिर होती है: जैसा कि पहले बताया गया है, अगर एलिमेंट को प्रमोट और धुंधला, दोनों किया गया है, तो जीपीयू लागू होता है. इसलिए, हम ब्लर करने की सुविधा की वैल्यू पर ज़्यादा ऐनिमेशन नहीं लगा रहे हैं. इसके बावजूद, टेक्सचर की धुंधलापन अब भी नहीं दिखती है. साथ ही, जीपीयू को हर फ़्रेम को फिर से धुंधला करना पड़ता है. फ़्रेम रेट का फ़्रेम रेट पहले से ज़्यादा खराब होने की वजह यह है कि सबसे नए को लागू करने की तुलना में, जीपीयू असल में पहले के मुकाबले ज़्यादा काम करता है. ज़्यादातर मामलों में दो तरह की ऐसी संरचना दिखती है जिन्हें अलग से धुंधला करना ज़रूरी होता है.

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

DevTools
  मौजूद है, जिससे एक ट्रेस पता चलता है कि जीपीयू को कितनी देर तक इस्तेमाल नहीं किया जा रहा.

अब हमारे पास जीपीयू पर ज़्यादा हेडरूम और 60 FPS (फ़्रेम प्रति सेकंड) वाला स्मूद फ़्रेम है. हमने कर दिखाया!

प्रोडक्शन

हमने अपने डेमो में कई बार एक DOM स्ट्रक्चर को डुप्लीकेट किया था, ताकि उस कॉन्टेंट की कॉपी कॉपी करके उसे अलग-अलग खूबियों के हिसाब से धुंधला किया जा सके. आप सोच रहे होंगे कि यह प्रोडक्शन एनवायरमेंट में कैसे काम करेगा, क्योंकि लेखक की सीएसएस स्टाइल या उनकी JavaScript पर अनचाहे तरीके से असर पड़ सकता है. सही जवाब. शैडो डीओएम डालें!

ज़्यादातर लोग Shadow DOM को अपने कस्टम एलिमेंट में "इंटरनल" एलिमेंट जोड़ने के तरीके के तौर पर देखते हैं. हालांकि, यह आइसोलेशन और परफ़ॉर्मेंस की शुरुआती प्रक्रिया भी है! JavaScript और सीएसएस, Shadow DOM की सीमाओं में बदलाव नहीं कर सकते. इससे हम डेवलपर की स्टाइल या ऐप्लिकेशन लॉजिक में रुकावट डाले बिना, कॉन्टेंट को डुप्लीकेट कर पाते हैं. हमारे पास हर कॉपी के लिए, <div> एलिमेंट पहले से मौजूद है, ताकि उसे रास्टराइज़ किया जा सके. अब इन <div> का इस्तेमाल शैडो होस्ट के तौर पर किया जाता है. हम attachShadow({mode: 'closed'}) का इस्तेमाल करके ShadowRoot बनाते हैं और <div> के बजाय, ShadowRoot में कॉन्टेंट की एक कॉपी अटैच कर देते हैं. हमें यह पक्का करना होगा कि सभी स्टाइलशीट को ShadowRoot में भी कॉपी किया जाए, ताकि इस बात की गारंटी दी जा सके कि हमारी कॉपी, ओरिजनल कॉपी की तरह ही स्टाइल की गई हैं.

कुछ ब्राउज़र Shadow DOM v1 का इस्तेमाल नहीं करते और उनके लिए हम सिर्फ़ कॉन्टेंट को डुप्लीकेट करते हैं और उम्मीद करते हैं कि कुछ भी खराब न हो. हम ShadyCSS के साथ Shadow DOM polyfill का इस्तेमाल कर सकते हैं, लेकिन हमने लाइब्रेरी में इसे लागू नहीं किया.

बस काम हो गया. Chrome की रेंडरिंग पाइपलाइन पर आगे बढ़ने के बाद, हमने जाना कि हम सभी ब्राउज़र में ब्लर को बेहतर ढंग से कैसे ऐनिमेट कर सकते हैं!

नतीजा

इस तरह के इफ़ेक्ट का इस्तेमाल हल्के से नहीं किया जाना चाहिए. हम डीओएम एलिमेंट को कॉपी करके, उन्हें उनके लेयर पर फ़ोर्स करते हैं, इस वजह से हम कम सुविधाओं वाले डिवाइसों की सीमा बढ़ा सकते हैं. हर ShadowRoot में सभी स्टाइलशीट कॉपी करने से, परफ़ॉर्मेंस का भी जोखिम हो सकता है. इसलिए, आपको यह तय करना चाहिए कि क्या अपने लॉजिक और स्टाइल में बदलाव करके, LightDOM में मौजूद कॉपी का असर न पड़े या हमारी ShadowDOM तकनीक का इस्तेमाल किया जाए. हालांकि, कभी-कभी हमारी तकनीक का इस्तेमाल करना फ़ायदेमंद साबित हो सकता है. हमारे GitHub रिपॉज़िटरी के कोड और डेमो पर एक नज़र डालें. अगर आपका कोई सवाल है, तो हमसे Twitter पर संपर्क करें!