Zusammenfassung
So haben wir mit Polymer eine leistungsstarke, über Mobilgeräte gesteuerte WebGL-Technologie entwickelt. Modulares und konfigurierbares Lichtschwert Wir sehen uns einige wichtige Details an unseres Projekts https://lightsaber.withgoogle.com/ damit Sie Zeit sparen können, wenn Sie beim nächsten Mal wütende Sturmtruppen.
Übersicht
Um Polymer oder WebComponents zu identifizieren, am besten damit beginnen, einen Auszug aus einem tatsächlichen Projekt zu teilen. Hier ist ein Beispiel von der Landingpage unseres Projekts. https://lightsaber.withgoogle.com. Es ist eine gewöhnliche HTML-Datei, die aber ein bisschen Magie enthält:
<!-- 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>
Heutzutage gibt es viele Möglichkeiten, einer HTML5-basierten Anwendung. APIs, Frameworks, Bibliotheken, Game Engines usw. Trotz der großen Auswahl ist es schwierig, eine ausgewogene Einrichtung zu erhalten. Kontrolle über hohe Grafikleistung und sauberen Modular- Struktur und Skalierbarkeit. Wir fanden heraus, dass Polymer uns helfen könnte, organisiert sein und gleichzeitig eine geringe Leistung Optimierungen vorgenommen. Wir haben unser Projekt sorgfältig in Komponenten zu verwandeln, um die Funktionen von Polymer optimal zu nutzen.
Modularität mit Polymer
Polymer ist eine Bibliothek, mit der ein wie Ihr Projekt aus wiederverwendbaren benutzerdefinierten Elementen aufgebaut wird. Sie können damit eigenständige, voll funktionsfähige Module verwenden, die in einem nur eine HTML-Datei erstellen. Sie enthalten nicht nur die Struktur (HTML-Markup), sondern auch und Inline-Styles und -Logik.
Sehen Sie sich das folgende Beispiel an:
<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>
Bei einem größeren Projekt kann es jedoch hilfreich sein, diese drei logischen -Komponenten (HTML, CSS, JS) und führen diese erst bei der Kompilierung zusammen. Eine Sache ist also haben wir jedem Element im Projekt einen separaten Ordner zugewiesen:
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
Der Ordner jedes Elements hat dieselbe interne Struktur mit separaten Verzeichnissen und Dateien für Logik (Coffee-Dateien), Stile (SCSS-Dateien) und Vorlage (Jade-Datei).
Hier ein Beispiel für ein sw-ui-logo
-Element:
sw-ui-logo/
|-- bower.json
|-- scripts
| `-- sw-ui-logo.coffee
|-- styles
| `-- sw-ui-logo.scss
`-- sw-ui-logo.jade
In der Datei .jade
sehen Sie Folgendes:
// 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')
Sie können sehen, wie Elemente übersichtlich angeordnet sind, indem Sie Stile hinzufügen
und Logik aus separaten Dateien. Um unsere Stile in unser Polymer-Element aufzunehmen,
verwenden wir Jades include
-Anweisung, sodass wir Inline-CSS-Code
nach der Kompilierung. Das Script-Element sw-ui-logo.js
wird zur Laufzeit ausgeführt.
Modulare Abhängigkeiten mit Bower
Normalerweise belassen wir Bibliotheken und andere Abhängigkeiten auf Projektebene.
In der Einrichtung oben sehen Sie jedoch ein bower.json
, das sich im
Ordner des Elements: Abhängigkeiten auf Elementebene. Bei diesem Ansatz geht es darum, dass bei vielen Elementen mit unterschiedlichen Abhängigkeiten nur die Abhängigkeiten geladen werden, die tatsächlich verwendet werden. Und wenn Sie ein Element entfernen, müssen Sie nicht daran denken,
Abhängigkeit entfernen, da Sie damit auch die Datei bower.json
entfernt haben
die diese Abhängigkeiten deklariert. Jedes Element lädt unabhängig
die sich darauf beziehen.
Um jedoch eine Duplizierung von Abhängigkeiten zu vermeiden, fügen wir eine .bowerrc
-Datei ein.
auch im Ordner jedes Elements gespeichert. So weiß die Laube, wo sie lagern soll.
Abhängigkeiten, sodass wir sicherstellen können,
dass nur eine am Ende im selben
Verzeichnis:
{
"directory" : "../../../../../bower_components"
}
Wenn mehrere Elemente THREE.js
als Abhängigkeit deklarieren,
installiert es für das erste Element
und parst das zweite.
erkennt es, dass diese Abhängigkeit
bereits installiert ist und nicht
herunterladen oder duplizieren Ebenso behält es diese Abhängigkeit
solange es mindestens ein Element gibt, das sie in
bower.json
Ein Bash-Skript findet alle bower.json
-Dateien in der Struktur verschachtelter Elemente.
Dann gibt sie diese Verzeichnisse nacheinander ein und führt bower install
in
alle:
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
Vorlage für schnelles neues Element
Es dauert jedes Mal etwas, wenn Sie ein neues Element erstellen möchten: Sie müssen den Ordner und die grundlegende Dateistruktur mit den richtigen Namen generieren. Also verwenden wir Slush, um einen einfachen Elementgenerator zu schreiben.
Sie können das Skript über die Befehlszeile aufrufen:
$ slush element path/to/your/element-name
Das neue Element wird erstellt, einschließlich aller Dateistruktur und -inhalte.
Wir haben Vorlagen für die Elementdateien definiert, z.B. die Vorlage für die .jade
-Datei
sieht so aus:
// 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')
Der Slush-Generator ersetzt die Variablen durch tatsächliche Elementpfade und ‑namen.
Verwenden von Gulp zum Erstellen von Elementen
Gulp hält den Build-Prozess unter Kontrolle. Um in unserer Struktur Elemente, die Gulp benötigen, um die folgenden Schritte auszuführen:
- Kompilieren Sie die Elemente
.coffee
Dateien in.js
- Kompilieren Sie die Elemente
.scss
Dateien in.css
- Kompilieren Sie die Elemente
.jade
-Dateien in.html
, wobei die.css
-Dateien eingebettet sind.
Im Detail:
Zusammenstellen der Elemente .coffee
Dateien in .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')));
});
Für die Schritte 2 und 3 verwenden wir Gulp und ein Compass-Plug-in, um scss
in .css
und .jade
in .html
zu kompilieren. Das entspricht dem Ansatz in Schritt 2 oben.
Einschließlich Polymerelementen
Um die Polymer-Elemente tatsächlich einzubeziehen, verwenden wir HTML-Importe.
<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">
Polymerelemente für die Produktion optimieren
Bei einem großen Projekt können viele Polymer-Elemente vorhanden sein. In unserem
haben wir mehr als 50. Wenn Sie davon ausgehen, dass jedes Element
separaten .js
-Datei und einigen Bibliotheken, auf die verwiesen wird, ist es mehr als
100 separate Dateien. Das bedeutet, dass der Browser
viele Anfragen stellen muss,
mit Leistungsverlusten. Ähnlich wie beim Verketten und Reduzieren
auf einen Angular-Build anwendbar wäre, „vulkanisieren“ wir das Polymer-Projekt
für die Produktion beendet wird.
Vulkanisieren ist ein Polymertool, Vereinfacht die Abhängigkeitsstruktur in einer einzigen HTML-Datei, wodurch der Anzahl der Anfragen. Das ist vor allem bei Browsern sinnvoll, Webkomponenten nativ unterstützt.
CSP (Content Security Policy) und Polymer
Bei der Entwicklung sicherer Webanwendungen müssen Sie CSP implementieren. CSP ist ein Regelwerk, das Cross-Site-Scripting-Angriffe (XSS) verhindert: Ausführung von Skripts aus unsicheren Quellen oder Ausführen von Inline-Skripts aus HTML-Dateien.
Die von Vulcanize generierte optimierte, zusammengeführte und minimierte .html
-Datei enthält jetzt den gesamten JavaScript-Code Inline in einem nicht CSP-konformen Format. Um dieses Problem zu beheben, verwenden wir ein Tool namens
Crisper:
Klarer teilt Inline-Skripts aus einer HTML-Datei auf und fügt sie in eine
externe JavaScript-Datei für die CSP-Compliance. Wir geben die vulkanisierte HTML-Datei also an Crisper weiter und erhalten zwei Dateien: elements.html
und elements.js
. In elements.html
wird auch die generierte elements.js
geladen.
Logische Struktur der Anwendung
In Polymer können Elemente alles Mögliche sein, von nicht-visuellen Elementen bis hin zu kleinen, eigenständige und wiederverwendbare UI-Elemente (wie Schaltflächen) zu größeren Modulen, „seiten“ und sogar komplette Anwendungen zu erstellen.
Nachbearbeitung mit Polymer-Architektur mit über- und untergeordneten Elementen
In jeder 3D-Grafikpipeline gibt es immer einen letzten Schritt, bei dem Effekte werden als Overlay über dem gesamten Bild hinzugefügt. Dies ist die und Effekte wie Leuchten, Götterstrahlen, Tiefenschärfe, Bokeh-Effekt, Unschärfen usw. Die Effekte werden kombiniert und auf verschiedene Elemente, je nachdem, wie die Szene aufgebaut ist. In THREE.js einen benutzerdefinierten Shader für die Nachbearbeitung in JavaScript oder Dank seiner hierarchischen Struktur ist das mit Polymer möglich.
Sehen Sie sich den HTML-Code des Elements des Postprozessors an:
<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>
Wir geben die Effekte als verschachtelte Polymer-Elemente unter einer gemeinsamen Klasse an. Gehen Sie dann so vor:
In sw-experience-postprocessor.js
tun wir Folgendes:
effects = @querySelectorAll '.effect'
@composer.addPass effect.getPass() for effect in effects
Wir verwenden die HTML-Funktion und querySelectorAll
von JavaScript, um alle
Effekte, die als HTML-Elemente im Postprozessor verschachtelt sind, in der Reihenfolge,
in dem sie angegeben wurden. Anschließend iterieren wir sie und fügen sie dem Composer hinzu.
Nehmen wir nun an, wir möchten den DOF-Effekt (Feldtiefe) entfernen und die Reihenfolge der Blüten- und Vignetteneffekte ändern. Dazu müssen wir nur die in etwa so aussehen:
<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>
und die Szene wird ausgeführt, ohne eine einzige Zeile Code zu ändern.
Rendering- und Aktualisierungsschleife in Polymer
Mit Polymer können wir auch Rendering und Engine-Updates elegant angehen.
Wir haben ein timer
-Element erstellt, das requestAnimationFrame
verwendet und
wie die aktuelle Zeit (t
) und die Delta-Zeit - Zeit, die seit dem
Letzter Frame (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()
Anschließend binden wir die Properties t
und dt
mithilfe der Datenbindung an unser
Suchmaschine (experience.jade
):
sw-timer(
t='{ % templatetag openvariable % }t}}',
dt='{ % templatetag openvariable % }dt}}'
)
sw-experience-engine(
t='[t]',
dt='[dt]'
)
Wir erfassen die Änderungen von t
und dt
in der Suchmaschine
ändern, wird die _update
-Funktion aufgerufen:
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
Wenn Sie jedoch eine hohe Framerate benötigen, sollten Sie die Datenbindung von Polymer im Render-Loop entfernen, um einige Millisekunden zu sparen, die zum Benachrichtigen der Elemente über die Änderungen erforderlich sind. Wir haben benutzerdefinierte Beobachter wie folgt implementiert:
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
# ...
Die Funktion addUpdateListener
nimmt einen Rückruf an und speichert ihn im Array „callbacks“. In der Aktualisierungsschleife iterieren wir dann über jeden Callback und
führen wir sie direkt mit den Argumenten dt
und t
aus und umgehen so die Datenbindung oder
Auslösung von Ereignissen. Wenn ein Callback nicht mehr aktiv sein soll, haben wir eine removeUpdateListener
-Funktion hinzugefügt, mit der Sie einen zuvor hinzugefügten Callback entfernen können.
Ein Lichtschwert in DREE.js
THREE.js abstrahiert die Low-Level-Details von WebGL und ermöglicht uns, zu diesem Problem. Unser Problem ist der Kampf gegen die Sturmtruppen. Waffe. Bauen wir also ein Lichtschwert.
Die leuchtende Klinge unterscheidet ein Lichtschwert eine zweihändige Waffe. Er besteht im Wesentlichen aus zwei Teilen: dem Balken und dem Weg. der beim Verschieben sichtbar ist. Wir haben einen hellen Zylinder mit einem dynamischen Verlauf erstellt, der dem Spieler folgt, während er sich bewegt.
Die Klinge
Das Blatt besteht aus zwei untergeordneten Flügeln. Ein inneres und ein äußeres. Beide sind THREE.js-Mesh-Netzwerke mit ihren jeweiligen Materialien.
Die innere Klinge
Für das innere Blatt haben wir ein spezielles Material mit einem benutzerdefinierten Shader verwendet. Mi. eine durch zwei Punkte erstellte Linie nehmen und die Linie zwischen diesen beiden projizieren Punkte in einer Ebene. Das Flugzeug wird gesteuert, mit dem Smartphone kämpfen müssen, vermittelt dies ein Gefühl von Tiefe und Orientierung bis zum Säbel.
Um den Eindruck eines runden, leuchtenden Objekts zu erzeugen, schauen wir orthogonaler Punktabstand eines beliebigen Punkts auf der Ebene vom Hauptpunkt die die beiden Punkte A und B wie unten dargestellt. Je näher ein Punkt am umso heller ist es.
In der folgenden Quelle wird gezeigt, wie wir vFactor
berechnen, um die Intensität im Vertex-Shader zu steuern und dann im Fragment-Shader mit der Szene zu mischen.
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" )
};
Der äußere Klingen-Leucht
Für das äußere Leuchten rendern wir in einen separaten Rendererbuffer und verwenden einen Bloom-Effekt in der Postproduktion, den wir mit dem Endbild mischen, um das gewünschte Leuchten zu erzielen. Im Bild unten sehen Sie drei verschiedene Regionen, wenn Sie einen anständigen Säbel haben wollen. Der weiße Kern, die Mitte und der äußere Schein.
Lichtschwertpfad
Die Spur des Lichtschwerts ist entscheidend für den vollen Effekt, wie das Original zu sehen ist in der Star Wars-Serie. Wir haben den Weg mit einem Fächer aus Dreiecken basierend auf der Bewegung des Lichtschwerts. Diese Fans sind dann zur weiteren visuellen Optimierung an den Postprozessor übergeben. Um die Lüftergeometrie haben wir ein Liniensegment und basierend auf seiner vorherigen Transformation Mit der aktuellen Transformation generieren wir ein neues Dreieck im Mesh-Netzwerk. vom Schwanz nach einer bestimmten Länge ab.
Sobald wir ein Netz haben, weisen wir ihm ein einfaches Material zu und übergeben es um einen flüssigen Effekt zu erzeugen. Wir nutzen denselben Bloom-Effekt, den äußeren Schein und erhalten einen gleichmäßigen Verlauf, wie du siehst:
Leuchte auf dem Weg
Damit das Endprodukt vollständig war, mussten wir einen Glanz um den eigentlichen Weg herum hinzufügen. Das lässt sich auf verschiedene Arten realisieren. Unsere Lösung, die wir gehen Sie hier nicht ins Detail. Aus Leistungsgründen war es, eine benutzerdefinierte Shader für diesen Puffer, der eine glatte Kante um eine Klemme des Renderbuffer. Diese Ausgabe wird im endgültigen Rendering kombiniert. Hier können Sie den Leuchten um den Weg zu sehen:
Fazit
Polymer ist eine leistungsstarke Bibliothek und ein leistungsstarkes Konzept (wie WebComponents in allgemein). Es liegt ganz allein bei dir, was du damit machst. Dabei kann es sich um über eine UI-Schaltfläche zu einer WebGL-Anwendung in voller Größe. In den vorherigen Kapiteln haben wir Ihnen Tipps und Tricks zur effizienten Verwendung von Polymer und wie sich komplexere Module strukturieren lassen, gut. Außerdem haben wir Ihnen gezeigt, wie Sie in WebGL ein optisch aussehendes Lichtschwert erstellen. Vergiss also nicht, deine Polymer-Elemente zu vulkanisieren, wenn du all das kombinierst. vor der Bereitstellung auf dem Produktionsserver Wenn Sie die CSP-Konformität wahren möchten, sind Sie vielleicht mit der Macht verbunden.