Three.js: Normalen drehten sich um einige Teile des Netzes, die doppelseitige Materialien haben

Erstellt am 23. Okt. 2019  ·  36Kommentare  ·  Quelle: mrdoob/three.js

Beschreibung des Problems

Beim Upgrade von 107 auf 108 habe ich festgestellt, dass Teile meines Modells jetzt so aussehen, als hätten sie Normalen umgedreht. Dies tritt nur bei doppelseitigen Materialien auf.
Siehe hier: https://vaulted-jonquil.glitch.me/

So sollte es aussehen, wobei das Muster auf beiden Rädern eingerückt ist. So war es in 107
Screen Shot 2019-10-23 at 3 51 35 PM

Im Jahr 108 sieht eines der Räder so aus, als würde es herausspringen:
Screen Shot 2019-10-23 at 3 51 27 PM

Three.js Version
  • [x] r108
Browser
  • [x] Alle von ihnen
Betriebssystem
  • [x] Alle von ihnen
  • [] Windows
  • [ ] Mac OS
  • [] Linux
  • [ ] Android
  • [] iOS
Bug Regression

Hilfreichster Kommentar

Behebt es!
Screen Shot 2019-11-21 at 10 02 54 AM

Alle 36 Kommentare

@pushmatrix Können Sie bestätigen, ob dieses Modell seine eigenen Tangenten liefert oder nicht? Ich bin gespannt, ob dies mit # 11438 zusammenhängt.

Ich glaube nicht, dass es seine eigenen Tangenten spezifiziert

Unter Verwendung eines anderen Testfalls zeigt git bisect auf # 17586 als PR, die das Problem ausgelöst hat, wenn das Netz doppelseitig ist und eine negative Skala X aufweist. Dies war jedoch in r.109, nicht in r.108.

Dies wurde an dem Modell aus dieser PR nicht getestet, da dieses Modell nicht verfügbar ist.

Hier ist der Test glb
rad.glb.zip

Von vor 3 Jahren: https://github.com/mrdoob/three.js/issues/10331#issue -194807426

Grundsätzlich scheint es, dass ... gl_FrontFace mit doppelseitigen Materialien auf Adreno-GPUs nicht richtig funktioniert.

Ist dies immer noch ein Problem, das wir berücksichtigen müssen?

// //

Dieses Modell scheint auf meinem Computer korrekt zu rendern, wenn wir die Adreno-Problemumgehung in normalmap_pars_fragment entfernen:

#ifdef DOUBLE_SIDED

    // Workaround for Adreno GPUs gl_FrontFacing bug. See #15850 and #10331

    bool frontFacing = dot( cross( S, T ), N ) > 0.0;

    mapN.xy *= ( float( frontFacing ) * 2.0 - 1.0 );

#else

    mapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );

#endif

Hmm, ich erinnere mich, dass ich diesen Kommentar auch gelesen habe; Ich glaube, ich bin darauf gestoßen, als ich mir diesen Fehler angesehen habe, der anscheinend in r108 behoben wurde (zumindest das Upgrade hat ihn für uns behoben): https://github.com/GoogleWebComponents/model-viewer/issues/740

Vielleicht ist es verwandt? FWIW, ich habe einige Rückmeldungen zu alten Adreno-GPUs erhalten, daher sind sie anscheinend immer noch ziemlich verbreitet.

Nur zur Bestätigung, dies geschieht immer noch in dev :

Screen Shot 2019-10-25 at 4 06 51 PM

Nur um zu bestätigen, passiert dies immer noch in dev:

Recht. Aber nicht, wenn Sie die Adreno-Fehlerumgehung entfernen.

Aber nicht, wenn Sie die Adreno-Fehlerumgehung entfernen.

Wie wäre es, wenn Sie die Problemumgehung vorerst entfernen und dann nach einer anderen Lösung suchen? Die aktuelle Implementierung führt zu falschen Grafiken, unabhängig davon, welche Plattform Sie verwenden.

@ Mugen87 In diesem speziellen Fall glaube ich, dass die Geometrien Spiegel voneinander sind, aber sie haben dieselbe normale Karte.

Ich stimme mit Ihnen ein. Ich habe viele Stunden investiert, um eine Adreno-kompatible Problemumgehung zu finden, die in jedem Anwendungsfall korrekt ist.

Bei der Inspektion des Radmodellmodells hat jedes Rad seine eigene UV-Schale. Es teilt keinen.
Und die Scheitelpunktreihenfolge ist entgegengesetzt.

Die Gesichtsausrichtung ist jedoch zumindest in Blender gleich.

Screen Shot 2019-11-18 at 11 21 05 AM

Ich bin mir also nicht sicher, ob es sich um einen Fehler in r108 handelt oder ob r108 jetzt die Dinge richtig macht. ¯_ (ツ) _ / ¯

@pushmatrix kannst du mit Unity oder Blender vergleichen?

@mrdoob

Mixer 2.8

Screen Shot 2019-11-20 at 8 27 27 AM

Einheit

Screen Shot 2019-11-20 at 8 40 30 AM

Sketchfab

Screen Shot 2019-11-20 at 8 32 48 AM

@ Pushhmatrix

Unity ist schwer zu erkennen, da das Licht in die gleiche Richtung wie die Kamera gerichtet ist, aber sieht es so aus, als ob Unity auch falsch ist? 🤔

@mrdoob

Ja, es hängt ein bisschen von der Beleuchtung ab, die letztendlich eine Illusion ist und so aussieht, als wäre sie an einigen Stellen aufgetaucht. Aber wenn Sie sich drehen, verschwindet es.

Hier ist es in einem anderen Licht, wo es richtig erscheint
Screen Shot 2019-11-20 at 2 36 16 PM

@mrdoob Die Vorderseite hat eine Wicklungsreihenfolge gegen den Uhrzeigersinn in drei.js. Typischerweise haben die UVs der 3 Eckpunkte jeder Fläche auch eine Wicklungsreihenfolge gegen den Uhrzeigersinn auf der UV-Karte.

In diesem Beispiel ist meine Vermutung, dass das Modell links UVs gegen den Uhrzeigersinn und das Modell rechts UVs im Uhrzeigersinn hat. Das Modell rechts wird in three.js falsch gerendert, wenn doubleSide true .

AFAIK, das Entfernen der Adreno-Problemumgehung behebt das Problem für Nicht-Adreno-GPUs.

@pushmatrix Ihr Unity-Beispiel scheint Richtungslichter aus zwei Richtungen zu haben. Das macht es schwierig zu erkennen, was los ist. Ein einzelnes Licht kann vorzuziehen sein.

@WestLangley Ich verwende dieselbe Umgebungskarte, die der Modellbetrachter verwendet, aber wahrscheinlich hat sie nicht dieselbe Drehung. Ich werde es mit einem einzigen Licht versuchen.

@WestLangley Licht in einer Richtung, das sich dreht. Ich habe das Gefühl, eine optische Täuschung zu betrachten

unity

Scheint, als würde Unity die Rillen ein- und ausblenden lassen, je nachdem, wie das Licht darauf trifft, aber zumindest ist es für beide gleich.

Threejs ist auch konsistent, aber man sieht definitiv immer herausgesprungen aus:
wheels

Ich habe das Gefühl, dass in der Einheit etwas nicht stimmt ...
Als ob es so etwas braucht. material.normalMapScale.x = -1 .

@ WestLangley

@mrdoob Die Vorderseite hat eine Wicklungsreihenfolge gegen den Uhrzeigersinn in drei.js. Typischerweise haben die UVs der 3 Eckpunkte jeder Fläche auch eine Wicklungsreihenfolge gegen den Uhrzeigersinn auf der UV-Karte.

In diesem Beispiel ist meine Vermutung, dass das Modell links UVs gegen den Uhrzeigersinn und das Modell rechts UVs im Uhrzeigersinn hat. Das Modell rechts wird in three.js falsch gerendert, wenn doubleSide true .

AFAIK, das Entfernen der Adreno-Problemumgehung behebt das Problem für Nicht-Adreno-GPUs.

Danke, das macht Sinn. Ich denke, es verdient noch mehr Nachforschungen. Wenn Sketchfab auf allen Geräten korrekt aussieht, müssen wir uns möglicherweise deren Shader ansehen.

Ich habe mir heute den jeweiligen Shader-Code angesehen und es scheint, dass sie nicht "Per-Pixel Tangent Space Normal Mapping" verwenden.

Laut diesem Beitrag erwartet Sketchfab tangentiale Definitionen in Assets oder diese Daten sind
generieren basierend auf UV-Koordinaten. Das entspricht dem, was ich im GLSL-Code gesehen habe.

Wenn ich dem Modell über BufferGeometryUtils.computeTangents() Tangenten hinzufüge und Material.vertexTangents auf true setze, scheint das Ergebnis in Ordnung zu sein:

image

Übrigens: Ist es in Ordnung, Codefragmente von Sketchfab in diesem Beitrag zu teilen ^^? Immerhin ist es nicht Open Source.

Aus Gründen der Konsistenz ist hier Sketchfab mit 1 Richtungslicht, das sich hin und her bewegt:

sketchfab

Ja, eine Sache, die Sie beachten sollten, ist, dass Sketchfab die Verarbeitung am Ende durchführt, wenn Sie ein Modell hochladen. Es ist also sehr wahrscheinlich, dass sie Dinge generieren / ändern. Was Sie anzeigen, ist keine glTF-Datei, sondern eine in ihr eigenes Format konvertierte glTF-Datei.

@pushmatrix Können Sie bitte zeigen, dass # 17958 für Ihr Modell funktioniert?

three.js berechnet Tangenten im Fragment-Shader. Ich glaube, es funktioniert richtig, wenn ein Hack zur Aufnahme bestimmter fehlerhafter Adreno-GPUs entfernt wird. Siehe # 17958.

// //

Sketchfab berechnet Tangenten auf der CPU, wenn Tangenten erforderlich sind und nicht vom Modell bereitgestellt werden. ( @donmccurdy Dies ist, was die glTF-Spezifikation erfordert.)

three.js kann das auch, aber es bedeutet, allen eingebauten Geometrien korrekte Tangenten hinzuzufügen. three.js muss auch den MIKKTSpace-Algorithmus implementieren, um ComputeTangents() zu ersetzen. Da three.js sowohl indizierte als auch nicht indizierte Geometrien unterstützt, gehe ich davon aus, dass dies einen erheblichen Aufwand erfordert.

Behebt es!
Screen Shot 2019-11-21 at 10 02 54 AM

Okay, die Lösung hier scheint also darin zu bestehen, die Adreno-Problemumgehung (# 17958) zurückzusetzen und den Leuten zu empfehlen, BufferGeometryUtils.computeTangents() wenn das Modell keine Tangenten aufweist und Adreno-GPUs unterstützen sollen (# 15850). .

Klingt gut?

Eine andere Lösung besteht darin, BufferGeometryUtils.computeTangents() in der Engine automatisch aufzurufen, wenn dies nicht bereitgestellt wird, und den gesamten Code zu entfernen, der Tangenten im Fragment-Shader berechnet ... 🤔

BufferGeometryUtils.computeTangents() benötigt derzeit einen Index, sodass er nicht im Kern verwendet werden kann. Ich denke jedoch, es wäre vorzuziehen, wenn three.js irgendwann Tangenten gemäß MIKKTSpace erzeugen und dann perturbNormal2Arb() entfernen könnte.

@ WestLangley schrieb:

Dies bedeutet, dass allen integrierten Geometrien korrekte Tangenten hinzugefügt werden.

Meine Meinung ändern ... Tangenten sind nicht unbedingt erforderlich. Stattdessen würde ich die Methode BufferGeometry.computeTangents() wiederherstellen und diese Methode für alle integrierten Geometrien "überschreiben", für die wir genaue Tangenten analytisch festlegen können.

// //

Eine andere Lösung besteht darin, BufferGeometryUtils.computeTangents () in der Engine automatisch aufzurufen, wenn dies nicht bereitgestellt wird, und den gesamten Code zu entfernen, der Tangenten im Fragment-Shader berechnet ...

Das klingt für mich richtig.

BufferGeometryUtils.computeTangents () benötigt derzeit einen Index, sodass er nicht im Kern verwendet werden kann.

Ich denke das ist leicht zu beheben. Und es muss behoben werden, um https://github.com/mrdoob/three.js/issues/17804#issuecomment -557135610 zu unterstützen.

Es wäre vorzuziehen, wenn three.js irgendwann Tangenten gemäß MIKKTSpace erzeugen und dann perturbNormal2Arb () entfernen könnte ...

Ich weiß nicht, ob MikkTSpace die Fragment-Shader-Berechnung unbedingt ersetzen sollte. Der Shader hat fast keine Leistungskosten und funktioniert für die meisten Modelle einwandfrei. Das Berechnen von Tangenten hat jedes Mal Vorabkosten pro Scheitelpunkt und keinen Vorteil, außer in diesen speziellen Fällen. 😕 Trotz der Angaben in der glTF-Spezifikation fällt es mir schwer, dies standardmäßig zu rechtfertigen.

Es wäre schön, wenn BufferGeometryUtils.computeTangents den MikkTSpace-Ansatz implementieren könnte - das ist der beste Algorithmus, wenn Sie sie vorberechnen müssen. Es wäre jedoch wahrscheinlich einfacher, MikkTSpace in Tools wie glTF-Pipeline oder gltfpack zu integrieren, die die vorhandene native Implementierung verwenden können, und die Berechnung im Voraus offline durchzuführen.

@donmccurdy

Aber sagen wir ... im Anwendungsfall <model-viewer> gibt es meines Erachtens keinen zuverlässigen Weg, um festzustellen, ob der Benutzer eine Adreno-GPU hat, aber wir möchten richtig aussehen (https: // github. com / GoogleWebComponents / model-viewer / issue / 740).

Sollte <model-viewer> (und andere Projekte, die x-gpu-Unterstützung wünschen) BufferGeometryUtils.computeTangents aufrufen, wenn keine Tangenten bereitgestellt werden, oder sollte Three?

@ Pushhmatrix

Haha, ich habe gerade gemerkt, woher diese Räder kommen 😁

https://bumbleride.com/products/era?variant=20719969599599

Screen Shot 2019-11-22 at 3 52 19 PM

@mrdoob 🕵

Okay, dann lassen Sie uns die Problemumgehung vorerst zurücksetzen.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen