Polimer ile Işın Kılıcı Oluşturma

Işın kılıcı ekran görüntüsü

Özet

Mobil kontrollü yüksek performanslı bir WebGL web sitesi oluşturmak için Polymer'i nasıl kullandık? Modüler ve yapılandırılabilir ışın kılıcı. Bir dahaki sefere öfkeli Stormtrooper'lara rastladığınızda kendi ışın kılıcınızı oluştururken zaman kazanmanıza yardımcı olmak için https://lightsaber.withgoogle.com/ projemizin bazı önemli ayrıntılarını inceliyoruz.

Genel Bakış

Polymer veya WebComponents'in ne olduğunu merak ediyorsanız gerçek bir çalışma projesinden bir kesit paylaşarak başlamanın en iyi olacağını düşündük. Burada projemizin açılış sayfasından alınmış bir örnek https://lightsaber.withgoogle.com. İnsanların içeren, normal bir HTML dosyası oluşturun, ancak içinde biraz sihir var:

<!-- 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>

Bu nedenle, günümüzde HTML5 tabanlı bir uygulama oluşturmak için birçok seçenek mevcuttur. API'ler, Çerçeveler, Kitaplıklar, Oyun Motorları vb. Tüm seçeneklere rağmen kaliteli ve uygun bir kurulum bulmak zor. yüksek performanslı grafik performansı ile temiz modüler yapı ve ölçeklenebilirlik. Polymer'in çevreyi korumamıza yardımcı olabileceğini düşük düzeyli performansa izin verecek şekilde organize edilmişse parçalama şeklimizi dikkatli bir şekilde oluşturduk. bileşenlerine ayırmanızı sağlar.

Polimer ile Modülerlik

Polymer, bir ve yeniden kullanılabilir özel öğelerden projenizin oluşturulma şekli üzerinde çok fazla güce sahip olmanız gerekir. Tek bir pakette bulunan bağımsız, tam işlevli modülleri kullanmanıza olanak tanır. tek HTML dosyası olabilir. Bunlar, yalnızca yapıyı (HTML işaretlemesi) değil, satır içi stiller ve mantık.

Aşağıdaki örneği inceleyin:

<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>

Ama daha büyük bir projede bu üç mantıksal (HTML, CSS, JS) düzenleyebilir ve yalnızca derleme sırasında birleştirir. Tek bir nokta projedeki her öğeye ayrı birer klasör vermek istedik:

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

Her bir öğenin klasörü, aynı iç yapıya sahiptir ve ayrı ayrı öğeler mantık (kahve dosyaları), stiller (scss dosyaları) ve şablonunu (yeşim dosyası) tıklayın.

Aşağıda örnek bir sw-ui-logo öğesi verilmiştir:

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

.jade dosyasına bakarsanız:

// 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')

Stilleri kullanarak öğelerin nasıl düzenli bir şekilde düzenlendiğini görebilirsiniz mantığı ve bunu kullanır. Stillerimizi Polymer öğelerimize dahil etmek için Jade'ın include ifadesini kullanırız. Böylece derleme işleminden sonra gerçek satır içi CSS dosya içeriğine sahip oluruz. sw-ui-logo.js komut dosyası öğesi, çalışma zamanında yürütür.

Bower ve Modüler Bağımlılıklar

Normalde kitaplıkları ve diğer bağımlılıkları proje düzeyinde tutarız. Ancak yukarıdaki kurulumda, öğenin klasöründe bir bower.json olduğunu fark edeceksiniz: öğe düzeyinde bağımlılıklar. Bu yaklaşımın arkasındaki fikir, farklı bağımlılıklara sahip çok sayıda öğenizin olduğu bir durumda yalnızca gerçekten kullanılan bağımlılıkları yüklediğinizden emin olabilmenizdir. Bir öğeyi kaldırdığınızda, bower.json dosyasını da kaldırmış olacağınızdan bağımlılığını kaldırın açıklayacağım. Her öğe, kendisiyle ilgili bağımlılıkları bağımsız olarak yükler.

Bununla birlikte, bağımlılıkların yinelenmesini önlemek için bir .bowerrc dosyası ekleriz. her bir öğenin klasöründe de bulabilirsiniz. Bu, çarşafın nereye saklanacağını gösterir Böylece aynı projenin sonunda yalnızca bir tane olduğundan emin olabiliriz. dizin:

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

Bu sayede, birden fazla öğe THREE.js'ü bağımlılık olarak belirtirse bower, öğeyi ilk öğe için yükledikten ve ikinci öğeyi ayrıştırmaya başladıktan sonra bu bağımlığın zaten yüklü olduğunu anlar ve öğeyi yeniden indirmez veya kopyalama yapmaz. Benzer şekilde, bu bağımlılığın öğe tanımlamaya devam eden en az bir öğe olduğu sürece dosyaları, bower.json.

Bir bash komut dosyası, iç içe yerleştirilmiş öğe yapısındaki tüm bower.json dosyalarını bulur. Daha sonra bu dizinleri tek tek girer ve bower install komutunu her biri:

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

Hızlı Yeni Öğe Şablonu

Yeni bir öğe oluşturmak istediğiniz her seferde biraz zaman alır. klasör ve temel dosya yapısının doğru adlara sahip olmasını sağlayın. Bu yüzden, Basit bir öğe oluşturucu yazmak için Slush.

Komut dosyasını, komut satırından çağırabilirsiniz:

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

Tüm dosya yapısı ve içeriği de dahil olmak üzere yeni öğe oluşturulur.

Öğe dosyaları için şablonlar tanımladık. Örneğin, .jade dosya şablonu aşağıdaki gibi görünür:

// 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')

Slush oluşturucu, değişkenleri gerçek öğe yolları ve adlarıyla değiştirir.

Nesne Oluşturmak için Gulp Kullanma

Gulp, derleme işlemini kontrol altında tutar. Yapımızda, öğeleri oluşturmak için Gulp'un aşağıdaki adımları uygulaması gerekir:

  1. Öğeleri derleyin .js hedefine .coffee dosya
  2. Öğeleri derleyin .css hedefine .scss dosya
  3. Öğeleri derleyin .jade dosya, .html hedefine .css dosya yerleştiriliyor.

Daha ayrıntılı olarak:

Öğeleri derleme .js hedefine .coffee dosya

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')));
});

2. ve 3. adımlarda scss öğesini aşağıdaki türlerde derlemek için gulp ve bir pusula eklentisi kullanırız: .css ve .jade, yukarıdaki 2'ye benzer bir yaklaşımla .html içine atanır.

Polimer Öğeler Dahil

Polimer öğelerini eklemek için HTML içe aktarmalarını kullanırız.

<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">

Polimer öğelerini üretim için optimize etme

Büyük bir projede çok fazla Polymer öğe olabilir. Şurada: elliden fazla örnek verilebilir. Her öğenin kendine özgü bir ayrı .js dosyası ve bazı kitaplıklara referansta bulunursanız bu dosya 100 ayrı dosya. Bu, tarayıcının yapması gereken çok sayıda istek performans kaybı yaşanır. Benzer şekilde, bir süreci tamamlamak için bir Angular yapısına başvuracak olursak, Polymer projesini sonlandırılması gerekir.

Vulcanize, bağımlılık ağacını tek bir HTML dosyasına düzleştirerek istek sayısını azaltan bir Polymer aracıdır. Bu özellik, özellikle web bileşenlerini doğal olarak desteklemeyen tarayıcılar için idealdir.

CSP (İçerik Güvenliği Politikası) ve Polymer

Güvenli web uygulamaları geliştirirken CSP'yi uygulamanız gerekir. CSP siteler arası komut dosyası çalıştırma (XSS) saldırılarını engelleyen bir kurallar kümesidir: güvenli olmayan kaynaklardan komut dosyalarının yürütülmesi veya satır içi komut dosyalarının çalıştırılması başka bir dosya türü olabilir.

Optimize edilmiş, birleştirilmiş ve küçültülmüş .html dosyası oluşturuldu tarafından sunulan Vulcanize, tüm JavaScript kodunu CSP uyumlu olmayan bir satır içi olarak biçimindedir. Bu sorunu gidermek için Crisper.

Crisper, bir HTML dosyasından satır içi komut dosyalarını böler ve bunları tek bir komut dosyasına yerleştirir. CSP uyumluluğu için harici JavaScript dosyası. Bu nedenle, vulkanize bir HTML dosyası oluşturacaksınız ve sonuçta iki dosya olacak: elements.html ve elements.js. elements.html içinde ayrıca, elements.js gelir sağladı.

Uygulamanın Mantıksal Yapısı

Polimer'de öğeler, görsel olmayan bir yardımcıdan küçüğe kadar her şey olabilir. kullanıcı arayüzü öğeleri (düğmeler gibi) gibi daha büyük modüllere "sayfalar" ve hatta tam uygulamalar oluşturabilirsiniz.

Uygulamanın en üst düzey mantıksal yapısı
Uygulamamızın üst düzey mantıksal yapısı Polimer öğeler.

Polimer ve Üst-Alt Mimari ile Son İşleme

Her 3D grafik ardışık düzeninde efektlerin etkilendiği son bir adım vardır. bir tür bindirme olarak tüm resmin üzerine eklenir. Bu, ve ışıltılar, tanrı ışınları, cisim ışınları arka plan resmi, bokeh, bulanıklaştırma vb. sahnenin nasıl oluşturulduğuna bağlı olarak farklı öğelerden faydalanır. THREE.js'de, JavaScript'te işleme sonrası için özel bir gölgelendirici oluşturabilir veya bunu, üst-alt yapısı sayesinde Polymer ile yapabiliyoruz.

Son işlemcimizin öğe HTML koduna bakarsanız:

<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>

Etkileri, ortak bir sınıf altında iç içe yerleştirilmiş Polymer öğeleri olarak belirtiriz. Ardından, sw-experience-postprocessor.js içinde şu işlemi gerçekleştiriyoruz:

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

Tüm URL'leri bulmak için HTML özelliğini ve JavaScript'in querySelectorAll son işlemci içinde HTML öğeleri olarak iç içe yerleştirilmiş efektler bir dizi dokümandır. Daha sonra bunları tekrarlayıp besteciye ekleriz.

Şimdi, DOF (Alan Derinliği) etkisini kaldırmak ve çiçeklenme ve vinyet efektlerinin sırasını değiştirebilirsiniz. Tek yapmamız gereken tanımlamayı şöyle özetleyebiliriz:

<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>

ve sahne, gerçek kodda tek bir satır bile değiştirmeden çalışır.

Polymer'de döngü oluşturma ve güncelleme döngüsü

Polymer ile oluşturma ve motor güncellemelerine de zarif bir şekilde yaklaşabiliriz. requestAnimationFrame ve hesaplama işlemleri kullanan bir timer öğesi oluşturduk geçerli saat (t) ve delta süresi - son kare (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()

Ardından, t ve dt özelliklerini motor (experience.jade):

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

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

Motorda t ve dt değişikliklerini de değeri değiştiğinde _update işlevi şu şekilde çağrılır:

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

Ancak FPS için can atıyorsanız öğeleri değişiklikler hakkında bilgilendirmek için gereken birkaç milisaniyeyi kurtarmak amacıyla Polymer'in veri bağlamasını oluşturma döngüsünden kaldırabilirsiniz. Özel gözlemcileri aşağıdaki şekilde uyguladık:

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 işlevi bir geri çağırmayı kabul eder ve geri çağırma dizisidir. Daha sonra, güncelleme döngüsünde her geri çağırmayı tekrar tekrar veri bağlamayı atlayarak veya doğrudan dt ve t bağımsız değişkenleriyle yürütüyoruz. etkinleşen etkinlik için de geçerlidir. Geri aramanın artık etkin olmaması gerektiğinde Daha önce eklenen bir geri çağırmayı kaldırmanıza olanak tanıyan removeUpdateListener işlevi.

THREE.js'de ışın kılıcı

THREE.js, WebGL'nin düşük düzey ayrıntılarını soyutlar ve soruna odaklanmamıza olanak tanır. Sorunumuz Stormtrooper'larla savaşmak. Bir silaha ihtiyacımız var. Şimdi bir ışın kılıcı oluşturalım.

Işın kılıcını eski ışınlardan ayıran şey parlak bıçaktır. kullandığı anlamına gelir. Temel olarak iki kısımdan oluşur: ışın ve ışın hareket ettirilirken görülen iz. Parlak silindir şeklinde inşa ettik ve oyuncu hareket ettikçe onu takip eden dinamik bir patika vardır.

Bıçak

Bıçak iki alt bıçaktan oluşur. Bir iç, bir dış mesele. Her ikisi de kendi malzemelerine sahip THREE.js örgüsüdür.

İç bıçak

İç bıçak için özel gölgelendiricili özel bir malzeme kullandık. Biz iki noktayla oluşturulan bir çizgiyi alıp bu ikisi arasındaki çizgiyi yansıtın görebilirsiniz. Bu düzlem, temel olarak mobil cihazınızla savaşırken kontrol ettiğiniz düzlemdir. Kılıca derinlik ve yön hissi verir.

Yuvarlak parlayan bir nesne hissi yaratmak için düzlemdeki herhangi bir noktanın ana noktaya uzaklığı aşağıdaki gibi A ve B noktasını birleştiren bir çizgi görürsünüz. Noktaya ne kadar yakın o kadar parlak olur.

İç bıçak ışığı

Aşağıdaki kaynak, yoğunluğu kontrol etmek için vFactor değerini nasıl hesapladığımızı gösterir kullanarak köşe gölgesindeki sahneyle uyumlu hale getirmek için parça gölgelendirici'yi tıklayın.

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" )

};

Dış Bıçak Parlaklığı

Dış parlaklık için ayrı bir oluşturma arabelleğine oluşturur ve elde etmek için işleme sonrası çiçek efekti ve son resimle parlaklık sağlayabilir. Aşağıdaki resimde, iyi bir kılıç elde etmek için sahip olmanız gereken üç farklı bölge gösterilmektedir. Yani beyaz çekirdek, ortadaki dış parıltı.

Dış bıçak

Işın Kılıcı Yolu

Star Wars serisinde görüldüğü gibi, ışın kılıcının izi efektin tam olarak ortaya çıkması için önemlidir. Patikaları, üçgenleri sevenlerle oluşturduk. ışın kılıcının hareketine göre dinamik olarak değişir. Bu hayranlar ve görsel açıdan daha iyi hale getirilmesi için son işlemciye iletilir. To fan geometrisinde bir çizgi segmentimiz var ve önceki dönüşümüne göre ve mevcut dönüşümden sonra örgü içinde yeni bir üçgen oluşturup kuyruk kısmından belirli bir süre sonra.

Işın kılıcı sol
Işın kılıcı sağa doğru yol

Bir örgü oluşturduktan sonra ona basit bir malzeme atarız ve son işlemci olarak kullanabilirsiniz. Dış bıçak ışıltısına uyguladığımız aynı parlama efektini kullanırız ve gördüğünüz gibi düzgün bir iz elde ederiz:

Eksiksiz yol

Patikanın çevresinde parıltı

Son parçanın tamamlanması için gerçek alanın etrafındaki ışıltıyı pek çok şekilde oluşturulabilir. Bizim çözümümüz ayrıntıya giremezsiniz. Performans nedeniyle, özel bir bir sabitleyici etrafında pürüzsüz bir kenar oluşturan bu arabellek için bir gölgelendirici oluşturucu arabelleğine Ardından bu çıktıyı son oluşturma işleminde birleştiririz. Burada, izi çevreleyen parıltıyı görebilirsiniz:

Parlak patika

Sonuç

Polimer, güçlü bir kitaplık ve kavramdır (WebComponents, genel). Onunla ne yapacağınıza siz karar verirsiniz. Basit bir kullanıcı arayüzü düğmesinden tam boyutlu bir WebGL uygulamasına kadar her şey olabilir. Önceki bölümlerde size Polymer'i verimli bir şekilde kullanmanıza yardımcı olacak ve aynı zamanda yüksek performans gösteren daha karmaşık modüllerin olur. Ayrıca, WebGL'de güzel görünen bir ışın kılıcını nasıl elde edebileceğinizi de gösterdik. Tüm bunları bir araya getirirseniz üretim sunucusuna dağıtmadan önce Polymer öğelerinizi Vulcanize etmeyi unutmayın. CSP uyumluluğunuzu korumak istiyorsanız Crisper'ı kullanmayı da unutmayın.

Oyun oynanışı