Ringkasan
Cara kami menggunakan Polymer untuk membuat Lightsaber berperforma tinggi yang dikontrol seluler WebGL yang modular dan dapat dikonfigurasi. Kami meninjau beberapa detail utama project kami https://lightsaber.withgoogle.com/ untuk membantu Anda menghemat waktu saat membuat lightsaber Anda sendiri saat Anda bertemu dengan sekelompok Stormtrooper yang marah.
Ringkasan
Jika Anda bertanya-tanya apa yang kami pikirkan tentang Polimer atau {i>WebComponent<i} adalah langkah terbaik untuk memulai dengan membagikan ekstrak dari proyek kerja yang sebenarnya. Berikut ini adalah contoh yang diambil dari halaman muka proyek kami https://lightsaber.withgoogle.com. Penting file HTML biasa tetapi memiliki beberapa keajaiban di dalamnya:
<!-- 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>
Jadi ada banyak pilihan di luar sana saat Anda ingin membuat aplikasi berbasis HTML5. API, Framework, Library, Game Engine, dll. Terlepas dari semua pilihan yang ada, sulit untuk mendapatkan konfigurasi yang baik antara kontrol atas performa grafis tinggi dan modular bersih struktur dan skalabilitas. Kami menemukan bahwa Polymer bisa membantu kami menjaga proyek terorganisir sambil tetap memungkinkan kinerja tingkat rendah pengoptimalan, dan kami dengan cermat merancang cara memecah proyek menjadi komponen untuk memanfaatkan kemampuan Polymer sebaik mungkin.
Modularitas dengan Polimer
Polymer adalah library yang memungkinkan banyak kekuatan atas bagaimana proyek Anda dibangun dari elemen khusus yang dapat digunakan kembali. Modul ini memungkinkan Anda menggunakan modul yang berfungsi penuh dan mandiri yang terdapat dalam sebuah {i>file<i} HTML tunggal. Mereka tidak hanya berisi struktur (markup HTML) tetapi juga gaya dan logika inline.
Lihat contoh di bawah:
<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>
Tetapi pada proyek yang lebih besar, mungkin akan membantu untuk memisahkan ketiga (HTML, CSS, JS) dan hanya menggabungkannya pada waktu kompilasi. Jadi, satu hal yang kami lakukan adalah memberi setiap elemen dalam project folder terpisahnya sendiri:
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
Selain itu, folder setiap elemen memiliki struktur internal yang sama dengan direktori dan file terpisah untuk logika (file coffee), gaya (file scss), dan template (file jade).
Berikut adalah contoh elemen sw-ui-logo
:
sw-ui-logo/
|-- bower.json
|-- scripts
| `-- sw-ui-logo.coffee
|-- styles
| `-- sw-ui-logo.scss
`-- sw-ui-logo.jade
Dan jika Anda melihat ke dalam file .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')
Anda dapat melihat cara mengaturnya dengan rapi dengan menyertakan gaya
dan logika dari file terpisah. Untuk menyertakan gaya dalam elemen
Polymer, kita menggunakan pernyataan include
Jade, sehingga kita memiliki konten file CSS
inline yang sebenarnya setelah kompilasi. Elemen skrip sw-ui-logo.js
akan
dieksekusi pada runtime.
Dependensi Modular dengan Bower
Biasanya, kita menyimpan library dan dependensi lainnya di level project.
Namun dalam penyiapan di atas, Anda akan melihat bower.json
yang berada dalam
folder elemen: dependensi tingkat elemen. Ide di balik pendekatan ini
adalah dalam situasi di mana Anda
memiliki banyak elemen dengan
dependensi, kita dapat memastikan untuk
memuat hanya dependensi yang
digunakan. Dan jika Anda menghapus suatu elemen, Anda tidak perlu mengingat
menghapus dependensinya karena Anda juga akan menghapus file bower.json
yang mendeklarasikan
dependensi ini. Setiap elemen secara independen memuat
dependensi yang
terkait dengannya.
Namun, untuk menghindari duplikasi dependensi, kami menyertakan file .bowerrc
di setiap {i>folder <i}elemen. Ini memberi tahu bower
di mana harus menyimpan
dependensi sehingga kita dapat memastikan bahwa
hanya ada satu di akhir
direktori:
{
"directory" : "../../../../../bower_components"
}
Dengan cara ini jika beberapa elemen mendeklarasikan THREE.js
sebagai dependensi, sekali
bower menginstalnya untuk elemen pertama
dan mulai menguraikan yang kedua,
aplikasi akan menyadari bahwa dependensi
ini telah terinstal dan tidak akan
mengunduh ulang atau menggandakannya. Demikian pula, hal ini akan
membuat dependensi itu
selama ada setidaknya satu elemen yang masih mendefinisikannya di
bower.json
-nya.
Skrip bash menemukan semua file bower.json
dalam struktur elemen bertingkat.
Kemudian, skrip tersebut memasuki direktori ini satu per satu dan mengeksekusi bower install
di
setiap elemen tersebut:
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
Template Elemen Baru Cepat
Butuh sedikit waktu setiap kali Anda ingin membuat elemen baru: menghasilkan folder dan struktur file dasar dengan nama yang benar. Kita gunakan Slush untuk menulis generator elemen sederhana.
Anda dapat memanggil skrip dari command line:
$ slush element path/to/your/element-name
Dan elemen baru telah dibuat, termasuk semua struktur dan konten file.
Kami menetapkan template untuk file elemen, mis. template file .jade
terlihat seperti berikut:
// 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')
Generator Slush mengganti variabel dengan jalur dan nama elemen yang sebenarnya.
Menggunakan Gulp untuk Membangun Elemen
Gulp menjaga proses build tetap terkontrol. Dan dalam struktur kita, untuk membangun elemen yang kita butuhkan Gulp untuk mengikuti langkah-langkah berikut:
- Mengompilasi file
.coffee
elemen ke.js
- Mengompilasi elemen
.scss
file ke.css
- Mengompilasi elemen
.jade
file ke.html
, menyematkan file.css
.
Secara lebih detail:
Mengompilasi elemen .coffee
file ke .js
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')));
});
Untuk langkah 2 dan 3, kita menggunakan gulp dan plugin kompas untuk mengompilasi scss
ke
.css
dan .jade
ke .html
, dengan pendekatan yang serupa dengan 2 di atas.
Termasuk Elemen Polimer
Untuk benar-benar menyertakan elemen Polymer, kita menggunakan impor HTML.
<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">
Mengoptimalkan elemen Polimer untuk produksi
Sebuah proyek besar bisa memiliki banyak elemen Polimer. Di
proyek, kita punya lebih dari lima puluh. Jika Anda menganggap setiap elemen memiliki
file .js
terpisah dan beberapa yang memiliki library
yang direferensikan, file tersebut menjadi lebih dari
100 file terpisah. Ini berarti banyak permintaan yang perlu dibuat oleh browser,
mengakibatkan penurunan performa. Mirip dengan proses
penggabungan dan minifikasi yang kita
akan berlaku untuk build Angular, kita "vulcanize" project Polymer di
tujuan akhir untuk produksi.
Vulcanize adalah alat Polymer yang meratakan hierarki dependensi menjadi satu file html, sehingga mengurangi jumlah permintaan. Ini sangat bagus untuk browser yang tidak mendukung komponen web secara native.
CSP (Kebijakan Keamanan Konten) dan Polimer
Saat mengembangkan aplikasi web yang aman, Anda perlu mengimplementasikan CSP. CSP adalah serangkaian aturan yang mencegah serangan pembuatan skrip lintas situs (XSS): eksekusi skrip dari sumber yang tidak aman, atau mengeksekusi skrip inline dari file HTML.
Sekarang file .html
yang dioptimalkan, digabungkan, dan diminifikasi telah dibuat
oleh Vulcanize memiliki semua kode JavaScript sebaris di non-CSP
format font. Untuk mengatasinya, kami menggunakan alat yang disebut
Crisper.
Crisper memisahkan skrip inline dari file HTML dan memasukkannya ke dalam satu file JavaScript eksternal untuk kepatuhan CSP. Jadi, kita teruskan objek vulkanik
melalui Crisper dan berakhir dengan dua file: elements.html
dan
elements.js
. Di dalam elements.html
, kode ini juga menangani pemuatan
elements.js
yang dihasilkan.
Struktur Logis Aplikasi
Di Polymer, elemen dapat berupa apa saja, mulai dari utilitas non-visual hingga elemen UI yang kecil, mandiri, dan dapat digunakan kembali (seperti tombol) hingga modul yang lebih besar seperti "halaman" dan bahkan menyusun aplikasi lengkap.
Pascapemrosesan dengan Arsitektur Induk-turunan dan Polymer
Dalam setiap pipeline grafis 3D, selalu ada langkah terakhir di mana efek ditambahkan di atas seluruh gambar sebagai semacam overlay. Ini adalah pascapemrosesan, dan melibatkan efek seperti cahaya, sinar dewa, kedalaman bidang, bokeh, buram, dll. Efek digabungkan dan diterapkan ke elemen yang berbeda sesuai dengan bagaimana adegan dibangun. Di THREE.js, kita dapat membuat shader kustom untuk pascapemrosesan di JavaScript atau kita bisa melakukannya dengan Polymer, Berkat struktur induk-turunannya.
Jika Anda melihat kode HTML elemen pasca-pemroses kami:
<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>
Kita menetapkan efek sebagai elemen Polimer bertingkat pada class yang sama. Kemudian,
di sw-experience-postprocessor.js
kita melakukan hal ini:
effects = @querySelectorAll '.effect'
@composer.addPass effect.getPass() for effect in effects
Kita menggunakan fitur HTML dan querySelectorAll
JavaScript untuk menemukan semua
efek yang disarangkan sebagai elemen HTML di dalam {i>post processor<i}, sesuai urutan
tempat token tersebut ditentukan. Kemudian, kita akan melakukan iterasi dan menambahkannya ke composer.
Sekarang, katakanlah kita ingin menghapus efek DOF (Depth of Field) dan mengubah urutan efek mekar dan vinyet. Yang perlu kita lakukan hanyalah mengedit definisi pasca-prosesor menjadi sesuatu seperti:
<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>
dan tampilan akan berjalan, tanpa mengubah satu baris kode yang sebenarnya.
Loop render dan loop update di Polymer
Dengan Polymer, kami juga dapat melakukan rendering dan update mesin dengan elegan.
Kita membuat elemen timer
yang menggunakan requestAnimationFrame
dan menghitung
nilai seperti waktu saat ini (t
) dan waktu delta - waktu yang berlalu dari
frame terakhir (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()
Kemudian, kita menggunakan data binding untuk mengikat properti t
dan dt
ke
mesin (experience.jade
):
sw-timer(
t='{ % templatetag openvariable % }t}}',
dt='{ % templatetag openvariable % }dt}}'
)
sw-experience-engine(
t='[t]',
dt='[dt]'
)
Selain itu, kita memproses perubahan t
dan dt
di mesin dan setiap kali
nilai berubah, fungsi _update
akan dipanggil:
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
Jika ingin FPS, Anda dapat menghapus data Polymer binding dalam loop render untuk menghemat beberapa milidetik yang diperlukan untuk memberi tahu elemen tentang perubahan. Kami menerapkan observer kustom sebagai berikut:
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
# ...
Fungsi addUpdateListener
menerima callback dan menyimpannya di
. Kemudian, dalam loop update, kita mengulangi setiap callback dan
kita menjalankannya dengan argumen dt
dan t
secara langsung, mengabaikan data binding atau
pengaktifan peristiwa. Setelah callback tidak lagi dimaksudkan untuk aktif, kita menambahkan
Fungsi removeUpdateListener
yang memungkinkan Anda menghapus callback yang ditambahkan sebelumnya.
Lightsaber di THREE.js
THREE.js mengabstraksikan detail WebGL tingkat rendah dan memungkinkan kami untuk fokus menyelesaikan masalah. Dan masalah kita adalah melawan Stormtrooper dan kita memerlukan senjata. Mari kita buat lightsaber.
Pisau yang berkilauan adalah yang membedakan lightsaber dari yang lain senjata dua tangan. Jalur ini utamanya terdiri dari dua bagian: balok dan jalur yang terlihat saat memindahkannya. Kami membuatnya dengan bentuk silinder berwarna cerah dan jalur dinamis yang mengikutinya saat pemain bergerak.
The Blade
Pisau terdiri dari dua sub-blade. Bagian dalam dan luar. Keduanya adalah THREE.js mesh dengan materialnya masing-masing.
Pisau Dalam
Untuk pisau bagian dalam, kita menggunakan material kustom dengan shader kustom. Kita mengambil garis yang dibuat oleh dua titik dan memproyeksikan garis di antara dua titik ini pada bidang. Pada dasarnya, bidang ini adalah apa yang Anda kontrol saat bertarung dengan ponsel Anda, ini memberikan kesan kedalaman dan orientasi dengan pedang itu.
Untuk menciptakan nuansa objek bulat yang bercahaya, kita melihat jarak titik ortogonal dari titik mana pun pada bidang dari garis utama yang menghubungkan dua titik A dan B seperti di bawah. Semakin dekat titik ke sumbu utama akan semakin terang.
Sumber di bawah ini menunjukkan cara kami menghitung vFactor
untuk mengontrol intensitas
dalam shader verteks, lalu menggunakannya untuk menyatu dengan
shader fragmen.
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" )
};
Kilau Bilah Luar
Untuk glow luar, kita merender ke renderbuffer terpisah dan menggunakan efek mekar pasca-pemrosesan ini dan menyatu dengan gambar akhir untuk mendapatkan kilau yang diinginkan. Gambar di bawah ini menunjukkan tiga wilayah berbeda yang Anda jika Anda menginginkan pedang yang layak. Yaitu inti putih, bagian tengah cahaya biru dan cahaya luar.
Jalan Setapak Lightsaber
Jejak lightsaber adalah kunci efek penuh seperti aslinya dalam serial Star Wars. Kami membuat jalan setapak dengan penggemar segitiga yang dibuat secara dinamis berdasarkan gerakan lightsaber. Penggemar ini kemudian diteruskan ke pascaprosesor untuk peningkatan visual lebih lanjut. Untuk membuat geometri kipas, kita memiliki segmen garis dan berdasarkan transformasi sebelumnya dan transformasi saat ini, kita membuat segitiga baru di mesh, yang menghapus bagian ekor setelah panjang tertentu.
Setelah memiliki {i>mesh<i}, kita menetapkan materi sederhana untuknya, dan meneruskannya ke pascaprosesor untuk menciptakan efek yang mulus. Kita menggunakan efek mekaran yang sama yang kita menerapkan kilau bilah luar dan mendapatkan jejak yang mulus seperti yang dapat Anda lihat:
Berpendar di sekitar jalan setapak
Agar hasil akhir benar-benar lengkap, kami harus menangani cahaya di sekitar {i>track<i}, yang dapat dibuat dengan berbagai cara. Solusi yang kami jangan bahas secara mendetail, karena alasan performa adalah membuat untuk buffer ini yang menghasilkan tepi halus di sekitar penjepit pada renderbuffer. Kemudian, kita menggabungkan output ini dalam render akhir, di sini Anda dapat melihat cahaya yang mengelilingi jejak:
Kesimpulan
Polymer adalah library dan konsep yang canggih (sama seperti WebComponents secara umum). Anda bebas menentukan cara untuk menggunakannya. Data bisa apa saja, tombol UI sederhana ke aplikasi WebGL berukuran penuh. Di bab sebelumnya kami telah menunjukkan beberapa tips dan trik cara menggunakan Polymer secara efisien dalam produksi dan cara menyusun modul yang lebih kompleks yang juga berfungsi ya. Kami juga menunjukkan cara mendapatkan lightsaber yang tampak bagus di WebGL. Jadi jika Anda menggabungkan semua itu, ingatlah untuk Vulcanize elemen Polymer sebelum men-deploy ke server produksi dan jika Anda tidak lupa menggunakan Crisper jika Anda ingin tetap mematuhi CSP, semoga Anda berhasil.