Three.js: Übernehmen Sie einige ES6-Funktionen

Erstellt am 16. Apr. 2015  ·  74Kommentare  ·  Quelle: mrdoob/three.js

ES6 kommt, und Browser und Tools werden jetzt schnell unterstützt. Ich denke, THREE.js könnte enorm von einigen der neuen Funktionen von ES6 profitieren.

Aus Spaß und um Diskussionen über eine mögliche Migration des Projekts anzuregen, habe ich dieses Thema erstellt und einige Codebeispiele erstellt.

In den folgenden Beispielen demonstrierte Funktionen:

  • Standardparameter
  • Blockbezogenes let Schlüsselwort
  • Iteratoren + For..Of
  • Klassen
  • Pfeilfunktionen
  • Generatoren
  • Module

Klassenbeispiel

import Object3D from '../core/Object3D';
import Geometry from '../core/Geometry';
import MeshBasicMaterial from '../materials/MeshBasicMaterial';

class Mesh extends Object3D {
    constructor(
        geometry = new Geometry(),
        material = new MeshBasicMaterial({color: Math.random() * 0xffffff}
    ) {
        super();

        this.geometry = geometry;
        this.material = material;

        this.updateMorphTargets();
    }
}

export default Mesh;

Beispiel für einen Traversalgenerator

class Object3D {
    constructor() {
        ...
    }

    traverse(callback) {
        callback(this);

        for (let object of this.children) {
            object.traverse(callback);
        }
    },

    *traversalGenerator() {
        this.traverse(object => yield object);
    }

    ...
}

Generator im Einsatz:

for (let object of scene.traversalGenerator()) {
    if (object.name === 'Blah') {
        break;
    }
}

Hinweis: Ich habe nichts davon getestet

Suggestion

Hilfreichster Kommentar

https://github.com/mrdoob/three.js/commit/1017a5432eede4487436d6d34807fda24b506088

Okay, ich denke, wir können mit let und const in src/ .

@DefinitelyMaybe Möchten Sie dabei helfen?

Alle 74 Kommentare

Wahrscheinlich etwas zu früh? Der Support ist nicht durchgängig großartig für Cross-Browser: http://kangax.github.io/compat-table/es6/

let in FF nicht angezeigt und nicht in 100% der Situationen in Chrome und IE.
generators nicht im Internet verfügbar
class ist nur in Chrome, IE12 (Spartan) Technical Preview für Win10 und FF39, die zwei über der aktuellen Version liegt.
import ist noch nirgendwo verfügbar
super ist nur in IE12 verfügbar, nicht in IE11, Chrome oder FF
arrow functions nicht in IE11 oder Chrome

Auch beide Generatoren und for-of sind Optimierungskiller für Chrome

Imo auch zu früh nur für schicker aussehende Syntax. Umstritten, wenn etwas auf der Liste spürbare Leistungssteigerungen oder Vorteile bei der Lesbarkeit des Codes bringen würde. Vielleicht kann sich jemand, der die Codebasis und die ES6-Funktionen kennt, dazu äußern.

Ich bin etwas spät zur ES6-Party. Das sieht für mich nach einer anderen Sprache aus. Ich trage regelmäßig zu Three.js bei, aber wenn es wie die obigen Ausschnitte aussehen würde, weiß ich nicht, ob ich fortfahren würde. Ich habe einfach nicht die Geduld, eine anders aussehende und anders funktionierende Version von JavaScript zu lernen, die im Grunde die gleichen Dinge tut wie 'new function()' und 'object.prototype', aber möglicherweise langsamer.

Ist dies die Forderung der Web-Community vom ES6-Sprachkomitee? Ich programmiere seit 20 Jahren und das Wort 'Klasse' taucht nirgendwo in meinen Projekten auf (und wird es auch nie, wenn es nach mir geht). Offen gesagt, JavaScript beginnt, wie JAVA auszusehen ... (Skript). :-\

Ich bin mit @benaadams und @jonnenauha zusammen ; zu früh, und es könnte den Code verlangsamen, wenn Chrome und Firefox diese neue Version der Sprache nicht so stark optimieren, wie sie bereits JavaScript unter der Haube optimieren (V8 usw.).

:+1:

@erichlof Nun, ich warte eigentlich am meisten auf die ES6-Klassen- und <script> Tags platziert werden. Dies ist nur albern, wenn Sie die Menge an Dateien wie Three.js haben. Die meisten Projekte lösen dies, indem sie eine große js-Datei erstellen (wie Three.js) und dann gibt es zufällige Extras/Helfer-Ordner, in die Sie andere Dinge einfügen können. Dies ist etwas einschränkend und ich muss einen ~500kb (minifizierten) Build einschließen, um ~alles unter die Sonne zu bekommen.

An einem Punkt, denke ich, haben drei AMD-Unterstützung hinzugefügt, aber das ist nur ein kleiner Codeblock, der erkennt, ob AMD verwendet wird und eine Funktion aufruft, anstatt Window.THREE effektiv zu deklarieren. Ich weiß nicht, wie schwer es derzeit ist, benutzerdefinierte Builds zu erstellen, die Funktionen löschen, die ich nicht benötige, und Dinge, die ich außerhalb des Kerns möchte, hinzufügen und in einer einzigen Arbeitsdatei optimieren, die die Dinge der Reihe nach lädt.

Sie haben vielleicht keine "Klasse" in Ihren Projekten, aber wenn Sie object.prototype verwenden (wie Three.js stark), ist es im Grunde dasselbe, würden Sie zustimmen? Wir mögen es, Objekte zusammenzusetzen und ihnen einen Zweck zu geben. Anderer Code möchte dann diese Objekte und einen sauberen deklarativen Weg verwenden, um sie zu importieren.

Ich sage nur ES6-Klassen und -Module wären auch eine schöne Ergänzung zu Three.js, um mehr Struktur und Modularität für Builds zu geben. Es ist viel zu früh, weil afaik keine Browser zB unterstützen. Module noch. Andere könnten sagen, sollte einfach anfangen, sie zu verwenden und Babel usw. zu verwenden und ES5-konforme Builds auszugeben, ich bin mir nicht sicher, ob das eine gute Idee ist, aber wer weiß. Dies erschwert die Entwicklung, Sie müssen den Build automatisch starten, wenn Sie Dateien speichern, und auch das Debuggen kann komplexer werden. Alleine für diese Dinge neige ich dazu zu denken, dass diese Transpiler es nicht wert sind.

PS War kein Schimpfwort gegen Three.js, ich habe nur gesagt, dass ES6 für Projekte wie Three.js Vorteile haben könnte, sobald die Browserunterstützung da ist :) und meistens ist es mehr syntaktischer Zucker, als es zu einer ganz neuen Sprache zu machen. Es wird einfach mehr Zeug haben.

Ein weiteres Feature, das für Three.js von Vorteil sein könnte, ist WeakMap und möglicherweise WeakSet . Ich bin mir der Auswirkungen nicht sicher, aber es scheint, als könnte dies verwendet werden, um Dinge zu verfolgen, ohne dass der GC seine Arbeit erledigt, wenn der "Eigentümer" die Referenz nicht mehr hält. Es gibt eine Menge solcher Zustände in Three.js und die interne Verwendung kann einen Unterschied machen. Es scheint mir, dass dies ein bisschen ähnlich zu Shared/Weak Ptrs in C++ ist, um den Besitz zu deklarieren.

Ein guter Kandidat könnten Dinge wie https://github.com/mrdoob/three.js/blob/master/src/lights/SpotLight.js#L12 sein, wo dies eine schwache Referenz sein könnte und automatisch gelöscht würde, wenn das Ziel war vom Tatort entfernt und eingesammelt. Aber ich denke, Sie könnten sich sowieso nicht auf die Sammlung verlassen, müssten dies jedoch sowieso auf Null setzen, sobald das Ziel aus der Szene entfernt wird.

Wer weiß, ich warte, bis Experten einige Blog-Posts schreiben, wie all diese Funktionen Apps im Allgemeinen nutzen könnten :)

Hallo @jonnenauha ,

Ja, ich stimme zu, dass neue Funktionen wie 'Import' und 'Export' nützlich sein werden, insbesondere wenn es um Modularität geht. Ich glaube, das ist die Richtung, die @coballast und @kumavis einschlagen wollen , um THREE.js modularer und überschaubarer für benutzerdefinierte Builds und codebasierte Wartbarkeit zu machen. Ich bin total für Module und die Wiederverwendung von Objekten und Funktionen, besonders wenn wir ein großes Bibliotheksformat wie THREE.js haben.

Ich glaube jedoch nicht, dass wir den zusätzlichen syntaktischen Zucker von Klassen, super, let, for, of, arrow Funktionen usw. brauchen schon viel Traktion. Ich mag antiquiert sein, aber ich bin bei Douglas Crockford, wenn er sagt, dass JavaScript bereits eine objektorientierte Sprache ist (d. h. Funktionen = Objekte = Bürger erster Klasse), aber keine "klassische" - also sollten wir uns nicht darum kümmern Schuhanzieher-Kurse in JavaScript. Es wurde mit einem anderen Ansatz entwickelt - ein Ansatz, der mich zuerst verblüffte (der aus der C/C++-Programmierung in den 1990er Jahren kam), dem ich aber jedes Mal mehr zustimme, wenn ich mich an Code setze oder versuche, Codearchitekturen zu lösen Probleme.

Anstelle von syntaktischen Änderungen an THREE.js würde ich eher eine Migration hin zu Funktionen wie der neuen SIMD-Programmierschnittstelle sehen. Ich denke, der gesamte Math-Code von DREI (insbesondere Vector3 und Matrix4) könnte davon stark profitieren. Hier ist ein Videolink (siehe 22:51 im Timecode):
https://youtu.be/CbMXkbqQBcQ?t=1371
Wenn diese Funktion in den gängigen Browsern landet, würde jeder THREE.js-Benutzer eine spürbare Beschleunigung seiner Framerate feststellen.

Tut mir leid, wenn mein früherer Beitrag wie ein Gerede klang, ich mag THREE.js einfach so, wie es jetzt aussieht - ich kann leicht jeden beliebigen Teil davon auswählen und weiß, was los ist, woher es kommt und was es verwendet. :)

@erichlof @jonnenauha Ich fühle mich gezwungen, darauf hinzuweisen, dass es6-Klassen nur Zucker sind und intern den Prototypmechanismus verwenden, um alles zur Laufzeit zu implementieren.

Ich bin ziemlich optimistisch, dass es6-Funktionen die Rechenleistung nicht beeinträchtigen werden. es6-Module können sich auf die Ladezeit auswirken, wenn diese schließlich von Engines implementiert werden, da Sie eher eine Reihe kleiner Dateien als eine große Datei abrufen. HTTP/2 könnte dies jedoch zu einem Problem machen. Wie auch immer, wenn wir es6-Module verwenden, können wir browserify verwenden, um ein Bundle zu erstellen, wie wir es immer tun.

Ich persönlich bin dafür, so viel wie möglich die es6-Syntax in der Codebasis zu verwenden, da dies den Code prägnanter machen und Fehler reduzieren würde. Ich denke, viele Leute neigen dazu, die Prototyp-Kette zu missbrauchen und falsch zu verwenden. Ich habe aber kein gutes Beispiel.

Ich denke auch, dass es die falsche Idee ist, zu sitzen und darauf zu warten, dass es6 in Motoren implementiert wird. Transpiler sind jetzt verfügbar, die gute Ergebnisse liefern, die gerade in Browsern ausgeführt werden. Ich denke, die Vorteile dieser Vorgehensweise sind enorm, also sollten wir ungeduldig sein und sofort damit beginnen.

Ich denke nicht, dass das manuelle Verschieben von Code eine gute Idee ist. Wie Doug McIlroy, der Erfinder von Unix-Pipes und im Allgemeinen ein Halbgott, sagte:
"Verwenden Sie Tools anstelle von ungelernter Hilfe, um eine Programmieraufgabe zu erleichtern, auch wenn Sie zum Erstellen der Tools einen Umweg machen müssen und erwarten, dass Sie einige von ihnen wegwerfen, nachdem Sie sie verwendet haben."

Ich möchte jeden, der sich für es6 interessiert, ermutigen, einzusteigen und zu diesem Repo beizutragen: https://github.com/5to6/5to6

Ich stimme der Konvertierung der gesamten Bibliothek in eine andere Untermenge von Javascript nicht zu. Wie immer sollten wir besprechen, was möglich ist und was die Vor- und Nachteile sind. Denn die Leistung wird sich zwischen den Versionen unterscheiden.

Weakmaps wären beispielsweise ein enormer Gewinn für die Renderer, um den Zustand von Objekten zu handhaben. Die größten Nachteile waren ein schwaches Polyfill und sehr wenig Browserunterstützung und unbekannte Leistungsmerkmale. (Es ist schon eine Weile her, seit ich dies untersucht habe, daher besteht die Möglichkeit, dass dies geändert wird)

Und wir sollten nicht nur es6 betrachten. Ams.js wäre beispielsweise eine großartige Technologie, die einen Software-Renderer ausführt. Weitere Informationen finden Sie unter http://stackoverflow.com/questions/18427810/three-and-asmjs/18439786#18439786.

Und wir sollten nicht vergessen, dass die meisten Mitwirkenden hauptsächlich Beiträge leisten, weil Javascript vertraut ist und es6 für die meisten noch nicht.

@gero3 Das sind gute Punkte, an die ich nicht gedacht habe. Wenn wir über Mikrooptimierung sprechen, stimme ich Ihnen zu 100% zu. Ohne Browserunterstützung würde ich diese Funktionen nicht nutzen wollen.

Was ich oben erwähnt habe, war hauptsächlich die Verwendung von syntaktischem Zucker, der eine identische Semantik wie vorhandene es5-Funktionen hat und so mit Transpilern erstellt werden konnte, ohne die Leistung zu stark zu beeinträchtigen.

AKTUALISIEREN:
Vielleicht interessiert es niemanden, aber ich habe meine Meinung geändert. Ich glaube, wir sollten keine Klassen verwenden. Ich halte es6-Module immer noch für eine gute Idee.

Ich bin total für den Unterricht. Ich bekomme all die wunderbaren Dinge, die der Objektprototyp in JavaScript tun kann. In THREE.js (und vielen anderen modernen Betriebssystemprojekten) verwenden wir jedoch prototypische Vererbung, um Klassen zu simulieren.

THREE.Object3D.call( this );

und

THREE.Scene.prototype = Object.create( THREE.Object3D.prototype );

Sobald Klassen in stabilem Chrome und Firefox unterstützt werden, hätte ich nichts dagegen, den Code zu aktualisieren 😊

@mrdoob- Klassen werden heute in stabilem Chrome 42 unterstützt und Firefox 39 wird im Juni ausgeliefert FYI

Safari auf iOS scheint heutzutage diejenige zu sein, die sich in die Länge zieht...

Der Unterricht ist erstaunlich, ebenso wie andere ES7-Funktionen. Wir verwenden sie in einem unserer Projekte, mussten aber einen Cross-Compiler (babel.js) einführen, da wir auf allen Browsern laufen müssen – Chrome, Firefox, IE und Safari.

Es gibt eine browserify-Transformation, um babel.js (babelify) auszuführen, also würde es mit meinen Bemühungen gut funktionieren.

Nur aus Neugier, hat die Arbeit an einigen davon begonnen? :)

nein, da wir noch nicht wissen, welche Auswirkungen diese auf die Geschwindigkeit haben.

Mein Verständnis ist transpiliert ES6 ist meistens nicht performant und daher nicht für die Produktion geeignet, bis es in den Browser implementiert wird. Damit sollten neuere Projekte oder Module diese Annehmlichkeiten heute anpassen, aber die Leistung muss bei dieser Entscheidung berücksichtigt werden.

Ich stimme @erichlof imo zu, die nützlichste Implementierung wäre SIMD (https://github.com/tc39/ecmascript_simd), auch wenn das Polyfill verwendet wird. Es scheint, als würden die Benutzer davon am meisten profitieren.

Wo würde SIMD in ThreeJS passen? Ich denke, ThreeJS verlagert bereits alle wichtigen Berechnungen auf die GPU. Obwohl ich die Verwendung in den Vector-Klassen einigermaßen verstehen kann, wird in ThreeJS nur sehr wenig Mathematik durchgeführt, vielmehr werden diese Vektoren hauptsächlich nur zur GPU transportiert.

Ich spreche aus Erfahrung, als ich zuvor SSE2/SSE4-Erweiterungen implementiert hatte, und ich stellte fest, dass die Vorteile in den meisten Fällen flüchtig waren – die einzigen wirklichen Fälle waren, in denen es von Vorteil war, wenn ich große Arrays hatte, auf denen ich dasselbe tun wollte Betrieb.

Hallo @bhouston ,
Gilt das gleiche für Matrix-Operationen? Als ich an SIMD dachte, dachte ich, dass 4 x 4-Matrixoperationen am meisten profitieren würden. Und wie wir alle wissen, werden Matrizen für jeden Animationsframe in Three.js auf der JavaScript-/CPU-Seite verwendet, unabhängig von der Komplexität der App.

Wenn die Jungs von Babylon.js nichts dagegen haben, hier ist ein Hinweis, wie Sie all dies starten können:
https://github.com/BabylonJS/Babylon.js/blob/master/src/Math/babylon.math.js#L2030 -L2093

Ich denke, dass ein einzelnes Matrix-Multiple, wenn Sie das Format konvertieren müssen, wahrscheinlich ein Verlierer ist. Wenn Sie Ihre Matrizen immer im SIMD-Format haben, kann dies von Vorteil sein.

Trotzdem ist Matrixmultiply oft nicht optimal, da Sie Spalten mit Zeilen multiplizieren müssen, was eine Neuordnungsoperation erfordert.

Ich habe festgestellt, dass sich die meisten Bemühungen bei der SIMD-Optimierung (mit Ausnahme großer Arrays mit homogenen Operationen) nicht lohnen, aber ich bin damit einverstanden, dass andere Benchmarks durchführen, um dies herauszufinden.

Der resultierende Code ist auch schwer zu debuggen und zu warten.

Eine Strategie, die funktionieren kann, besteht darin, dass alle Vektoren und Matrizen ein SIMD-kompatibles Speicherlayout als native Darstellung verwenden - was Quake 3 meiner Meinung nach in seiner mathematischen Bibliothek glaubte. Aber dann müssen Sie aus Effizienzgründen 4 Floats für die Typen vec2 und vec3 verwenden, aber das wird dann problematisch, wenn Sie auf die GPU hochladen möchten, da Sie jetzt zusätzliche Floats im Weg haben.

Ich verstehe, was du meinst, danke für deine Einsicht und dein Fachwissen. Von der SIMD.js-Präsentation vor einiger Zeit beeindruckt zu sein und sie in drei.js zu stecken und zu pflegen, sind zwei verschiedene Dinge, nehme ich an. Es wäre interessant, wie Sie sagten, einige Leistungsvergleiche durchführen zu lassen. Vielleicht würden Physikbibliotheken wie Cannon.js und Oimo.js , die in Verbindung mit Three.js verwendet werden, mehr von SIMD profitieren?

@bhouston Ahh ok das macht schon Sinn, einige Benchmarks wären aber ganz interessant.

@erichlof bei Interesse habe ich eine Filiale gestartet, https://github.com/Globegitter/three.js/tree/include-SIMD , wo ich angefangen habe Vector3 durch SIMD zu ersetzen. Es ist immer noch ein schweres WIP und meine Zeit ist begrenzt, also werden wir mal sehen, wie weit ich komme. Außerdem können Sie diesen Code nachts mit dem neuesten Firefox ohne Polyfill ausführen (wobei die native Implementierung im Vergleich zum Polyfill anscheinend ~20-mal schneller ist: https://blog.mozilla.org/javascript/2015/03/10/state -of-simd-js-performance-in-firefox/).

@erichlof @jonnenauha Ich fühle mich gezwungen, darauf hinzuweisen, dass es6-Klassen nur Zucker sind und intern den Prototypmechanismus verwenden, um alles zur Laufzeit zu implementieren.
Ich bin ziemlich optimistisch, dass es6-Funktionen die Rechenleistung nicht beeinträchtigen werden.

Vielleicht kommen Sie zu schnell zu dem Schluss: Es gibt tatsächlich in jeder JS-Engine in der (ziemlich komplexen) Implementierung von JS-Objekten unterschiedliche Codepfade für ES6.

es6-Module können sich auf die Ladezeit auswirken, wenn diese schließlich von Engines implementiert werden, da Sie eher eine Reihe kleiner Dateien als eine große Datei abrufen. HTTP/2 könnte dies jedoch zu einem Problem machen.

Kunden möchten möglicherweise immer noch die Komprimierung auf JS-Ebene für die gesamte Anwendung verwenden, um die Netzwerkbandbreite zu reduzieren und ihr geistiges Eigentum zu schützen.

Wenn der Closure-Compiler Three.js verständlich macht, kann man auf ES6 kompilieren und sehen, wann der richtige Zeitpunkt für die Umstellung ist, plus viele zusätzliche Vorteile. Ich denke, hier sollten jetzt solche Bemühungen in Angriff genommen werden...

Trotzdem ist [SIMD] Matrix Multiply oft nicht optimal, da Sie Spalten mit Zeilen multiplizieren müssen, was eine Neuordnungsoperation erfordert.

SIMD-Befehlssätze haben oft einen Befehl "mit Skalar multiplizieren und addieren", um die Matrixmultiplikation wie folgt zu implementieren:

for i : 0..3:
    dst.col[i] = lhs.col[i] * rhs.co[i][0] // multiply vector by scalar
    for j : 1..3:
        dst.col[i] += lhs.col[i] * rhs_col[i][j] // multiply vector by scalar & add

Die Matrixmultiplikation wendet eigentlich nur eine Transformation auf die Spaltenvektoren des rechten Operanden an. Nun können Transformationen entweder als Bündel von Punktprodukten betrachtet werden (die verwirrende Methode, die wir normalerweise mit Stift und Papier verwenden) oder als Linearkombination der Achsenvektoren des Zielraums = Spaltenvektoren der linken Seite Operand.

@Globegitter Wow das ist ein

@Globegitter Ich liebe es, wenn jemand einfach

wobei die native Implementierung im Vergleich zum Polyfill anscheinend ~20-mal schneller ist

Würde mich auch interessieren, wie viel langsamer das Polyfill im Vergleich zu Nicht-SIMD ist

Ich werde Firefox Nightly bekommen, damit ich auch mit dem neuen Zweig experimentieren kann!

Sollte auch in der Lage sein, es in Edge auszuprobieren, indem Sie experimentell und asm.js in about:flags . einschalten

@Globegitter Ich glaube, dein Editor ändert den Whitespace, was zu wirklich fiesen Diffs führt: https://github.com/Globegitter/three.js/commit/d835ca3a22eed4ed4603534773ae55c29d5a8026

Mir ist aufgefallen, dass Sie den SIMD-Typ als Beiwagen erstellen:

https://github.com/Globegitter/three.js/commit/8ed9c1d351a3b0587a1f05051922d271d79f642d

Darf ich vorschlagen, dass Sie Vector3 x, y, z in Getter/Setter ändern und nur ein float32x4 speichern? Ich denke, ein solcher Ansatz kann mit weniger Änderungen viel einfacher zu implementieren sein.

Ich bin mir nicht sicher, wie man Eigenschaften am besten definiert, aber mrdoob macht hier so etwas:

https://github.com/mrdoob/three.js/blob/5c7e0df9b100ba40cdcaaf530196290e16c34858/examples/js/wip/proxies/ProxyVector4.js#L18

Die SIMD als Hauptspeichertyp hinter einem mathematischen Typ zu haben, ist wahrscheinlich am effizientesten, es sind keine zusätzlichen Konvertierungen erforderlich. Hier ist die SSE-Mathematikbibliothek von Bullet Physics, wenn Sie eine Anleitung zu Standardvektor-/Matrixoperationen benötigen:

https://code.google.com/p/bullet/source/browse/trunk/src/vectormath/sse/

@bhouston , danke für diese Hinweise. Ich war gerade dabei, zu sehen, wie weit ich in ein paar Stunden kommen würde, ohne vorher viel mit drei und SIMD gearbeitet zu haben (wir verwenden es in den meisten unserer Projekte). Daher wird dieses Feedback von jemandem, der drei kennt, wirklich geschätzt. Und ja, ich muss das in meinem Editor ausschalten.

@tschw danke für den Hinweis zur Matrix/Vektor-Mathematik! Du hast Recht das ist besser.

@Globegitter Hier ist ein besseres Beispiel für Setter/Getter am Prototyp eines Objekts: https://github.com/mrdoob/three.js/blob/master/src/core/Object3D.js#L83

Einige Cent für die Arbeit an ES2015 (hauptsächlich in Knoten)

  • Es gibt Orte, an denen Javascript-Engines (z. B. V8) spielen müssen, um die ES6-Funktionen zu optimieren
  • aus meiner Erfahrung würde Code wie let x = 1, y = 2 v8 deoptimieren, obwohl ich erwarten würde, dass v8 es irgendwann unterstützt
  • transpilierter Code in ES5 kann langsamer ausgeführt werden als ES6-Code (weshalb ich es vorziehe, nur unterstützte ES6-Funktionen in >node 4 zu verwenden, das ist fast alles außer dem Import-Export-System)
  • Karten und Sets sind Leistungsgewinne
  • Klassen sind schön
  • Die Verwendung von Babel kann Ihren Arbeitsablauf belasten, wahrscheinlich nicht die Mühe wert, wenn Sie ES6 nur für Syntaxzucker verwenden

Vor einem halben Jahr habe ich einige Three.js-Funktionen (4x4-Matrixmultiplikation, Vector4 usw.) in SIMD konvertiert und Sie können sie ausprobieren. Irgendwann funktionierte es als Bookmarklet, aber jetzt ist möglicherweise eine Aktualisierung erforderlich, um mit der neuesten Three-Version zu funktionieren

  • Firefox Nightly unterstützt ab Werk native SIMD
  • Chrome mit dem Flag --js-flags="--harmony-simd" unterstützt JS-Polyfill von SIMD, sodass es langsamer ist als die Nicht-Simd-Version. Zumindest können Sie überprüfen, ob es funktioniert und experimentieren!

350% Leistungssteigerung ist eine LÜGE :)

Ich habe auch einen Teil von Vector3 portiert, aber es ist kommentiert.

https://github.com/DVLP/three.turbo.js

Bearbeiten: Ich habe irgendwo auf meiner Festplatte eine aktuellere Version, also werde ich dieses Projekt bald aktualisieren

Fantastisch zuzusehen und zu starren ein +1 dazu.
Was großartig wäre, wäre ein System, das die Leistung überprüft und solche Funktionen je nach Leistung aktiviert oder deaktiviert.

Was großartig wäre, wäre ein System, das die Leistung überprüft und solche Funktionen je nach Leistung aktiviert oder deaktiviert.

Ich denke, man hätte zwei Vector3-Definitionen im Vector3-Modul und Sie würden bedingt die eine oder andere zurückgeben, je nachdem, ob SIMD nativ ist? Ich denke, das würde funktionieren, aber es würde die Download-Seite erhöhen. Vielleicht könnten Sie nur ein paar Funktionen haben, die je nachdem, ob SIMD verfügbar ist, wechseln - wahrscheinlich ist SIMD nur für eine kleine Teilmenge mathematischer Funktionen am wichtigsten. Wenn dies in Bezug auf den Gesamtcode klein war, kann es sich lohnen, jetzt einzufügen. Es muss jedoch optional sein, damit es nicht langsam wird, wenn SIMD nicht verfügbar ist.

Wir könnten mit einer SIMD-Version von Matrix4 multiplyMatrices() da dies derzeit die am häufigsten aufgerufene Methode in komplexen Szenen ist.

https://github.com/mrdoob/three.js/blob/dev/src/math/Matrix4.js#L383 -L419

screen shot 2016-08-30 at 20 46 29

@mrdoob schau hier
https://github.com/DVLP/three.turbo.js/blob/master/src/three.turbo.js

Versuchen Sie es als Bookmarklet:
javascript:(function(){var script=document.createElement('script');script.src='//rawgit.com/DVLP/three.turbo.js/master/src/three.turbo.js';document.head.appendChild(script);})()

Das verantwortliche Stück Code

THREE.Matrix4.prototype.multiplyMatrices = function(a, b) {
    var ae = a.elements,
      be = b.elements,
      tb = this.elements,
      arr1 = SIMD.Float32x4.load(ae, 0),
      arr3 = SIMD.Float32x4.load(ae, 4),
      arr5 = SIMD.Float32x4.load(ae, 8),
      arr7 = SIMD.Float32x4.load(ae, 12),
      arr2,
      arr4,
      arr6,
      arr8,
      res;
    // calculated version
        for (var i = 0; i < 4; i++) {
            arr2 = SIMD.Float32x4.splat(be[i * 4]);
            arr4 = SIMD.Float32x4.splat(be[i * 4 + 1]);
            arr6 = SIMD.Float32x4.splat(be[i * 4 + 2]);
            arr8 = SIMD.Float32x4.splat(be[i * 4 + 3]);
            res = SIMD.Float32x4.add(SIMD.Float32x4.add(SIMD.Float32x4.mul(arr1, arr2), SIMD.Float32x4.mul(arr3, arr4)), SIMD.Float32x4.add(SIMD.Float32x4.mul(arr5, arr6), SIMD.Float32x4.mul(arr7, arr8)));
            SIMD.Float32x4.store(tb, i * 4, res);
          }
}

Beim Testen vor einem halben Jahr ist mir aufgefallen, dass die Version mit ausgeklappter "for"-Schleife minimal schneller war. Deshalb ist in meiner kleinen Bibliothek die Schleife kommentiert und eine hartcodierte Version vorhanden.

Es gibt mehr Funktionen im "inversen" Zweig
https://github.com/DVLP/three.turbo.js/blob/inverse/src/three.turbo.js

Was ist der Leistungsunterschied?

https://jsfiddle.net/tk6zx5dm/6/

Es hängt davon ab, ob. In Nightly, wenn die Anzahl der Berechnungen klein ist (<1000), ist das Ergebnis dreimal langsamer. Wenn die Anzahl der Berechnungen höher als 10000 ist, ist die Geschwindigkeit ~40% schneller

In Chrome mit aktiviertem --js-flags="--harmony-simd" Flag gibt es kein echtes SIMD, sondern ein JavaScript-Polyfill, daher ist die Geschwindigkeit im Moment offensichtlich um ein Vielfaches langsamer.

Ein guter Ort zum Testen wäre das Crosswalk-Projekt (basierend auf Chromium). Sie haben echte SIMD für Android, daher könnte es ein interessantes Experiment sein, ein Projekt mit Code aus diesem JSFiddle zu erstellen, um zu sehen, was das Ergebnis wäre.

Vielleicht möchten Sie das simd polyfill sowieso nicht in Ihre Beispielseiten einbinden. Nur ein bisschen bequemer für die Leute, sie auszuprobieren. Protokollieren Sie eine Zeile in der Konsole oder geben Sie Text auf den Bildschirm, wenn kein natives Element verfügbar ist (das Polyfill hinterlässt wahrscheinlich einige Hinweise darauf, dass es aktiviert ist).

Ich kann mir nicht vorstellen, warum Chrome einfach das js simd polyfill mit --js-flags="--harmony-simd" laden würde, das macht einfach keinen Sinn, wenn es bereits im Userland möglich ist?! Was ist der Vorteil davon. Vielleicht werden sie nach und nach anfangen, Sachen einzubauen. Wo hast du gelesen, was passiert eigentlich mit der Flagge, gibt es gute Links? Scheint hier "in Entwicklung" zu sein https://www.chromestatus.com/features/5757910432874496

Bearbeiten: Zum eigentlichen Thema: Ich kann mir vorstellen, dass es sehr schwer ist, dieses Zeug in Three.js zu packen, wenn die Perf von wenigen Objekten bis hin zu vielen Objekten überall ist. Wenn alle Implementierungen eine Leistungsverbesserung mit 1 bis N Objekten liefern können, sollte diese Funktion erkannt und dort verwendet werden, wo es sinnvoll ist. Wenn die nativen Impls inkonsistent sind, sehe ich das Ganze nirgendwo hin. Warum also daran arbeiten, die Entwicklerstunden mit etwas Produktiverem verbringen.

Three kann darauf springen, wenn es ausgereift ist, oder könnte die Unterstützung von Three.js dazu führen, dass Browser-Implementierungen besser werden? Ich würde denken, dass eine unwirkliche Engine und andere Simulations-/Mathematik-Anwendungsfälle die treibende Kraft für Browser-Anbieter sind, nicht besonders, wie viele Bibliotheken die Funktion verwenden möchten. Aber wer weiß.

Ich kann mir nicht vorstellen, warum Chrome einfach das js simd polyfill mit --js-flags="--harmony-simd" lädt

Ich denke, es ist eine ziemlich gängige Praxis, dass Browser dies auf diese Weise tun, damit Benutzer anfangen können, Dinge auszuprobieren. Wenn ich es zum Beispiel richtig verstehe, wird WASM zunächst so in Browsern eingeführt.

Alle Argumente, die die Unvermeidlichkeit unterstützen, dass ein Zenturio erforderlich ist. Echtzeitüberwachung der Leistung, die Funktionen aktivieren oder deaktivieren und die optimale Leistung bestimmen kann. Daher sollte sich sogar die Dichte der Schattenkarte basierend auf der Kameraentfernung usw. ändern. Wie auch immer, ich weiß, dass der Konsens entschieden hat, dass dies ein Tool von Drittanbietern ist und nicht benötigt wird. Trotzdem möchte ich diesen Punkt im Bewusstsein, wenn nicht im Unterbewusstsein, behalten.
Vielleicht suchen Sie nur nach einem Pollyfill und deaktivieren SIMD, aber wieder sagt FPS alles. Prioritäten, die aktiviert oder deaktiviert werden sollen, sind wahrscheinlich am besten als benutzer-/anwendungsspezifische Präferenz. Danke fürs Zuhören! Ich freue mich auf einen besseren schnelleren GL in naher Zukunft. Seien wir bereit, den Rest in den Schatten zu stellen.

Es scheint, dass der Prozess des Ladens von Daten in SIMD einen Overhead verursacht, der den Vorteil der Verwendung von SIMD in Nightly widerlegt. Ich bin sehr gespannt auf die Leistung in Chrome, aber das neueste Chromium mit echter SIMD ist hier http://peterjensen.github.io/idf2014-simd/
Es ist alt.

Aktualisieren:
jetzt funktioniert SIMD auch in Edge. Sie können es aktivieren, indem Sie zu about:flags gehen und "Experimentelle JavaScript-Funktionen aktivieren" aktivieren (Edge neu starten).
Ich bin mir jedoch nicht sicher, ob dies echtes SIMD oder Polyfill ist. Dieser Test rendert die SIMD auf meinem Computer ~ 40% langsamer :/ https://jsfiddle.net/tk6zx5dm/6/

Variation des Tests mit SIMD-Objekten, die im Matrix4-Objekt zwischengespeichert sind, nicht sicher, ob dies jemals nützlich sein wird
https://jsfiddle.net/tk6zx5dm/15/
Interessant ist, dass Code mit zwischengespeicherten SIMD-Objekten _manchmal_ schneller ist, selbst in Chrome, das polyfill SIMD verwendet (...? seltsam)

THREE.Matrix4.prototype.multiplyMatrices = function(a, b) {
  var i = 4;
  while(i--) {
    SIMD.Float32x4.store(this.elements, i * 4, 
      SIMD.Float32x4.add(
        SIMD.Float32x4.add(
          SIMD.Float32x4.mul(
            a.cacheSIMDRow1,
            b.cacheSIMDSplat[i * 4]
          ),
          SIMD.Float32x4.mul(
            a.cacheSIMDRow2,
            b.cacheSIMDSplat[i * 4 + 1]
          )
        ),
        SIMD.Float32x4.add(
          SIMD.Float32x4.mul(
            a.cacheSIMDRow3,
            b.cacheSIMDSplat[i * 4 + 2]
          ), 
          SIMD.Float32x4.mul(
            a.cacheSIMDRow4,
            b.cacheSIMDSplat[i * 4 + 3]
          )
        )
      )
    );
  }
}

Caching - muss wahrscheinlich bei jedem updateMatrix() ausgeführt werden, was die gesamte Lösung am Ende verlangsamen kann

THREE.Matrix4.prototype.updateSIMDCache = function() {
  this.cacheSIMDRow1 = SIMD.Float32x4.load(this.elements, 0);
  this.cacheSIMDRow2 = SIMD.Float32x4.load(this.elements, 4);
  this.cacheSIMDRow3 = SIMD.Float32x4.load(this.elements, 8);
  this.cacheSIMDRow4 = SIMD.Float32x4.load(this.elements, 12);

  if(!this.cacheSIMDSplat) {
    this.cacheSIMDSplat = [];
  }
  for(var i = 0; i < 16; i++) {
    this.cacheSIMDSplat.push(SIMD.Float32x4.splat(this.elements[i]));
  }
};

Ich bin neugierig, wurde der ES6-Stil überarbeitet? Der gesamte Code ist im Moment ohne Verkettung unbrauchbar. Warum also nicht auch babel ausführen und gegebenenfalls ES6-Zeug verwenden?

Der gesamte Code ist im Moment ohne Verkettung unbrauchbar. Warum also nicht auch babel ausführen und gegebenenfalls ES6-Zeug verwenden?

Hauptsächlich aufgrund fehlender Tests zu den Auswirkungen von in Babel produziertem Code auf die Leistung. Außerdem habe ich gehört, dass V8 schnelleren Code erzeugt, wenn var anstelle von let/const verwendet wird.

Zu Ihrer Information : Ich habe vor kurzem angefangen,

Das Ende dieses Links hilft bei der Erklärung von var vs. let in loops
http://stackoverflow.com/questions/21467642/is-there-a-performance-difference-between-let-and-var
Persönlich warte ich darauf, dass die Nicht-Transpiler-Lösungen den Browser treffen. wie für 'warten', desto besser, aber im Moment sollte es vielleicht so geschrieben werden und einen Transpiler durchlaufen (von dem er schrecklich entstellt wird), aber wenn es in Chrome funktioniert?! also für andere browser testen? Ich sage "Lass sie Kuchen essen... oder Chrome verwenden." (mein Lieblingsausdruck).
Ich denke, 'let' sollte verwendet werden, wenn es in der Situation ist, in der es vorzugsweise durch Tests bewiesen wird, dass es besser ist.
Ich nehme an, es ist so, als ob 'var' hochgezogen wird, um ein Scoping zu vermeiden, aber Sie möchten das vielleicht, und dann ist 'lassen' am besten. Ich denke / hoffe, dass 'let' Ihren Speicherbedarf in bestimmten Situationen auch kleiner halten sollte.

Transpilierter Code wird nie so schnell sein wie von Hand optimiert. Es ist eine Schande, dass JSPerf down ist. Ich habe es öfter besucht als Google.
Edit: JSPerf.com ist nicht down! Ich habe einfach angenommen, dass es für immer tot ist, nachdem es ein Jahr lang nicht funktioniert hat
let 3x langsamer als var in meinem Chrome Canary: https://jsperf.com/let-vs-var-performance/14
in Firefox und Edge kein Unterschied in der Geschwindigkeit, aber Chrome ist das wichtigste.
Kann jemand in Safari testen?

Der Unterricht scheint großartig und modern zu sein! Weiß jemand, ob das schon auf dem Plan steht?

@ Rubinhuang9239 Ich habe noch niemanden gesehen, der es

let 3x langsamer als var in meinem Chrome Canary: https://jsperf.com/let-vs-var-performance/14

Für meinen Wert sind let und const jetzt geringfügig schneller als var für mich auf Chrome 66, Firefox 59 und Edge 42, wenn ich diesen Test verwende.

Das Umschalten der Klassen sollte meiner Meinung nach sehr einfach sein - der Hauptteil der Arbeit war die Einführung des Rollups, das vor einiger Zeit durchgeführt wurde. Es würde mich nicht wundern, dass ein Held in ein paar Stunden Klassen in ThreeJS implementieren könnte.

Nun, es gibt viele Kurse, also dauert es vielleicht 8 Stunden oder so, wenn Sie es manuell gemacht haben.

Vielleicht klein anfangen und zuerst die Mathe-Klassen umwandeln und eine PR machen. Wenn das funktioniert, fahren Sie mit den anderen fort.

@looeee es ist über ein Jahr her, also keine Überraschung, dass ES6 es geschafft hat, mit der Leistung aufzuholen

2019 ist das Jahr, um endlich damit zu beginnen, ES6-Code in die Beispiele/Dokumente aufzunehmen, richtig @mrdoob? 😄

ES6 ist schon länger der Standard, neue Entwickler lernen ES6. Wir können auch die Unterstützung von IE11 in den Beispielen einstellen, wie Sie in #16220 besprochen haben. Welche Entwickler sehen sich drei.js-Beispiele mit IE11 an? 😅

Ich denke, die am meisten benötigten Funktionen, um den Code für Neulinge zu vereinfachen, sind die Klassen und die Vorlagenzeichenfolgen, während das jetzt standardmäßige const/let nicht vergessen wird.

Ich kann einen Beitrag leisten, wenn wir uns entschließen, damit anzufangen.

Schritt für Schritt. Beginnen wir damit, die Beispiele zu aktualisieren, um vorerst three.module.js zu verwenden.

Schritt für Schritt. Beginnen wir mit der Aktualisierung der Beispiele, um zunächst drei.module.js zu verwenden.

Dieser Schritt ist seit einiger Zeit abgeschlossen. Vielleicht ist es an der Zeit, offiziell zum nächsten Schritt überzugehen?

Zwei Kandidaten:

  1. const/lass
  2. Klassen

Da Klassen bereits seit einiger Zeit in den Box-Geometrien verwendet werden, stimme ich dafür, dies zuerst zu tun. Oder wir könnten beides gleichzeitig machen.

Verwandte: #11552, #18863

Wenn ich das richtig verstehe, besteht das Problem darin, dass wir nichts in ES6-Klassen konvertieren können, wenn es um Beispiele erweitert wird, bis auch die Beispiele konvertiert werden. Und das könnte bedeuten, zu warten, bis examples/js weg ist? Es sei denn, wir können bestätigen, dass das Skript modularize Klassen unterstützt, um die examples/js Dateien gleichzeitig mit ihren Elternklassen zu konvertieren.

So wie ich es verstehe, ist examples/js irgendwie all die überschüssigen Funktionen, die trotzdem cool sind, aber wenn wir alle in den Hauptfunktionen kombiniert würden, würde src/... es unverhältnismäßig aufblähen. Inhärent ist die Antwort auf die Frage „Stellen wir Beispiele/Skripte für häufig erstellte x, y, z zur Verfügung?“. Ich vermute, dass die Antwort von Three.js meistens ja ist, aber als Lehrmaterial auf der Website. Das Entfernen von examples/js scheint zu diesem Zeitpunkt nicht in Frage zu kommen. Obwohl ich vielleicht falsch verstanden habe, wie examples/js referenziert/verwendet wird, lass es mich wissen.

examples/js als einzige Website/Bildung zu belassen, verfehlt einen Teil dessen, was dieser Ordner sein könnte, z das.

Ich schweife ab.

bis auch die Beispiele konvertiert sind.

Ich mag den Klang davon als unseren nächsten besten Zwischenschritt.

@DefinitelyVielleicht entfernen wir die Funktionalität in examples/js , es sind zwei Verzeichnisse erwähnenswert:

  • examples/js/*
  • examples/jsm/*

Die erste enthält Legacy-Dateien, die zweite enthält aus diesen Dateien generierte ES-Module mit derselben Funktionalität. Wir werden schließlich die erste entfernen. Das Skript, das die Konvertierung durchführt, unterstützt derzeit keine ES-Klassen. Solange das nicht entfernt wird, können Dateien in examples/js nicht in ES-Klassen konvertiert werden. Einige von ihnen erweitern Dateien in src/ , und Sie können ES-Klassen nicht erweitern, ohne ES-Klassen zu verwenden, daher ist dies eine blockierende Abhängigkeit.

ah, war verwirrt von dem vorherigen Kommentar

Und das könnte bedeuten, zu warten, bis example/js weg ist?

macht jetzt Sinn.

modularize.js erinnert mich an mein erstes Projekt, das mich hierher gebracht hat. Konverter . Ich habe hier Kommentare zum Wechsel zu ES6-Klassen gesehen, also dachte ich, ich springe stattdessen einfach hier ein.

Wenn also examples/js src in irgendeiner Weise erweitert, müssen beide gleichzeitig in ES6-Klassen konvertiert werden
oder...
arbeiten Sie an modularisieren, bis es Klassen/es6 generiert?

wir können nichts in ES6-Klassen konvertieren, wenn es um Beispiele erweitert wird

Es gibt immer noch viele Dinge im Kern, die in den Beispielen nicht erweitert werden, warum fangen wir nicht damit an?

Das klingt gut für mich.

@ Mugen87 gab es sonst noch etwas, das den ES-Klassenwechsel blockierte, oder nur das?

Es gibt immer noch viele Dinge im Kern, die in den Beispielen nicht erweitert werden, warum fangen wir nicht damit an?

Liste der Skripte nicht durch Beispiele erweitert .

Edit: Liste wurde aktualisiert!

Die Blocker sind Abschnitte wie diese:

https://github.com/mrdoob/three.js/blob/6865b8e6367d0ce07acbacfae6663c4cce3ac21e/examples/js/loaders/ColladaLoader.js#L6 -L12

https://github.com/mrdoob/three.js/blob/6865b8e6367d0ce07acbacfae6663c4cce3ac21e/examples/js/cameras/CinematicCamera.js#L38 -L39

https://github.com/mrdoob/three.js/blob/6865b8e6367d0ce07acbacfae6663c4cce3ac21e/examples/js/controls/OrbitControls.js#L1149 -L1150

Die Verwendung von THREE.<class>.call und Object.create( THREE.<class> wäre die wahrscheinlichsten Muster. Das würde bedeuten, dass Loader, EventDispatcher und PerspectiveCamera (neben wahrscheinlich vielen anderen) noch nicht in Klassen umgewandelt werden können.

https://github.com/mrdoob/three.js/commit/1017a5432eede4487436d6d34807fda24b506088

Okay, ich denke, wir können mit let und const in src/ .

@DefinitelyMaybe Möchten Sie dabei helfen?

🎉 💯 hellz ja!

Ich wollte nur Bedenken äußern, dass, wenn Sie heißen Code laden, meine Angst ist, dass Konstante Probleme verursachen wird. Wenn es in allen JavaScripts zutrifft, dass Objekte const vollständig überschreiben, ist das kein Problem. Wenn dies nicht der Fall ist, sollten Sie niemals alle const verwenden. Ich füge einfach Objektstrukturen mit Codefunktionen zusammen, die Schlüsseln dieser Objektbäume (wie Strukturen) zugewiesen sind, sodass ich größtenteils vermeide, let oder const verwenden zu müssen.
Wie auch immer, es ist etwas, worüber man nachdenken sollte, und ich glaube im Grunde genommen, dass const niemals verwendet werden sollte und wirklich unnötig ist. Hauptsächlich für meine Bedenken mit dem Laden von Hotcode.
Trotzdem denke ich, dass sie nicht so konstant sind, wie Sie denken, vielleicht kann jemand, der das versteht, erklären, dass es ein bedeutungsloses Problem mit dem Neuladen von Importen oder was auch immer ist. Danke für Ihre Überlegung und Ihren Input.
Lass es sein 'lassen'! Schließlich.

Crockford sagte, var sei ein großer Fehler, könne aber nicht geändert werden, also wurde 'let' erstellt, aber var wird als fehlerhaft angesehen und der Code von 'let' hätte eine Lösung für var sein sollen, aber es hätte ein paar schlecht codierte Randfälle gebrochen in freier Wildbahn lauern. Strikter Modus und Heben sind Themen rund um dieses Thema.

@MasterJames es gibt absolut keine Probleme mit dem Hot-

Ich arbeite in einer React-Umgebung und heißes Nachladen ist dort die Norm, ebenso wie const und let, die heute Standard sind.

Ich stimme zu, dies wird das heiße Nachladen nicht beeinträchtigen. Vielleicht haben Sie const verwechselt, weil Sie Objekte mit Object.freeze unveränderlich machen? Das planen wir nicht.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

seep picture seep  ·  3Kommentare

jack-jun picture jack-jun  ·  3Kommentare

fuzihaofzh picture fuzihaofzh  ·  3Kommentare

filharvey picture filharvey  ·  3Kommentare

konijn picture konijn  ·  3Kommentare