Three.js: Selektive Beleuchtung

Erstellt am 10. Aug. 2014  ·  101Kommentare  ·  Quelle: mrdoob/three.js

Ich bin mir nicht sicher, ob dies bereits ein geplantes oder vielleicht sogar ein fertiges Feature ist, daher versuche ich zunächst, die Aufgabe zu erklären.

Ich muss selektive Beleuchtung für verschiedene Räume machen. Ich habe zum Beispiel zwei Zimmer. Ein Licht darf nur auf Gegenstände und Innenwände eines Raumes wirken. Der zweite Raum darf von diesem Licht nicht beeinflusst werden.

Wenn ich der Szene derzeit ein Licht hinzufüge, wirkt sich dies auf alle Objekte in ihrer Entfernung aus. Und ich bekomme einen seltsamen Effekt, wenn Licht "durch die Wand" des zweiten Zimmers fällt.

Ich denke, ich brauche eine Art Gruppen oder Kanäle für die Beleuchtung, damit ich die Objekte einstellen kann, die von einer Lichtquelle beeinflusst werden, und Objekte, die von einer anderen beeinflusst werden.

Ich habe so etwas weder bei Lichtern noch bei Objekten gefunden, also dachte ich, dass es vielleicht eine gute Funktion sein könnte.

Und übrigens, wenn es noch nicht implementiert ist, was ist der empfohlene Ansatz, um solche Aufgaben mit dem aktuellen Stand von Three.js zu lösen?

Enhancement

Hilfreichster Kommentar

Hast du einen Link zu einem Beispiel für so etwas?

hier habe ich einen nur für dich gemacht: https://jsfiddle.net/f2Lommf5/524/

Alle 101 Kommentare

Was ich sage, ist im Grunde ein channel Feld in THREE.Light und ein lightChannel Feld in THREE.Mesh oder so ähnlich. Wenn letzteres null ist, wird es von allen Lichtquellen beeinflusst. Wenn letzteres nicht null ist, werden nur die Lichtkanäle mit dem gleichen Wert beeinflusst.

Oder vielleicht könnte es nicht zum Mesh selbst hinzugefügt werden, sondern zu separaten Flächen der Mesh-Geometrie.

Klingt so, als ob Sie Schatten verwenden möchten?

Nun, mit Schatten könnte ich so etwas erreichen (und das habe ich auch schon versucht), aber es gibt verschiedene Nebenwirkungen und ich empfinde es als Hack, weil ich nicht einige Objekte beleuchten und dann Schatten darauf werfen muss . Ich darf sie erst gar nicht anzünden.

Was ich brauche, ist, dass eine bestimmte Lichtquelle nicht einen Satz von Netzen beeinflusst, sondern den anderen Satz.

Normalerweise mache ich dies mit einer Technik wie dieser: Beispiel-Diskussionsthread :

glEnable(GL_LIGHT0);
//...
glEnable(GL_LIGHTn);

// Draw the walls to room 1
DrawWalls(room[0]);

// Draw the contents of room 1
DrawContents(room[0]);

glDisable(GL_LIGHT0);
//...
glDisable(GL_LIGHTn);

// Draw the walls to room 2
DrawWalls(room[1]);

// Draw the contents of room 2
DrawContents(room[1]);

Es sieht also wie ein anderes Feature aus als nur Schatten. Oder übersehe ich etwas?

Ja ... ich denke, das kann in der Tat praktisch sein. Ich bin mir jedoch nicht sicher, wie die API dafür aussehen soll.

Vielleicht könnte hier die einfachste Lösung die effektivste sein:

  1. Füge channel (oder group ) zu THREE.Light
  2. Füge affectedByLightChannel (oder affectedByLightGroup ) zu THREE.Mesh (oder vielleicht sogar zu einer Fläche in der Geometrie)

Was denkst du?

Vielleicht ist 'affectedByLightChannel' zu lang und so etwas wie 'lightChannel' würde es tun, aber ich denke, es wäre praktisch: nur Kanalnummern auf Lichtquelle und Empfängern.

So wie das:

    light = new THREE.PointLight(0xFFF7D6, 1.0, 15)
    light.channel = 123
    testScene.add(light)

    testScene = new THREE.Scene
    geometry = new THREE.BoxGeometry(2,2,2)
    material = new THREE.MeshLambertMaterial 
        color: 0xffffff

    cube = new THREE.Mesh(geometry, material)
    cube.lightChannel = 123
    testScene.add(cube)

Wenn lightChannel gleich 0 ist, wird es von allen Kanälen beeinflusst. Wenn channel gleich 0 ist, dann wirkt sich dies auf alle Meshes aus.

Es wäre also vollständig abwärtskompatibel mit dem aktuellen Verhalten.

Das ist vielleicht etwas zu schwer zu verstehen... Vielleicht ist es besser so:

cube.lightInfluences = [ light1, light2 ];

Scheint mir absolut in Ordnung.

Vielleicht ist es in einigen Fällen etwas schwieriger zu verwenden, aber es ist offensichtlich einfacher zu verstehen.

Wie wäre es mit einer einfachen Integer-Maskeneigenschaft für Netze und Lichter?

light = new THREE.PointLight(0xFFF7D6, 1.0, 15)
light.mask = 0xffffffff; // default mask
testScene.add(light);

cube = new THREE.Mesh(geometry, material)
cube.mask = 0xffffffff; // default
testScene.add(cube);

Objekte werden nur dann durch Lichter beleuchtet, wenn das logische UND ihrer Masken ungleich Null ist.
Dies würde es ermöglichen, Lichter von mehr als einem Kanal zu beeinflussen, ohne zusätzliche Methoden für die Objekte.

Ein Maskenstandard von 0xffffffff würde sich nicht auf bestehenden Code auswirken.

Was @satori99 sagte.

Ich denke jedoch, dass mask stattdessen eine Eigenschaft von Light und Mesh*Material sollte. (Nur Materialien, die von Licht beeinflusst werden.)

Außerdem könnte die Eigenschaft alternativ lightMask , lightChannel oder channel heißen.

Das Problem des Kanal/Masken-Ansatzes besteht darin, dass der Benutzer bitweise Operationen verstehen muss. Etwas zu intensiv, wenn man es mit dem Rest der API vergleicht.

Was können Sie mit Masken tun, was Sie mit dem Array-Ansatz nicht tun können?

Ich könnte ein Beispiel aus der Aufgabe mit zwei Räumen oben geben.

Der Hauptpunkt bei der Verwendung des Kanalansatzes gegenüber dem Array-Ansatz besteht darin, dass einfache Operationen wie "Licht1 von Raum 1 nach Raum 2 verschieben" komplizierter werden, wenn Sie Arrays verwenden.

Anstatt nur einzustellen

light1.channel = 2

(vorher war es auf 1 gesetzt)

Sie müssten alle Objekte in Raum 1 finden, die zuvor Licht1 im Array lightInfluences hatten, dann das Licht aus ihren Arrays entfernen und es dann zu allen Objekten in Raum 2 hinzufügen.

Gleiche Geschichte mit der einfachen Bedienung wie 'Objekt 1 von Raum 1 nach Raum 2 bewegen'. Anstatt seinen Einflusskanal von 1 auf 2 zu setzen, müssten Sie alle Lichter in diesem Raum finden, sie dann aus seinem Einfluss-Array entfernen, dann alle Lichter in Raum zwei finden und hinzufügen.

Es ist nicht so, dass es nicht geht, deshalb habe ich gesagt, dass der Ansatz von lightInfluences für mich absolut in Ordnung ist. Aber das Kanal-Zeug wäre das erste, was ich darüber für mich implementieren würde, nur um allgemeine Operationen so einfach wie 1 Zuweisung zu machen.

Ich denke, es sollte als Maske implementiert werden. (Ob es auf der CPU oder GPU implementiert ist, wird später erörtert.)

Wir können anhand von Beispielen zeigen, wie es eingestellt wird, und Benutzer können dem Muster folgen.

Wenn Ihnen das noch zu kompliziert ist, können wir eine THREE.Channels API dafür erstellen.

light.channels = new THREE.Channels();
...
light.channels.clear();
light.channels.add( channel );
light.channels.remove( channel );
light.channels.all();

Dieselben Methoden für Mesh*Material .

Ich mag diese API :)
Ich kann sehen, dass dies für Objekte und Lichter funktioniert, aber wie funktioniert es für Materialien?

Nur Materialien reagieren auf Licht. Das müsste eine Eigenschaft des Materials sein, würde ich meinen.

Da stimme ich @westlangley zu. Leuchten sind materialabhängig.

Gleiche Geschichte mit der einfachen Bedienung wie 'Objekt 1 von Raum 1 nach Raum 2 bewegen'.

Nun, das ist ein Problem. Channels wäre nicht objektbasiert.

Nun, das ist ein Problem. Kanäle wären nicht objektbasiert.

Aber wieso? Ist es eine technische Einschränkung?

Weil es die ganze Idee von all dem irgendwie entkräftet. Denn es kann verschiedene Objekte geben, die dasselbe Material wiederverwenden, aber eines davon sollte beleuchtet sein und das andere - nicht.

Aber wieso? Ist es eine technische Einschränkung?

Nein, weil Objekte nicht auf Licht reagieren. Nur Materialien tun.

Denn es kann verschiedene Objekte geben, die dasselbe Material wiederverwenden, aber eines davon sollte beleuchtet sein und das andere - nicht.

Sie können für alle Objekte in der Szene dasselbe Material verwenden – nur clone das Material für Objekte, deren Material unterschiedliche einheitliche Werte erfordert. Es sollte immer noch nur ein Shader-Programm von allen geteilt werden.

Ich denke, es sollte als Maske implementiert werden. (Ob es auf der CPU oder GPU implementiert ist, wird später erörtert.)

Lässt sich das einigermaßen direkt in der GPU handhaben?

Lässt sich das einigermaßen direkt in der GPU handhaben?

Ja, Sie müssten die zusätzlichen channels Uniformen für die Lichter und Materialien abgeben.

Wie wäre es mit einem Layer-Management-System? Ich würde die Netze in Ebenen gruppieren und die Masken von dort aus anwenden (könnte Lichter, Schatten, Sichtbarkeit usw. beeinflussen), Einheit wäre ein gutes Beispiel?

Schatten ist auch ein verwandtes Thema. Ich denke, es sollte auch so etwas wie selektiven Schattenwurf geben. Wie 'receiveShadowFrom = ...' (und Liste der Quellen) statt nur 'receiveShadow = true'.

Denn wenn Sie Lichter einstellen, die nur einen bestimmten Raum betreffen (in meinem Beispiel), möchten Sie auch sofort, dass diese Lichter nur auf diese Raumobjekte Schatten werfen.

Schattenattribute sollten sich aus den gleichen Gründen wie oben in diesem Thread wirklich auf den Materialien und nicht auf den Objekten befinden.

Schattenattribute sollten sich aus den gleichen Gründen wie oben in diesem Thread wirklich auf den Materialien und nicht auf den Objekten befinden.

Ja, es macht Sinn!

Gibt es Pläne für die Aufnahme dieses Features (wie eine geplante Zielversion für den ersten Entwurf)?

Können Sie als Workaround die meisten Ihrer Anforderungen erfüllen, indem Sie für jeden Raum (und seine Lichter) eine separate Szene haben?

renderer.autoClear = false;
...
renderer.render( scene1, camera );
renderer.render( scene2, camera );

Hmm, ich werde diesen Ansatz ausprobieren!

Selektive Beleuchtung / Schatten ist ein Muss für zukünftige Versionen IMO.

GROßE +9999 für dieses hier würde ich gerne auswählen können, ob ein Material einen Schatten von Lichtquelle A oder von Lichtquelle B wirft. Hat jemand derzeit eine andere Lösung als zwei Szenen? Das wird mir ziemlich weh tun...

Heilige Scheiße, wie wird das immer noch nicht umgesetzt? nach +9999 von rohan )

Haha, ich vermute, dass es schwierig ist, @tsone zu implementieren.

Wie ist es schwer zu implementieren, wenn dies nur Uniformen sind, die sie an Materialien weitergeben? alles was sie tun müssen, ist die globale liste der lichter durch die in material definierte zu ersetzen, falls vorhanden, irgendwo tief im webgl-renderer.

Hier ist ein einfaches JSFiddle, das die Layers-Implementierung des Dev-Zweigs testet:
https://jsfiddle.net/Angrypickle/t8f7q3vo/4/
Leider sieht es im Moment nicht so aus, als ob es richtig funktioniert. Oder mache ich etwas falsch?

Ja. Ebenen funktionieren noch nicht mit Lichtern. Sie arbeiten jedoch mit Kamera / Objekt! 😊

Roger, Herr! Hier ist ein aktualisiertes JSFiddle, das überlappende Kameras verwendet, um eine selektive Beleuchtung mit Ebenen zu erzielen:
https://jsfiddle.net/Angrypickle/t4a1eusL/
Es scheint auf dem Desktop und auf dem Handy ordnungsgemäß zu funktionieren. Sieht jemand etwas zutiefst Schlimmes an diesem Ansatz? Zumindest bis Lichter in die Layer-Funktionalität eingebunden sind?

Sieht jemand etwas zutiefst Schlimmes an diesem Ansatz?

natürlich ist es schlecht. Anstatt mit einer einzelnen Kamera durch die Szene zu navigieren, müssen die Leute jetzt Dinge tun camera1.add( camera2 ); Ich meine, das ist WTF, wenn ich es mir ansehe. Wie... was? Kamera in meiner Kamera? Was ist, wenn ich Dutzende von Räumen habe, die einzeln beleuchtet werden müssen? Wie viele Kameras brauche ich? und Schichten... gestern gab es keine Schichten, richtig, und jetzt muss ich darüber l̲e̲a̲r̲n̲ .

schimpfen, um nicht zu sagen, dass ich die perfekte Lösung dafür habe. zB haben alternative3d-Leute Licht auf Sachen gesetzt, die sich in den Begrenzungsrahmen von Licht befanden. Dies hatte den Vorteil des Next-to-0-Setups für Endbenutzer, aber es fiel auseinander, wenn die Grenze zwischen den Lichtern schräg sein musste. aber dennoch, wenn ich dieses Problem im aktuellen Projekt jetzt lösen müsste, würde ich höchstwahrscheinlich dazu neigen, gebrauchte Standardmaterialien in ShaderMaterial-s zu kratzen und die Lichter, die ich möchte, von Hand dorthin weiterzugeben.

@makc- Ebenen sind eigentlich super einfach (und mächtig)!
Der Ansatz von

Leute, nur um sicherzustellen, dass ich richtig folge; Nehmen wir an, ich habe eine einzelne Szene und eine "Haupt"-Lichtquelle. Ist es mit dieser Technik möglich, dass bestimmte Materialien diese Hauptlichtquelle ignorieren und gleichzeitig Schatten von einer anderen Lichtquelle werfen?

Nun, dafür müssen wir den Materialien auch Ebenenunterstützung hinzufügen.

Was wir im Moment tun können, ist Objekte vor der Kamera anzuzeigen/auszublenden:

Angenommen, Sie machen ein Spiel und verwenden im Editor Kugeln, um Collider anzuzeigen. Diese Kugeln könnten auf Layer 1 gesetzt werden, der Editor der Kamera könnte Layer 0 und 1 aktiviert haben, aber die Game-Kamera könnte auf Layer 0 eingestellt sein. Auf diese Weise sehen Sie in Ihrem Editor alle Dummys, aber im Spiel sie' wieder weg.

Ich denke, dass dies immer dann sinnvoller ist, wenn ich die Funktionalität zum Editor selbst hinzufüge. Wir sollten wahrscheinlich auch einige Beispiele machen.

Richtig! Im Grunde möchte ich also 2D-Charaktere in meiner Three JS-Welt haben. Diese Charaktere brauchen "Punkt"-Schatten, damit sie so aussehen, als wären sie Teil der Umgebung. Ich erreiche dies derzeit mit transparenten schwarzen Kreisgeometrien, die zu ihren Füßen platziert sind, und einigen ziemlich hackigen Sachen, um es in Winkeln zum Laufen zu bringen. Selbst dann funktioniert es auf komplexen Oberflächen überhaupt nicht gut.

Meine ursprüngliche Idee war, unsichtbare Kreisgeometrien als "Halos" über jedem Charakter zu platzieren und ein Licht zu erzeugen, das direkt nach unten zeigt und die gesamte Szene abdeckt. Diese Lichthöfe würden nur Schatten von dieser Lichtquelle werfen, während alles andere in der Szene Schatten von der "Haupt"-Lichtquelle werfen würde.

Ich denke, damit diese Idee funktioniert, brauchen wir Ebenen, oder?

Diese Lichthöfe würden nur Schatten von dieser Lichtquelle werfen, während alles andere in der Szene Schatten von der "Haupt"-Lichtquelle werfen würde.

Früher hatten wir eine Option shadowOnly , aber sie wurde entfernt.

FWIW, es gibt diesen Ansatz um Schatten zu erzeugen...

Ah aber shadowOnly würde nicht wirklich funktionieren, weil dann die Halos Schatten von beiden Lichtquellen werfen würden, ich möchte nur, dass sie Schatten von einer werfen.

Ich werde mir das Beispiel gleich am Telefon ansehen, sieht aber vielversprechend aus.

Bearbeiten Hmm, aber wenn diese Kugel ihre Position in der Szene ändert und das Bodennetz unterschiedliche Höhen hätte, würde ihr Schatten dann richtig mit den Oberflächennormalen des Bodens übereinstimmen?

NÖ...

Ja dachte schon. Brauche Schichten! Hehe

Hallo @rohan-deshpande,

Ja, für Ihren Anwendungsfall benötigen Sie irgendeine Art von Ebenen. Ich war derjenige, der vor einiger Zeit das Shadowmesh-Feature implementiert hat. Sie sollten für eine Szene mit einem flachen Boden oder Boden verwendet werden, da es sich um einflächige Schatten handelt. Wenn Sie jedoch jemals schnelle, billige (aber korrekte) Single-Plane-Schatten benötigen, sind diese in Bezug auf die Leistung kaum zu übertreffen. Der Grund, warum ich diese hinzugefügt habe, war, dass Shadowmaps sogar bei einfachen Demoszenen meine Framerate erheblich verringert haben. Shadowmeshes hingegen laufen selbst auf meinem Handy schnell.

Sie können mein Spiel, das sie verwendet, hier ansehen:
https://github.com/erichlof/3dLightCycles

Ich rendere die Szene zweimal durch 2 verschiedene Ansichtsfenster und alle Spielobjekte (Zyklen und Trailwände) haben korrekte Schatten. Auf meinem Smartphone läuft es seidenweich, was mit Shadowmaps für 2 Szenen-Renderings pro Frame unmöglich wäre.

+1 hier für Schichten in der Zukunft :)

Das Spiel

Okay, ich denke, ich werde auf Schichten warten. Bis dahin muss meine Hacky-Lösung ausreichen.

Nein, es wurde noch nicht implementiert. Sie müssen auf Ebenen warten oder eine der in ITT aufgeführten Lösungen ausprobieren (z. B. separate Szenen).

+99999 wieder

Dies wäre auf jeden Fall sehr hilfreich. Und wir haben jetzt Schichten, die sich so anhören, was das aufgehalten hat. Also, hier ist die freundliche Beule. ;-)

@manthrax überprüfe das!

+99999 wieder

Das hätte ich gerne. Ich habe eine Situation, in der jeder Avatar nur vom nächstgelegenen Licht beleuchtet wird und ich Tausende von Lichtern in der Szene haben kann. Es wäre schön, für jeden Avatar ein einzelnes Licht anzugeben.

Hallo!
Ich werde diese Funktion brauchen und dachte daran, sie zu implementieren, da ich denke, dass ich gefunden habe, wo dies möglich ist ( initMaterial in WebGLRenderer ) und die Verwendung sollte ziemlich einfach sein vorhandene Schichten.

Ich überlege, eine lichtspezifische Bitmaske (als Layers Objekt) zu erstellen, um auszuwählen, welche Ebenen von einem bestimmten Lichtobjekt betroffen sind (unabhängig von der eigenen Objektebene des Lichts), und dann Lichter/Schattenkarten zu filtern, die werden als Uniformen für jedes Objekt in der oben zitierten Funktion festgelegt.

Wäre das relevant?

Ich werde dies versuchen und eine Pull-Anfrage senden, sobald ich dies erreicht habe, es sei denn, Sie leiten mich vorher auf eine andere Methode um.

AKTUALISIEREN:

https://github.com/tieselune/three.js/tree/selective-lighting

Ich komme irgendwo hin. Ich bin mir nicht sicher, wie sich dies auf die Leistung auswirken oder wie ich meinen Code für die Leistung optimieren kann, aber er funktioniert bei den wenigen Tests, die ich durchgeführt habe. Beleuchtung pro Schicht! Yay!

Ich muss jedoch noch etwas testen und ein relevantes Beispiel erstellen, bevor ich einen Pull-Request einreiche.

AKTUALISIEREN:

Ich habe noch ein paar Tests gemacht und das gleiche Material auf zwei Objekten, die sich auf verschiedenen Ebenen befinden (und unterschiedliche Beleuchtungseinstellungen haben), führt dazu, dass der Renderer das Material seit den Beleuchtungseinstellungen ständig aktualisiert (über needsUpdate ). auf den Materialwechsel zwischen zwei Objekten, was vorher unmöglich war. Dies bedeutet einen enormen Leistungsabfall und visuelle Kuriositäten (da der letzte Materialupload zur Renderzeit gewinnt)

Dies kann natürlich vermieden werden, indem eine neue Materialinstanz erstellt wird, anstatt dieselbe für zwei Objekte mit unterschiedlichen Beleuchtungseinstellungen zu verwenden. Aber ich bezweifle, dass es für den Benutzer eine gute Idee ist, es zu klonen, da es bedeuten würde, das Originalmaterial auf Änderungen zu überprüfen, um sie auf den Klon zu spiegeln.

Hier sind zwei Lösungen, die ich verwenden könnte:

  1. Ich könnte einfach eine Warnung anzeigen, wenn zwei Objekte auf verschiedenen Ebenen mit unterschiedlichen Beleuchtungseinstellungen dasselbe Material teilen, sodass der Benutzer selbst ein neues Klonmaterial erstellen und verwalten kann.

  2. Ich könnte Ebenen auf Materialebene anstelle der Objektebene hinzufügen (und ein paralleles Ebenensystem für Lichter erstellen), sodass es obligatorisch ist, verschiedene Materialien zu verwenden, um unterschiedliche Beleuchtungseinstellungen zu erzielen. Das würde bedeuten, dass es das aktuelle Layersystem für die Sichtbarkeit (auf Objekten und Kameras) und ein anderes für die Beleuchtung (auf Materialien und Lichter) geben würde.

Was denkt ihr?

Ich habe gerade darüber nachgedacht, als ich gesehen habe, wie Ihr Kommentar eingegangen ist. Ich denke, es ist nicht hilfreich, eine Warnung anzuzeigen, da viele Leute sie wahrscheinlich nicht sehen werden. Von beiden lege ich definitiv lieber Lichtschichten auf das Material als auf das Objekt. Es ist ein wenig kontraintuitiv, aber es macht immer noch Sinn.

Nur zur Verdeutlichung, wenn needsUpdate gesetzt ist, werden in diesem Fall nur die einheitlichen Werte neu berechnet, oder? Es sollte keinen Shader neu kompilieren müssen, da die verschiedenen Shader alle zwischengespeichert werden sollten. Welche Art von Leistungseinbußen sehen Sie? Haben Sie einen Profiler verwendet, um genau zu sehen, wo die zusätzliche Berechnung stattfindet?

Übrigens, filterAmbiantLights sollte filterAmbientLights .

Mit der Rechtschreibfehler hast du recht. Ich hatte eigentlich alles mit "ambiant" geschrieben, bevor ich bemerkte, dass es falsch war und ich einen Vorfall vergessen hatte. 😇

Ich denke, ich werde die Ebeneninformationen dann auf das Material verschieben. Es scheint relevanter und konsistenter mit der Art und Weise zu sein, wie es funktioniert.

Der Leistungsabfall kam (und kommt immer noch) davon, dass initMaterial (und dann acquireProgram und getShaderParameter was aus irgendeinem Grund enorm langsam ist) bei jedem Frame mehrmals aufgerufen wurden, weil die lightHash wäre jedes Mal anders und würde material.needsUpdate auf true .

Übrigens verwende ich die Profiling-Tools von Chrome. (Zeitleisten und Profiler).

Das ist in Ordnung für mich, aber mir ist nicht klar, warum acquireProgram die ganze Zeit laufen sollte. Wenn die Anzahl jeder Lichtart zu den Programmparametern hinzugefügt wird, sollte es dann nicht unnötig sein, den Shader jedes Mal neu zu kompilieren?

Ich verstehe es auch nicht;

Hier ist die Aufrufliste (bei jedem Frame) und das folgende schreckliche Speicherleck, wenn Sie damit vertraut sind, könnte mir helfen, zu verstehen, was schief geht. Es sieht so aus, als ob es für jeden Frame neue WebGLProgram ...

threejscalltree

Vielleicht könnte es replaceLightNums , das den Vertex-/Fragment-Shader-Code während der Erstellung des WebGL-Programms aktualisiert, wodurch es neu kompiliert wird, oder wenn man bedenkt, dass es sich um einen anderen Shader handelt... ?

BEARBEITEN: Wie auch immer, die Verwendung von Ebenen auf Materialebene löst das Problem wie erwartet. Ich habe nur irgendwo ein Speicherleck, das ich untersuchen sollte, aber ansonsten sieht es ganz gut aus.

Es ist wahrscheinlich eine gute Idee zu verstehen, warum dies geschieht, nur um sicherzustellen, dass Sie den Code vollständig verstehen und keine neuen Fehler einführen. Können Sie es schrittweise durchgehen, um zu sehen, warum der Shader-Code jeden Frame ändert?

Ich kenne WebGLPrograms gut genug, um zu sagen, was los ist, aber es scheint, als ob es diese Shader für Sie zwischenspeichern sollte.

Es ist eigentlich ganz einfach:

  • um zu wissen, ob acquireProgram aufgerufen werden soll oder nicht, holt initMaterial den Shader-"Code" aus dem Cache (eigentlich ist es eher ein Hash, konstruiert in getProgramCode ) und vergleicht es in den "Code" des Programms des aktuellen Materials.
  • Da diese Funktion den "Code" aus Parametern erstellt, einschließlich der Anzahl jeder Lichtart, die gefiltert wird und sich zwischen den Objekten unterscheidet, kann der Code für dasselbe Material (sozusagen dasselbe Programm) von einem Objekt zu einem anderen unterschiedlich sein andere.
  • Da dieser Prozess für jedes Objekt wiederholt wird, ändert sich der "Code" mehrmals pro Frame, wodurch er in einem einzigen Frame genauso oft neu kompiliert wird: was den Perf-Drop verursacht.
  • Da jedoch mehrere Objekte das gleiche Material und somit das gleiche Programm haben, hat das zuletzt durchlaufene Objekt dem Programm seine Parameter auferlegt, was dazu führte, dass beide Objekte mit dem gleichen Lichtsetup, aber nicht unbedingt den gleichen shadowMaps beleuchtet wurden (das kann für Objekte in einer anderen Reihenfolge berechnet werden, leidet aber unter dem gleichen "letzten Objekt gewinnt"-Problem), was zu meinen visuellen Merkwürdigkeiten führt.

Jetzt funktioniert alles wie erwartet (da jedes Objekt mit unterschiedlichen Licht-Setups ein anderes Material und ein anderes Programm hat), bis auf eine Speicheroptimierung, die ich mit meinen eigenen Licht-Hashes machen könnte, die ich demnächst in Angriff nehmen werde.

Es könnte einige Verbesserungen geben, wenn die Lichtzahlen variabel wären, so dass jedes Material nur Instanzen desselben Programms ist, aber da diese Zahlen in den Shader-Code (in replaceLightNums ) eingefügt werden, scheint es mit der aktuellen Vorgehensweise nicht kompatibel zu sein sind (und deren Optimierung).

Hoffe die Erklärung war verständlich genug

Ich frage mich, ob wir die Ebenenmaske an den Shader übergeben können (eine Uniform pro Objekt und eine weitere pro Licht). Dann könnten wir so etwas wie fügen diese in hier .

Etwas wie...

for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {

    pointLight = pointLights[ i ];
    pointLight.distance *= float( object.mask & pointlight.mask > 0.0 );

    ...

}

Meh, ich glaube nicht, dass wir in glsl bitweise Operationen durchführen können...

Ja, es sieht so aus, als ob bitweise Operationen in GLSL 1.30 beginnen und dass Standard-WebGL 1.00 verwendet. 😕

Hallo @mrdoob und @tieselune ,

Chrome 56 und Firefox 51 sind gerade gelandet, was bedeutet, dass WebGL 2.0 standardmäßig aktiviert ist (WebGL2 folgt der OpenGL ES 3.0-Spezifikation). Das bedeutet, dass Bit-Operationen (und andere coole Sachen wie 3D-Texturen) jetzt verfügbar sind. Ich weiß nicht, ob Three sich langsam auf die Umstellung auf WebGL 2.0 vorbereitet hat, aber ich habe ein paar obligatorische Änderungen an meiner Kopie von three84.js vorgenommen und WebGL 2.0 aktiviert und eine kleine Operation in einem Shader durchgeführt, um dies sicherzustellen hat funktioniert, und es hat!
https://developers.google.com/web/updates/2017/01/nic56
https://developer.mozilla.org/en-US/Firefox/Releases/51

Ich wollte dich nur wissen lassen. +1 für die Maskierungsidee :-)

Hallo @erichlof ! Das sind großartige Neuigkeiten für WebGL2; Dies bedeutet, dass der WebGL2-Renderer wahrscheinlich in der Lage sein wird, die Maskierungsprobleme effizienter anzugehen.

Wie auch immer, angesichts der bisher sehr begrenzten Verwendung von Browsern, die WebGL2 unterstützen, glaube ich nicht, dass wir die Bemühungen, es in WebGL 1 zum gedauert , bis fast alle Browser WebGL-Apps ausführen können, also wird es wahrscheinlich ein etwas länger, bis WebGL 2 wirklich im großen Stil nutzbar ist... 😕 Aber danke für den Hinweis!

Hallo nochmal!

Neues Update: Ich habe getan, was ich für die Speicherverwaltung für notwendig hielt, aber die JS-Heap-Garbage-Collection scheint viel mit meiner Softwarekonfiguration (Ausführung von Programmen, geöffneten Registerkarten, Erweiterungen) zum Zeitpunkt der Ausführung von Profilen zu tun zu haben. Kann jemand mit etwas mehr Erfahrung damit bestätigen, dass mein Code im Vergleich zur aktuellen Version von Threejs nicht so speicherhungrig ist?

Wie auch immer, ich habe ein Beispiel in example/webgl_lights_selective_lighting.html gemacht . Die Sache ist die, ich habe Shadowmap-bezogene visuelle Artefakte bekommen, wenn ich zwei Spotlights (auf denselben Ebenen) gleichzeitig auf die gehäuteten Objekte der Szene verwende. Die statischen Objekte verhalten sich wie erwartet. Ich habe Tests durchgeführt und es passiert auch im Dev-Zweig, ohne selektive Lichtschichten überhaupt zu berücksichtigen (eigentlich habe ich gerade ein Spotlight im Shadowmap-Beispiel im Dev-Zweig hinzugefügt). Weiß jemand woher das kommt?

Hier ist ein Screenshot:
shadowmap

Das Beispiel soll hier live zu sehen sein:

https://rawgit.com/tieselune/three.js/selective-lighting/examples/webgl_lights_selective_lights.html

Ich bekomme jedoch einen Fehler:

Uncaught TypeError: Cannot read property 'set' of undefined
    at init (webgl_lights_selective_lights.html:117)
    at webgl_lights_selective_lights.html:67

@looeee : Sie müssen npm run build-uglify auf einem lokalen Host ausführen. Ich habe aus Gründen der Zusammenführung freiwillig keine Builds in meine Commits aufgenommen...

Oder sollte ich?

BEARBEITEN: Hier ist ein funktionierender Link zu einem anderen Zweig zu Testzwecken: https://rawgit.com/tieselune/three.js/selective-lights-test/examples/webgl_lights_selective_lights.html

Hey, +999999 von mir. Dies sollte implementiert werden (zumindest mit THREE.Layers )

$$('.comment-body').reduce((acc, el) => {
  let mat = el.textContent.match(/\+(\d+)/)
  let num = +(mat && mat[1] || 0)
  return acc + num
}, 0)
>> 1219997

🤔

@mrdoob er hat +Ns in diesem Thread berechnet

übrigens, +14570 für selektive Lichter

Dies ist unglaublich gut für die Feinabstimmung der Beleuchtung in einer höheren Abstraktion.

Im folgenden Stift möchte ich beispielsweise, dass die Beleuchtung für die DOM-Elemente in eine Richtung und für die Kugel in eine andere Richtung funktioniert, damit die Beleuchtung realistischer ist:

https://codepen.io/trusktr/pen/RjzKJx

Bestimmte Effekte, die wie ein Einzelpunktlicht aussehen, können durch die Kombination von zwei oder mehr Lichtern erzielt werden, die selektiv nur bestimmte Elemente beeinflussen.

In meinem vorherigen Beispiel kann ich zum Beispiel die Lichtintensität erhöhen, um einen gut aussehenden Schatten auf dem "DOM-Element" zu erhalten, aber dann sieht die Kugel etwas zu glänzend und hell aus. Wenn ich für die Sphere ein dunkleres Licht und für das "DOM-Element" ein helleres Licht haben könnte, könnte ich auf diese Weise etwas realistischeres erreichen, bei dem es für den Betrachter so aussieht, als ob es immer noch nur ein Licht gibt. Dann kann diese Art von Dingen in einer übergeordneten API abstrahiert werden, die den Anschein erweckt, als würde nur ein Licht manipuliert, wenn hinter der Szene tatsächlich zwei Three.js-Lichter im Spiel sind.

@WestLangley

Können Sie als Workaround die meisten Ihrer Anforderungen erfüllen, indem Sie für jeden Raum (und seine Lichter) eine separate Szene haben?

Hast du einen Link zu einem Beispiel für so etwas? Kann es andere unerwartete Rendering-Effekte auf das Ergebnis haben?

andere unerwartete Rendering-Effekte auf das Ergebnis?

Renderreihenfolge von transparenten Objekten, zum Beispiel - transparente Objekte in Szene 1 werden vor undurchsichtigen Objekten in Szene 2 gerendert.

Hast du einen Link zu einem Beispiel für so etwas?

hier habe ich einen nur für dich gemacht: https://jsfiddle.net/f2Lommf5/524/

Renderreihenfolge von transparenten Objekten, zum Beispiel - transparente Objekte in Szene 1 werden vor undurchsichtigen Objekten in Szene 2 gerendert.

Das ist was ich gedacht habe; es macht die Problemumgehung nur eine Problemumgehung für sehr begrenzte Fälle. Freue mich auf die echte Lösung!

Nun, Sie könnten argumentieren, dass das Problem nur auftreten würde, wenn Sie undurchsichtige Objekte von Szene2 von Szene1 durch die transparenten Objekte sehen könnten. aber wenn dies der Fall ist, sollten die Lichter auch durchgehen, und es gäbe keinen Grund, die Szenen von vornherein zu trennen. aber ich stimme zu, dass diese Art von Argument nicht wirklich überzeugend ist.

@makc Hier ist ein Beispiel für das Problem, das ich zu lösen versuche:

https://discourse.threejs.org/t/how-to-make-shadows-darker-on-transparent-objects/1389

Ich denke, eine selektive Beleuchtung würde dabei wirklich helfen.

@trusktr Ich denke, Sie können das lösen, indem Sie das Schattenmaterial von mrdoob ändern. es zeigt nur eine schwarz-weiße Schattentextur, und Sie können sie bei Bedarf transparent ändern

Masken in PlayCanvas scheinen für die selektive Beleuchtung wirklich einfach zu verwenden: https://forum.playcanvas.com/t/set-certain-object-to-not-receive-light/785.

können wir das einbinden? Ich denke, die Schattenprobleme waren auf Lambert-Shader zurückzuführen und haben nichts mit der Änderung des Codes zu tun. @tieselune

@ErikBehar Ich habe heute Nachmittag eigentlich nach etwas gesucht, das ich tun kann. Ich werde versuchen, den Code auf die neuesten Threejs zu aktualisieren und vielleicht eine Pull-Anfrage einzureichen? Es würde mich wirklich freuen zu wissen, dass ich einen echten Beitrag zu einem so großen Projekt geleistet habe. (Und gut, eine Bestätigung zu haben, dass dieser Fehler nichts mit meinen Änderungen zu tun hatte)

EDIT: Habe gerade festgestellt, dass sich dieser Teil des Codes stark geändert hat. Ich denke, ich werde ein wenig Zeit brauchen, da die Staaten, die ich zuvor verwendet habe, von WebGLRenderer zu WebGLLights gewechselt sind.

@tieselune Ich musste dies irgendwie in ein Projekt integrieren, also habe ich Ihren Code auf v93 portiert, siehe: https://github.com/ErikBehar/three.js/tree/selectiveLights

Ich kann eine PR machen, wenn ihr wollt? @mrdoob

@ErikBehar Nun, es sieht so aus, wie ich es mir vorgenommen habe, aber ich hatte nicht die Zeit, es vollständig zu tun. Ich denke, ich hätte die Filter- / Hash-Funktionen aus WebGLRenderer verschoben und sie dem WebGLLights-Zustandsobjekt hinzugefügt. Ich habe das Gefühl, dass sie jetzt dorthin gehören, da das Ebenensystem Teil des Staates und nicht Teil des Renderers ist.

@ErikBehar eine PR wäre toll!

@tieselune Ich werde gerne eine PR auf meine Gabel drücken lol = ] und ich werde die PR bald posten @mrdoob

Wie ist der Stand dazu? Ich habe den r94dev-Code von @ErikBehar in r94 zusammengeführt und dann r97 darin zusammengeführt, nur ein paar sehr einfache Konflikte (Versionsänderung, ein paar Variablen für selektive Beleuchtung und die Hash-Erstellung in renderers/WebGLRenderer.js; Ich würde stelle gerne eine PR ein. @tesselune Wenn Sie mir eine Vorstellung davon geben können, wo Sie den selektiven Beleuchtungszustand beabsichtigt haben, würde ich ihn gerne verschieben, testen und eine PR

BEARBEITEN:
Etwas später: Ich sehe, dass dies jetzt mit dem neuen Lighthash etwas Arbeit braucht, um zu funktionieren.

@VaelynPhi Ich denke, unabhängig davon, ob sie den Code von @ErikBehar akzeptieren oder nicht, ist es eine gute Idee, die PR einzureichen, nur um die veraltete zu ersetzen, falls andere Leute sie wollen, wie du selbst Tat

Entschuldigung, dass ich den Ball auf diese Leute fallen lassen muss = / ...

Keine Bange; Ich verstehe, beschäftigt zu sein. Leider konnte ich nicht einmal den Zweig, den Sie hatten, zum Laufen bringen, @ErikBehar; Ich beschloss, den Code durchzulesen, um ihn aufzuschlüsseln, damit ich den Zustand an die richtige Stelle verschieben und hoffentlich alle Fehler beheben konnte. Ich muss auch auf v94 noch zu einem funktionierenden Portstatus gelangen. Vielleicht kann ich es bereinigen und die PR einfügen , um es zu aktualisieren, wie

eine PR basierend auf:
https://github.com/ErikBehar/three.js/commit/ac0499b70b82bc7bb780100a8372fcdf318d1424#diff -5e43a0b5002eb2c419def3baf67d4e67
von @ErikBehar
Kann jemand mit einer Rezension und dem Beispiel helfen?

https://github.com/mrdoob/three.js/pull/15223

Hey Leute, wie ist der Status in diesem Fall? @tieselune @ErikBehar Darf ich dir bei etwas helfen? Wäre schön es nach 4 Jahren endlich umzusetzen

@flyrell Ich denke, wir könnten dieses Problem vielleicht schließen, da es in # 15223 vielleicht näher an der Fertigstellung zu sein scheint?

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen