पॉलिमर के साथ शमशेर-ए-रोशनी बनाना

Lightsaber का स्क्रीनशॉट

खास जानकारी

हमने Polymer का इस्तेमाल करके, बेहतर परफ़ॉर्म करने वाला WebGL मोबाइल कंट्रोल कैसे बनाया लाइटसेबर जिसे मॉड्यूलर और कॉन्फ़िगर किया जा सकता है. हम कुछ अहम जानकारी की समीक्षा करते हैं https://lightsaber.withgoogle.com/ पर जाकर ताकि अगली बार आपको गेम का पैकेट बनाने के साथ ही, अपना समय बचाने में भी मदद मिल सके गुस्सैल स्टॉर्मट्रूपर.

खास जानकारी

अगर आपको यह जानना है कि पॉलीमर या वेबकॉम्पोनेंट क्या है, तो तो सबसे अच्छा होगा कि काम करने वाले किसी असल प्रोजेक्ट का डेटा शेयर करके शुरुआत करें. यहां हमारे प्रोजेक्ट के लैंडिंग पेज से लिया गया सैंपल दिया गया है https://lightsaber.withgoogle.com. यह समय है एक सामान्य एचटीएमएल फ़ाइल है, लेकिन उसके अंदर कुछ जादू है:

<!-- Element-->
<dom-module id="sw-page-landing">
    <!-- Template-->
    <template>
    <style>
        <!-- include elements/sw/pages/sw-page-landing/styles/sw-page-landing.css-->
    </style>
    <div class="centered content">
        <sw-ui-logo></sw-ui-logo>
        <div class="connection-url-wrapper">
        <sw-t key="landing.type" class="type"></sw-t>
        <div id="url" class="connection-url">.</div>
        <sw-ui-toast></sw-ui-toast>
        </div>
    </div>
    <div class="disclaimer epilepsy">
        <sw-t key="disclaimer.epilepsy" class="type"></sw-t>
    </div>
    <sw-ui-footer state="extended"></sw-ui-footer>
    </template>
    <!-- Polymer element script-->
    <script src="scripts/sw-page-landing.js"></script>
</dom-module>

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

पॉलिमर के साथ मॉड्यूलेरिटी

Polymer एक ऐसी लाइब्रेरी है जो दोबारा इस्तेमाल किए जा सकने वाले कस्टम एलिमेंट से आपके प्रोजेक्ट को बनाने में काफ़ी मदद मिलती है. यह आपको अपने सॉफ़्टवेयर में मौजूद सिंगल एचटीएमएल फ़ाइल का इस्तेमाल करता है. इनमें सिर्फ़ स्ट्रक्चर (एचटीएमएल मार्कअप) ही नहीं, बल्कि इनलाइन स्टाइल और लॉजिक के हिसाब से बनाया जा सकता है.

यहां दिया गया उदाहरण देखें:

<link rel="import" href="bower_components/polymer/polymer.html">

<dom-module id="picture-frame">
    <template>
    <!-- scoped CSS for this element -->
    <style>
        div {
        display: inline-block;
        background-color: #ccc;
        border-radius: 8px;
        padding: 4px;
        }
    </style>
    <div>
        <!-- any children are rendered here -->
        <content></content>
    </div>
    </template>

    <script>
    Polymer({
        is: "picture-frame",
    });
    </script>
</dom-module>

हालांकि, एक बड़े प्रोजेक्ट के लिए, इन तीन लॉजिकल तरीकों को कॉम्पोनेंट (एचटीएमएल, सीएसएस, JS) अलग-अलग होंगे और कंपाइल करते समय सिर्फ़ उन्हें मर्ज किया जाएगा. तो एक बात हमने प्रोजेक्ट के हर एलिमेंट को उसका अलग फ़ोल्डर दिया था:

src/elements/
|-- elements.jade
`-- sw
    |-- debug
    |   |-- sw-debug
    |   |-- sw-debug-performance
    |   |-- sw-debug-version
    |   `-- sw-debug-webgl
    |-- experience
    |   |-- effects
    |   |-- sw-experience
    |   |-- sw-experience-controller
    |   |-- sw-experience-engine
    |   |-- sw-experience-input
    |   |-- sw-experience-model
    |   |-- sw-experience-postprocessor
    |   |-- sw-experience-renderer
    |   |-- sw-experience-state
    |   `-- sw-timer
    |-- input
    |   |-- sw-input-keyboard
    |   `-- sw-input-remote
    |-- pages
    |   |-- sw-page-calibration
    |   |-- sw-page-connection
    |   |-- sw-page-connection-error
    |   |-- sw-page-error
    |   |-- sw-page-experience
    |   `-- sw-page-landing
    |-- sw-app
    |   |-- bower.json
    |   |-- scripts
    |   |-- styles
    |   `-- sw-app.jade
    |-- system
    |   |-- sw-routing
    |   |-- sw-system
    |   |-- sw-system-audio
    |   |-- sw-system-config
    |   |-- sw-system-environment
    |   |-- sw-system-events
    |   |-- sw-system-remote
    |   |-- sw-system-social
    |   |-- sw-system-tracking
    |   |-- sw-system-version
    |   |-- sw-system-webrtc
    |   `-- sw-system-websocket
    |-- ui
    |   |-- experience
    |   |-- sw-preloader
    |   |-- sw-sound
    |   |-- sw-ui-button
    |   |-- sw-ui-calibration
    |   |-- sw-ui-disconnected
    |   |-- sw-ui-final
    |   |-- sw-ui-footer
    |   |-- sw-ui-help
    |   |-- sw-ui-language
    |   |-- sw-ui-logo
    |   |-- sw-ui-mask
    |   |-- sw-ui-menu
    |   |-- sw-ui-overlay
    |   |-- sw-ui-quality
    |   |-- sw-ui-select
    |   |-- sw-ui-toast
    |   |-- sw-ui-toggle-screen
    |   `-- sw-ui-volume
    `-- utils
        `-- sw-t

और हर एलिमेंट के फ़ोल्डर का अंदरूनी स्ट्रक्चर एक जैसा होता है. साथ ही, लॉजिक (कॉफ़ी फ़ाइलें), स्टाइल (सीएसएस फ़ाइलें) और टेंप्लेट (जेड फ़ाइल).

यहां sw-ui-logo एलिमेंट का एक उदाहरण दिया गया है:

sw-ui-logo/
|-- bower.json
|-- scripts
|   `-- sw-ui-logo.coffee
|-- styles
|   `-- sw-ui-logo.scss
`-- sw-ui-logo.jade

और अगर आप .jade फ़ाइल में देखें:

// Element
dom-module(id='sw-ui-logo')

    // Template
    template
    style
        include elements/sw/ui/sw-ui-logo/styles/sw-ui-logo.css

    img(src='[[url]]')

    // Polymer element script
    script(src='scripts/sw-ui-logo.js')

स्टाइल शामिल करके यह देखा जा सकता है कि चीज़ों को कैसे व्यवस्थित किया गया है और लॉजिक की मदद से बनाया जा सकता है. हमारे पॉलिमर में हमारी शैलियों को शामिल करने के लिए एलिमेंट में, हम जेड के include स्टेटमेंट का इस्तेमाल करते हैं. इसलिए, हमारे पास असली इनलाइन सीएसएस है कंपाइलेशन के बाद फ़ाइल सामग्री. sw-ui-logo.js स्क्रिप्ट एलिमेंट यह काम करेगा रनटाइम पर एक्ज़ीक्यूट होता है.

Bower के साथ मॉड्यूलर डिपेंडेंसी

आम तौर पर, हम लाइब्रेरी और अन्य डिपेंडेंसी को प्रोजेक्ट लेवल पर रखते हैं. हालांकि, ऊपर दिए गए सेटअप में आपको एक bower.json दिखाई देगा, जो एलिमेंट फ़ोल्डर: एलिमेंट लेवल डिपेंडेंसी. इस रणनीति के पीछे का आइडिया यह है कि ऐसी स्थिति में जब आपके पास अलग-अलग एलिमेंट के साथ डिपेंडेंसी हम पक्का कर सकते हैं कि सिर्फ़ वे डिपेंडेंसी लोड हों जो इस्तेमाल किया गया है. साथ ही, अगर किसी एलिमेंट को हटाया जाता है, तो आपको इसकी डिपेंडेंसी हटाएं, क्योंकि आपने bower.json फ़ाइल भी हटा दी होगी जो इन डिपेंडेंसी के बारे में बताता है. हर एलिमेंट, पेज को अलग-अलग लोड करता है डिपेंडेंसी जो इससे जुड़ी होती हैं.

हालांकि, डिपेंडेंसी के डुप्लीकेट से बचने के लिए, हम .bowerrc फ़ाइल शामिल करते हैं फ़ोल्डर में भी मिल सकती है. इससे बोवर को यह पता चलता है कि उसे कहां स्टोर करना है डिपेंडेंसी, ताकि हम यह पक्का कर सकें कि एक ही डायरेक्ट्री:

{
    "directory" : "../../../../../bower_components"
}

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

बैश स्क्रिप्ट, नेस्ट किए गए एलिमेंट स्ट्रक्चर में सभी bower.json फ़ाइलें ढूंढती है. इसके बाद, यह इन डायरेक्ट्री को एक-एक करके डालता है और bower install को हर स्थिति के लिए:

echo installing bower components...
modules=$(find /vagrant/app -type f -name "bower.json" -not -path "*node_modules*" -not -path "*bower_components*")
for module in $modules; do
    pushd $(dirname $module)
    bower install --allow-root -q
    popd
done

क्विक न्यू एलिमेंट टेंप्लेट

जब भी आप नया एलीमेंट बनाना चाहते हैं, तो इसमें कुछ समय लगता है: फ़ोल्डर और बेसिक फ़ाइल स्ट्रक्चर को सही नामों के साथ सबमिट करें. इसलिए, हम आसानी से एलिमेंट जनरेटर लिखने के लिए, स्लश करें.

कमांड लाइन से स्क्रिप्ट को कॉल किया जा सकता है:

$ slush element path/to/your/element-name

और नया एलिमेंट बन जाता है, जिसमें फ़ाइल का पूरा स्ट्रक्चर और कॉन्टेंट शामिल होता है.

हमने एलिमेंट फ़ाइलों के लिए टेंप्लेट तय किए हैं, जैसे कि .jade फ़ाइल टेंप्लेट ऐसा दिखता है:

// Element
dom-module(id='<%= name %>')

    // Template
    template
    style
        include elements/<%= path %>/styles/<%= name %>.css

    span This is a '<%= name %>' element.

    // Polymer element script
    script(src='scripts/<%= name %>.js')

स्लश जनरेटर, वैरिएबल को असल एलिमेंट पाथ और नामों से बदल देता है.

एलिमेंट बनाने के लिए गल्प का इस्तेमाल करना

Gulp, बिल्ड प्रोसेस को कंट्रोल में रखता है. और हमारी संरचना में, जिन एलिमेंट की ज़रूरत हमें गल्प की ज़रूरत होती है, वे नीचे दिए गए चरणों को पूरा करते हैं:

  1. एलिमेंट कंपाइल करें' .js के लिए .coffee फ़ाइलें
  2. एलिमेंट कंपाइल करें' .css के लिए .scss फ़ाइलें
  3. एलिमेंट कंपाइल करें' .html में .jade फ़ाइलें, .css फ़ाइलें एम्बेड की जा रही हैं.

ज़्यादा जानकारी:

एलिमेंट कंपाइल करना' .js के लिए .coffee फ़ाइलें

gulp.task('elements-coffee', function () {
    return gulp.src(abs(config.paths.app + '/elements/**/*.coffee'))
    .pipe($.replaceTask({
        patterns: [{json: getVersionData()}]
    }))
    .pipe($.changed(abs(config.paths.static + '/elements'), {extension: '.js'}))
    .pipe($.coffeelint())
    .pipe($.coffeelint.reporter())
    .pipe($.sourcemaps.init())
    .pipe($.coffee({
    }))
    .on('error', gutil.log)
    .pipe($.sourcemaps.write())
    .pipe(gulp.dest(abs(config.paths.static + '/elements')));
});

दूसरे और तीसरे चरण में, हम scss को कंपाइल करने के लिए गल्प और कंपास प्लगिन का इस्तेमाल करते हैं .css और .jade से .html तक, उसी तरह ऊपर 2 के मामले में.

इसमें पॉलिमर एलिमेंट शामिल हैं

असल में, पॉलिमर एलिमेंट को शामिल करने के लिए, हम एचटीएमएल इंपोर्ट का इस्तेमाल करते हैं.

<link rel="import" href="elements.html">

<!-- Polymer -->
<link rel="import" href="../bower_components/polymer/polymer.html">

<!-- Custom elements -->
<link rel="import" href="sw/sw-app/sw-app.html">
<link rel="import" href="sw/system/sw-system/sw-system.html">
<link rel="import" href="sw/system/sw-routing/sw-routing.html">
<link rel="import" href="sw/system/sw-system-version/sw-system-version.html">
<link rel="import" href="sw/system/sw-system-environment/sw-system-environment.html">
<link rel="import" href="sw/pages/sw-page-landing/sw-page-landing.html">
<link rel="import" href="sw/pages/sw-page-connection/sw-page-connection.html">
<link rel="import" href="sw/pages/sw-page-calibration/sw-page-calibration.html">
<link rel="import" href="sw/pages/sw-page-experience/sw-page-experience.html">
<link rel="import" href="sw/ui/sw-preloader/sw-preloader.html">
<link rel="import" href="sw/ui/sw-ui-overlay/sw-ui-overlay.html">
<link rel="import" href="sw/ui/sw-ui-button/sw-ui-button.html">
<link rel="import" href="sw/ui/sw-ui-menu/sw-ui-menu.html">

प्रोडक्शन के लिए पॉलिमर एलिमेंट ऑप्टिमाइज़ करना

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

Vulcanize एक पॉलिमर टूल है डिपेंडेंसी ट्री को एक html फ़ाइल में फ़्लैट करता है, जिससे अनुरोधों की संख्या. यह विशेष रूप से उन ब्राउज़र के लिए बढ़िया है जो वेब कॉम्पोनेंट के साथ काम करता है.

सीएसपी (कॉन्टेंट की सुरक्षा के बारे में नीति) और पॉलीमर

सुरक्षित वेब ऐप्लिकेशन बनाते समय, आपको सीएसपी लागू करना होगा. सीएसपी ऐसे नियमों का एक सेट है जो क्रॉस-साइट स्क्रिप्टिंग (XSS) हमलों को रोकता है: असुरक्षित सोर्स से स्क्रिप्ट चलाना या इनलाइन स्क्रिप्ट चलाना को एचटीएमएल फ़ाइलों से हटाएं.

अब ऑप्टिमाइज़ की गई, छोटी की गई, और छोटी की गई .html फ़ाइल जनरेट की गई Vulcanize के सभी JavaScript कोड को सीएसपी के साथ काम न करने वाले कोड के साथ इनलाइन बनाया गया है फ़ॉर्मैट. इसे ठीक करने के लिए, हम क्रिस्पर.

क्रिस्पर किसी एचटीएमएल फ़ाइल से इनलाइन स्क्रिप्ट को बांटता है और उन्हें एक सिंगल, सीएसपी अनुपालन के लिए बाहरी JavaScript फ़ाइल. इसलिए, हमने दुनिया भर के Crisper के ज़रिए एचटीएमएल फ़ाइल अपलोड करने पर, आपको दो फ़ाइलें मिलती हैं: elements.html और elements.js. elements.html के अंदर, elements.js जनरेट हुआ.

ऐप्लिकेशन लॉजिकल स्ट्रक्चर

पॉलिमर में, एलिमेंट कुछ भी हो सकता है. जैसे, नॉन-विज़ुअल यूटिलिटी एलिमेंट या छोटे एलिमेंट अलग-अलग और फिर से इस्तेमाल किए जा सकने वाले यूज़र इंटरफ़ेस (यूआई) एलिमेंट (जैसे, बटन) से लेकर बड़े मॉड्यूल जैसे "पेज" पूरी तरह से आवेदन करने में भी मदद मिलती है.

ऐप्लिकेशन का टॉप-लेवल लॉजिकल स्ट्रक्चर
हमारे ऐप्लिकेशन का टॉप-लेवल लॉजिकल स्ट्रक्चर पॉलीमर एलिमेंट.

पॉलिमर और पैरंट-चाइल्ड आर्किटेक्चर के साथ पोस्टप्रोसेसिंग

किसी भी 3D ग्राफ़िक्स पाइपलाइन में, हमेशा एक अंतिम चरण होता है, जहां इन्हें पूरी तस्वीर के ऊपर एक तरह के ओवरले के तौर पर जोड़ा जाता है. यह है जिसमें चमक, गॉड-रे, फ़ील्ड की डेप्थ, बोकेह, ब्लर वगैरह. इन इफ़ेक्ट को मिलाकर इस्तेमाल किया जाता है और इन पर लागू किया जाता है अलग-अलग एलिमेंट तैयार करता है. THREE.js में, हमने JavaScript में पोस्ट-प्रोसेसिंग के लिए कस्टम शेडर बना सकता है या हम Polymer की मदद से यह कर सकते हैं, क्योंकि इसके पैरंट-चाइल्ड स्ट्रक्चर की वजह से ऐसा किया जा सकता है.

हमारे पोस्ट-प्रोसेसर के एलिमेंट का एचटीएमएल कोड देखने पर:

<dom-module id="sw-experience-postprocessor">
    <!-- Template-->
    <template>
    <sw-experience-effect-bloom class="effect"></sw-experience-effect-bloom>
    <sw-experience-effect-dof class="effect"></sw-experience-effect-dof>
    <sw-experience-effect-vignette class="effect"></sw-experience-effect-vignette>
    </template>
    <!-- Polymer element script-->
    <script src="scripts/sw-experience-postprocessor.js"></script>
</dom-module>

हम इफ़ेक्ट को कॉमन क्लास के तहत, नेस्ट किए गए पॉलिमर एलिमेंट के तौर पर तय करते हैं. इसके बाद, sw-experience-postprocessor.js में हम ऐसा करते हैं:

effects = @querySelectorAll '.effect'
@composer.addPass effect.getPass() for effect in effects

हम एचटीएमएल सुविधा और JavaScript की querySelectorAll का इस्तेमाल करके, सभी पोस्ट प्रोसेसर में, एचटीएमएल एलिमेंट के तौर पर नेस्ट किए गए इफ़ेक्ट, क्रम में जिनमें वे शामिल थे. इसके बाद, हम उन्हें दोहराते हैं और उन्हें कंपोज़र में जोड़ देते हैं.

अब मान लीजिए कि हम डीओएफ़ (फ़ील्ड की गहराई) इफ़ेक्ट को हटाना चाहते हैं और फूल और विनेट इफ़ेक्ट का क्रम बदल सकता है. हमें बस बदलाव करना है पोस्ट-प्रोसेसर की परिभाषा इस तरह है:

<dom-module id="sw-experience-postprocessor">
    <!-- Template-->
    <template>
    <sw-experience-effect-vignette class="effect"></sw-experience-effect-vignette>
    <sw-experience-effect-bloom class="effect"></sw-experience-effect-bloom>
    </template>
    <!-- Polymer element script-->
    <script src="scripts/sw-experience-postprocessor.js"></script>
</dom-module>

और वास्तविक कोड की एक भी लाइन बदले बिना, सीन बस चलेगा.

Polymer में लूप और अपडेट लूप को रेंडर करें

Polymer की मदद से, हम रेंडरिंग और इंजन अपडेट को भी शानदार तरीके से कर सकते हैं. हमने एक timer एलिमेंट बनाया है, जो requestAnimationFrame का इस्तेमाल करता है और कंप्यूट करता है मौजूदा समय (t) और डेल्टा समय जैसे मान - इस समय से बीता हुआ समय पिछला फ़्रेम (dt):

Polymer
    is: 'sw-timer'

    properties:
    t:
        type: Number
        value: 0
        readOnly: true
        notify: true
    dt:
        type: Number
        value: 0
        readOnly: true
        notify: true

    _isRunning: false
    _lastFrameTime: 0

    ready: ->
    @_isRunning = true
    @_update()

    _update: ->
    if !@_isRunning then return
    requestAnimationFrame => @_update()
    currentTime = @_getCurrentTime()
    @_setT currentTime
    @_setDt currentTime - @_lastFrameTime
    @_lastFrameTime = @_getCurrentTime()

    _getCurrentTime: ->
    if window.performance then performance.now() else new Date().getTime()

इसके बाद, हम t और dt प्रॉपर्टी को अपने इंजन (experience.jade):

sw-timer(
    t='{ % templatetag openvariable % }t}}',
    dt='{ % templatetag openvariable % }dt}}'
)

sw-experience-engine(
    t='[t]',
    dt='[dt]'
)

और हम इंजन में t और dt के बदलावों को सुनते हैं और जब भी मान बदलने के बाद, _update फ़ंक्शन को कॉल किया जाएगा:

Polymer
    is: 'sw-experience-engine'

    properties:
    t:
        type: Number

    dt:
        type: Number

    observers: [
    '_update(t)'
    ]

    _update: (t) ->
    dt = @dt
    @_physics.update dt, t
    @_renderer.render dt, t

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

sw-timer.coffee:

addUpdateListener: (listener) ->
    if @_updateListeners.indexOf(listener) == -1
    @_updateListeners.push listener
    return

removeUpdateListener: (listener) ->
    index = @_updateListeners.indexOf listener
    if index != -1
    @_updateListeners.splice index, 1
    return

_update: ->
    # ...
    for listener in @_updateListeners
        listener @dt, @t
    # ...

addUpdateListener फ़ंक्शन एक कॉलबैक स्वीकार करता है और उसे कॉलबैक अरे. इसके बाद, अपडेट लूप में, हम हर कॉलबैक को दोहराते हैं और हम डेटा बाइंडिंग को बायपास करते हुए, उसे सीधे dt और t आर्ग्युमेंट के साथ एक्ज़ीक्यूट करते हैं या इवेंट ट्रिगर होने में मदद मिलती है. जब कॉलबैक चालू न हो, तब हमने removeUpdateListener फ़ंक्शन, जो आपको पहले जोड़े गए कॉलबैक को हटाने देता है.

THREE.js में एक शमशेर-ए-रोशनी

THREE.js, WebGL के निम्न स्तर की जानकारी को हटा देता है और हमें फ़ोकस करने देता है समस्या पर ध्यान दें. हमारी समस्या स्टॉर्मट्रूपर्स से लड़ रही है और हमें हथियार. तो चलो एक शमशेर-ए-रोशनी बनाते हैं.

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

द ब्लेड

ब्लेड दो सब ब्लेड से बना होता है. अंदर और बाहर. दोनों THREE.js मेश हैं और इनकी सामग्री का इस्तेमाल किया जाता है.

इनर ब्लेड

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

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

इनर ब्लेड ग्लो

नीचे दिए गए स्रोत से पता चलता है कि हम तीव्रता कंट्रोल करने के लिए vFactor का हिसाब कैसे लगाते हैं इसके बाद, वर्टेक्स शेडर में जाकर, इसका इस्तेमाल सीन के साथ ब्लेंड करने के लिए करें फ़्रैगमेंट शेडर.

THREE.LaserShader = {

    uniforms: {
    "uPointA": {type: "v3", value: new THREE.Vector3(0, -1, 0)},
    "uPointB": {type: "v3", value: new THREE.Vector3(0, 1, 0)},
    "uColor": {type: "c", value: new THREE.Color(1, 0, 0)},
    "uMultiplier": {type: "f", value: 3.0},
    "uCoreColor": {type: "c", value: new THREE.Color(1, 1, 1)},
    "uCoreOpacity": {type: "f", value: 0.8},
    "uLowerBound": {type: "f", value: 0.4},
    "uUpperBound": {type: "f", value: 0.8},
    "uTransitionPower": {type: "f", value: 2},
    "uNearPlaneValue": {type: "f", value: -0.01}
    },

    vertexShader: [

    "uniform vec3 uPointA;",
    "uniform vec3 uPointB;",
    "uniform float uMultiplier;",
    "uniform float uNearPlaneValue;",
    "varying float vFactor;",

    "float getDistanceFromAB(vec2 a, vec2 b, vec2 p) {",

        "vec2 l = b - a;",
        "float l2 = dot( l, l );",
        "float t = dot( p - a, l ) / l2;",
        "if( t < 0.0 ) return distance( p, a );",
        "if( t > 1.0 ) return distance( p, b );",
        "vec2 projection = a + (l * t);",
        "return distance( p, projection );",

    "}",

    "vec3 getIntersection(vec4 a, vec4 b) {",

        "vec3 p = a.xyz;",
        "vec3 q = b.xyz;",
        "vec3 v = normalize( q - p );",
        "float t = ( uNearPlaneValue - p.z ) / v.z;",
        "return p + (v * t);",

    "}",

    "void main() {",

        "vec4 a = modelViewMatrix * vec4(uPointA, 1.0);",
        "vec4 b = modelViewMatrix * vec4(uPointB, 1.0);",
        "if(a.z > uNearPlaneValue) a.xyz = getIntersection(a, b);",
        "if(b.z > uNearPlaneValue) b.xyz = getIntersection(a, b);",
        "a = projectionMatrix * a; a /= a.w;",
        "b = projectionMatrix * b; b /= b.w;",
        "vec4 p = projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
        "gl_Position = p;",
        "p /= p.w;",
        "float d = getDistanceFromAB(a.xy, b.xy, p.xy) * gl_Position.z;",
        "vFactor = 1.0 - clamp(uMultiplier * d, 0.0, 1.0);",

    "}"

    ].join( "\n" ),

    fragmentShader: [

    "uniform vec3 uColor;",
    "uniform vec3 uCoreColor;",
    "uniform float uCoreOpacity;",
    "uniform float uLowerBound;",
    "uniform float uUpperBound;",
    "uniform float uTransitionPower;",
    "varying float vFactor;",

    "void main() {",

        "vec4 col = vec4(uColor, vFactor);",
        "float factor = smoothstep(uLowerBound, uUpperBound, vFactor);",
        "factor = pow(factor, uTransitionPower);",
        "vec4 coreCol = vec4(uCoreColor, uCoreOpacity);",
        "vec4 finalCol = mix(col, coreCol, factor);",
        "gl_FragColor = finalCol;",

    "}"

    ].join( "\n" )

};

द आउटर ब्लेड ग्लो

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

आउटर ब्लेड

लाइटसेबर ट्रेल

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

शमशेर-ए-रोशनी वाला रास्ता बाईं ओर
लाइटसेबर ट्रेल दाईं ओर

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

पूरी पगडंडी

रास्ते के चारों ओर चमक

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

रोशनी से जगमगाता रास्ता

नतीजा

Polymer एक बेहद मज़बूत लाइब्रेरी और कॉन्सेप्ट है (जैसा कि Webcomponents में होता है सामान्य). यह सिर्फ़ आप पर निर्भर करता है कि आप इससे क्या बनाते हैं. यह यहाँ से कुछ भी हो सकता है: एक पूर्ण आकार के WebGL ऐप्लिकेशन का आसान यूज़र इंटरफ़ेस (यूआई) बटन है. पिछले चैप्टर में हमने आपको Polymer ऐप्लिकेशन का बेहतर तरीके से इस्तेमाल करने के कुछ सुझाव और तरकीबें दिखाई हैं और ऐसे जटिल मॉड्यूल को स्ट्रक्चर करने का तरीका जानें जो बेहतर परफ़ॉर्म कर सकें करते हैं. हमने आपको WebGL में एक सुंदर दिखने वाले लाइटसेबर पाने का तरीका भी दिखाया. इसलिए, इन सभी को मिलाने पर, अपने पॉलीमर एलिमेंट को Vulcanize याद रखें और अगर आप Crisper का इस्तेमाल करना न भूलें, तो अगर आप सीएसपी का पालन करना चाहते हैं, तो सहायता करने के लिए हमारी सहायता लें!

गेम प्ले