Three.js: GLTFLoader: Das Ergebnis des Normal-Tangent-Testmodells ist falsch

Erstellt am 3. Juni 2017  ·  30Kommentare  ·  Quelle: mrdoob/three.js

Beschreibung des Problems

Ich habe versucht, das Normal-Tangent-Testmodell anzuzeigen.
Das angezeigte Ergebnis scheint sich jedoch von der von Khronos zu unterscheiden.

Three.js + Ergebnis des Normal-Tangens-Testmodells:
image

Khronos Sample Loader + Ergebnis des Normal-Tangent-Testmodells:
image

Ich denke, dass dieses Beispielmodell die gleichen Ergebnisse für links und rechts haben sollte.

Verwandte: https://emackey.github.io/testing-pbr/normal-tangent-readme.html

/ cc @emackey

Three.js Version
  • [x] Dev
  • [] r85
  • [] ...
Browser
  • [x] Alle von ihnen
  • [ ] Chrom
  • [ ] Feuerfuchs
  • [ ] Internet Explorer
Betriebssystem
  • [x] Alle von ihnen
  • [] Windows
  • [ ] Mac OS
  • [] Linux
  • [ ] Android
  • [] iOS
Hardwareanforderungen (Grafikkarte, VR-Gerät, ...)

ThinkPad X260 + Windows 10 + Intel HD Graphics 520

Bug Loaders

Hilfreichster Kommentar

Ich möchte insbesondere auf normalen Karten einen Satz aus der

Die normalen Vektoren verwenden OpenGL-Konventionen, bei denen + X richtig und + Y oben ist. + Z zeigt auf den Betrachter.

Mit diesem Satz können Modelle platzsparend ohne Tangentenvektoren versendet werden.

Lass es uns testen. Hier habe ich aus einem Fleck in einem Malprogramm eine miese Höhenkarte (Bump Map) gemacht:

TestHeightMap

Definieren wir dieses Höhenfeld als eine nach außen gerichtete Erhebung, bei der weiße Pixel näher am Betrachter und schwarze Pixel weiter entfernt sind.

Mit einem Online-Konverter (von fragwürdiger Qualität, aber wir werden das Ergebnis gleich untersuchen) habe ich dies von einer Höhenkarte in eine normale Karte konvertiert. Denken Sie daran, dass es hier kein 3D-Modell, keine UV-Koordinaten, Mikktspace-Berechnungen oder Geometrien gibt. Nur eine Höhenkarte, die in eine normale Karte umgewandelt wurde. Ich musste den Online-Konverter manuell gemäß den Anweisungen von glTF konfigurieren, sodass X richtig ist, Y oben ist und Z dem Betrachter zugewandt ist. Das ist das Ergebnis:

TestNormalMap

Lassen Sie uns das zurück in ein Malprogramm bringen und die Farbkanäle ausbrechen, um zu sehen, wohin diese Vektoren zeigen. Unten wurde jeder Farbkanal in ein eigenes Graustufenbild unterteilt. Denken Sie daran, dass diese so interpretiert werden, dass Schwarz -1.0 , Mittelgrau 0.0 und Weiß +1.0 .

TestNormalMap-Decomposed

Ich denke, der Online-Konverter hat das getan, was glTF verlangt hat, zumindest nachdem er es richtig konfiguriert hat. Im roten (X) Bild sehen wir, dass die Steigung rechts weiße Pixel (+1,0) aufweist und den X-Vektor auf den rechten Bildrand zeigt. Auf der linken Seite des roten Bildes zeigen schwarze Pixel (-1,0) den X-Vektor auf die linke Seite des Bildes. Im grünen (Y) Bild zeigen weiße Pixel entlang der oberen Neigung der Erhebung den Y-Vektor am oberen Rand des Bildes. Die Z-Werte sind am wenigsten intuitiv, aber denken Sie daran, dass die Spitze der Erhebung und die Rückplatte selbst beide auf den Betrachter zeigen und die Steigungen auf allen Seiten weg zeigen, sodass alle gleichmäßig dunkler sind.

Was ist, wenn wir dies in Blender Eevee laden, das (genau wie glTF) normale Karten im OpenGL-Stil akzeptiert? Was passiert, wenn die UV-Karte gedreht oder sogar skaliert wird, um invertiert zu werden?

NormalSpinTest

Es stellt sich heraus, dass dies gut funktioniert. In der Tat besteht der Sinn der Definition des Tangentenraums auf diese Weise nicht darin, Software in die Lage zu versetzen, mit den Vektoren verrückt zu werden, sondern Texturkünstlern eine gewisse Vernunft zu geben, indem sichergestellt wird, dass ihre normalen Karten unabhängig von der Geometrie richtig herum liegen.

Nicht jede Software verwendet jedoch die OpenGL-Konvention. Einige verwenden eine andere Konvention (manchmal auch als DirectX-Konvention bezeichnet), bei der die Y-Vektoren auf den unteren Rand des Bildes anstatt auf den oberen Punkt zeigen. Hier ist der zerlegte Y-Kanal meines Bildes in dieser Form. Die helleren Pixel zeigen zum unteren Bildrand.

TestNormalMap_DirectX-Green

Kann ich trotzdem erwarten, dass eine dieser normalen Karten im DirectX-Stil in Blender Eevee funktioniert?

NormalSpinTest_DirectX_v3

Blender hatte + Y erwartet. Die Mathematik ist falsch und die reflektierte Horizontlinie dreht sich ringsum.
Das gleiche passiert, wenn Sie eine normale Karte im OpenGL-Stil in eine Engine laden, die + Y erwartet hat.

Dies versucht das NormalTangentTest-Modell zu testen. Jede Zeile dreht die UV-Koordinaten in eine andere Ausrichtung und versucht sicherzustellen, dass die Reflexionen in diesen unterschiedlichen Ausrichtungen mit der rechten Seite nach oben bleiben.

Alle 30 Kommentare

Danke, dass du das hier geschrieben hast @ cx20.

Nur für mehr Kontext, hier sind einige verwandte Informationen und Probleme:

  • Ich habe ein ähnliches Problem in @donmccurdys ThreeJS glTF-Viewer, donmccurdy / three-gltf-viewer # 10, gemeldet. Aber ich denke jetzt, dass dies ein Fehler im glTF-Loader von ThreeJS ist, nicht im Viewer. Diese neue Ausgabe ist also besser platziert als meine alte Ausgabe.

  • In der obigen älteren Ausgabe war das Modell zum Himmel gerichtet, aber später habe ich es gedreht, um zum Horizont zu schauen. Dies macht es einfacher zu erkennen, wenn die Reflexionen nicht richtig sind, da sich der Horizont wie oben gezeigt verrückt dreht.

  • Die Verwendung einer normalen Karte durch das Modell wurde durch Diskussion in KhronosGroup / glTF # 952 als korrekt bestätigt.

  • Der Umgang von ThreeJS mit normalen Karten wurde in # 11315 in Frage gestellt.

  • BabylonJS hatte kürzlich ein ähnliches Problem, das hier gemeldet und hier behoben wurde . Hier ist eine Live-Demo des glTF 2.0-Laders von BabylonJS mit dem angewendeten Fix .

Gutes Schreiben, danke!

Das Modell scheint mit dem Hinzufügen dieser Zeile korrekt zu rendern:

materialParams.normalScale = new THREE.Vector2(-1, 1);

Aber ich bin nicht sicher, ob ich das Problem gut verstehe. Das Verständnis von # 11315 könnte hier helfen.

@donmccurdy Danke für deinen Rat.
Ich habe verstanden, dass sich das durch Anpassen von normalScale verbessert.
Wenn das glTF-Modell jedoch korrekt ist, ist es meiner Meinung nach für glTF Loader besser, damit umzugehen.

@ cx20 stimmte zu, dieser Fix wird jetzt in THREE.GLTF2Loader zusammengeführt.

Ich habe bestätigt, dass es behoben wird.

Three.js + Ergebnis des Normal-Tangens-Testmodells:
image

Dies hat sich irgendwann zwischen r101 und r104 zurückgebildet:
Screenshot from 2019-06-11 16-38-27

Siehe https://github.com/mrdoob/three.js/pull/15749 - Die Regression ist beabsichtigt und kann durch Einbeziehen von Tangenten in das Modell vermieden werden.

Idealerweise hätten wir eine JS-Implementierung zum Generieren von Mikktspace-Tangenten, um dies vollständig zu lösen, aber das ist ziemlich komplex.

# 15749 war mir bis jetzt nicht bekannt. Ich bin überrascht, dass wir die Tangenten in glTF so gut definiert haben, dass sie zur Laufzeit zumindest angenähert werden können.

Beachten Sie, dass der Blender-Exporter standardmäßig keine glTF-Tangenten exportiert, da dies dazu beiträgt, die Dateigröße niedrig zu halten, und die wichtigsten Implementierungen von glTF diesen Test alle ohne Tangenten bestanden haben. Ich vermute, dass diese Änderung die normale Zuordnung für die meisten glTF-Modelle in ThreeJS beeinträchtigt hat.

Ich brauche etwas Zeit, um alle damit verbundenen Probleme durchzulesen und ein tieferes Verständnis dafür zu bekommen, was passiert ist und warum. Ich denke jedoch, dass die glTF-Community diese hohe Priorität in Betracht ziehen sollte, um Modelle ohne Tangenten wieder korrekt wiederzugeben, da ich glaube, dass die meisten Modelle standardmäßig in dieser Kategorie sind.

Wiedereröffnung 😅

Ich vermute, dass diese Änderung die normale Zuordnung für die meisten glTF-Modelle in ThreeJS beeinträchtigt hat.

Ich glaube nicht, dass es etwas so Schweres ist - wir haben immer Tangenten in Echtzeit im Shader mit Derivaten erzeugt, und das tun wir immer noch. Wir haben zuvor einen Hack ( normalScale.y *= -1 ) eingefügt, der dieses spezielle Testmodell repariert, aber auch einige andere Beispiele gebrochen hat. Ich habe keine Erklärung dafür, wann das geholfen hat oder nicht, also haben wir den Hack entfernt, sobald wir gespeicherte Tangenten unterstützt haben - in diesem Fall wäre es sicherlich falsch gewesen. Jetzt sind die Modelle, die sich auf den Hack verlassen haben (und keine Tangenten enthalten), defekt, und Modelle, die vom Hack gebrochen wurden (und keine Tangenten enthalten), wurden repariert.

Ich denke jedoch, dass die glTF-Community diese hohe Priorität in Betracht ziehen sollte, um Modelle ohne Tangenten wieder korrekt wiederzugeben, da ich glaube, dass die meisten Modelle standardmäßig in dieser Kategorie sind.

Siehe oben. Im Allgemeinen glaube ich, dass wir Modelle ohne Tangenten angemessen rendern. Wir erzeugen jedoch keine Mikktspace-Tangenten gemäß der glTF-Spezifikation. Meines Wissens gibt es keine JS-Implementierung dafür, und unsere auf Derivaten basierende Shader-Implementierung ist einfach eine "meist gut genug" -Näherung. Dieses Beispielmodell ist ein absichtlich extremer Fall, der die Grenzen dieser Näherung aufzeigt.

Wir würden uns über eine Implementierung der JS-Mikktspace-Tangentengenerierung freuen. Das wäre eine gute Ergänzung zu THREE.BufferGeometryUtils. Aber der offizielle (native) Mikktspace-Code ist ziemlich lang, und ich habe noch nicht genug eingegraben, um zu sehen, wie viel davon für die Erzeugung von Tangenten erforderlich ist.

Wir haben zuvor einen Hack ( normalScale.y *= -1 ) eingefügt, der dieses spezielle Testmodell repariert, aber auch einige andere Beispiele gebrochen hat

Hat es andere glTF-Modelle speziell oder nur Beispiele im Allgemeinen gebrochen?

Es gibt zwei verschiedene Arten von Tangentenraum-Normalkarten in freier Wildbahn. Substance Painter nennt diese "DirectX-Normalen" und "OpenGL-Normalen", was nicht der beste Name dafür ist. Der Unterschied besteht speziell darin, dass der y -Kanal invertiert ist, was bedeutet, dass alle grünen Kanalwerte in der Textur invertiert sind. Das Multiplizieren von y *= -1 ist der richtige Weg, um eines in das andere umzuwandeln. Die sogenannten "DirectX-Normalen" verwenden ein linkshändiges Koordinatensystem, und glTF definiert ein rechtshändiges Koordinatensystem für Normal / Tangens / Bitangens.

Was ich vermute, ist, dass ThreeJS bei der automatischen Berechnung von Tangenten erwartet, dass die normale Karte mit dem gespiegelten Y-Stil (DirectX) erstellt wurde, und diesen Kanal für glTF rückwärts erhält, sodass der Flip erforderlich ist. Wenn die Tangenten geliefert werden, ist jedoch kein solcher Flip erforderlich.

Die Frage des Mikktspace ist meiner Meinung nach davon getrennt. Es ist bedauerlich, dass die Spezifikation Mikktspace erfordert und die meisten Implementierungen in etwa dem mit Screen-Space-Derivaten entsprechen. Ich weiß nicht, wie ähnlich die beiden sind, aber normale Karten, die im Mikktspace generiert wurden, scheinen ziemlich gut zu funktionieren, wenn sie mit der Näherung angezeigt werden, solange die Links- / Rechtshändigkeit der Karte korrekt ausgeführt wird.

(Es gibt auch einige Diskussionen darüber aus dem letzten Jahr in KhronosGroup / glTF-Sample-Models # 174)

Ich möchte insbesondere auf normalen Karten einen Satz aus der

Die normalen Vektoren verwenden OpenGL-Konventionen, bei denen + X richtig und + Y oben ist. + Z zeigt auf den Betrachter.

Mit diesem Satz können Modelle platzsparend ohne Tangentenvektoren versendet werden.

Lass es uns testen. Hier habe ich aus einem Fleck in einem Malprogramm eine miese Höhenkarte (Bump Map) gemacht:

TestHeightMap

Definieren wir dieses Höhenfeld als eine nach außen gerichtete Erhebung, bei der weiße Pixel näher am Betrachter und schwarze Pixel weiter entfernt sind.

Mit einem Online-Konverter (von fragwürdiger Qualität, aber wir werden das Ergebnis gleich untersuchen) habe ich dies von einer Höhenkarte in eine normale Karte konvertiert. Denken Sie daran, dass es hier kein 3D-Modell, keine UV-Koordinaten, Mikktspace-Berechnungen oder Geometrien gibt. Nur eine Höhenkarte, die in eine normale Karte umgewandelt wurde. Ich musste den Online-Konverter manuell gemäß den Anweisungen von glTF konfigurieren, sodass X richtig ist, Y oben ist und Z dem Betrachter zugewandt ist. Das ist das Ergebnis:

TestNormalMap

Lassen Sie uns das zurück in ein Malprogramm bringen und die Farbkanäle ausbrechen, um zu sehen, wohin diese Vektoren zeigen. Unten wurde jeder Farbkanal in ein eigenes Graustufenbild unterteilt. Denken Sie daran, dass diese so interpretiert werden, dass Schwarz -1.0 , Mittelgrau 0.0 und Weiß +1.0 .

TestNormalMap-Decomposed

Ich denke, der Online-Konverter hat das getan, was glTF verlangt hat, zumindest nachdem er es richtig konfiguriert hat. Im roten (X) Bild sehen wir, dass die Steigung rechts weiße Pixel (+1,0) aufweist und den X-Vektor auf den rechten Bildrand zeigt. Auf der linken Seite des roten Bildes zeigen schwarze Pixel (-1,0) den X-Vektor auf die linke Seite des Bildes. Im grünen (Y) Bild zeigen weiße Pixel entlang der oberen Neigung der Erhebung den Y-Vektor am oberen Rand des Bildes. Die Z-Werte sind am wenigsten intuitiv, aber denken Sie daran, dass die Spitze der Erhebung und die Rückplatte selbst beide auf den Betrachter zeigen und die Steigungen auf allen Seiten weg zeigen, sodass alle gleichmäßig dunkler sind.

Was ist, wenn wir dies in Blender Eevee laden, das (genau wie glTF) normale Karten im OpenGL-Stil akzeptiert? Was passiert, wenn die UV-Karte gedreht oder sogar skaliert wird, um invertiert zu werden?

NormalSpinTest

Es stellt sich heraus, dass dies gut funktioniert. In der Tat besteht der Sinn der Definition des Tangentenraums auf diese Weise nicht darin, Software in die Lage zu versetzen, mit den Vektoren verrückt zu werden, sondern Texturkünstlern eine gewisse Vernunft zu geben, indem sichergestellt wird, dass ihre normalen Karten unabhängig von der Geometrie richtig herum liegen.

Nicht jede Software verwendet jedoch die OpenGL-Konvention. Einige verwenden eine andere Konvention (manchmal auch als DirectX-Konvention bezeichnet), bei der die Y-Vektoren auf den unteren Rand des Bildes anstatt auf den oberen Punkt zeigen. Hier ist der zerlegte Y-Kanal meines Bildes in dieser Form. Die helleren Pixel zeigen zum unteren Bildrand.

TestNormalMap_DirectX-Green

Kann ich trotzdem erwarten, dass eine dieser normalen Karten im DirectX-Stil in Blender Eevee funktioniert?

NormalSpinTest_DirectX_v3

Blender hatte + Y erwartet. Die Mathematik ist falsch und die reflektierte Horizontlinie dreht sich ringsum.
Das gleiche passiert, wenn Sie eine normale Karte im OpenGL-Stil in eine Engine laden, die + Y erwartet hat.

Dies versucht das NormalTangentTest-Modell zu testen. Jede Zeile dreht die UV-Koordinaten in eine andere Ausrichtung und versucht sicherzustellen, dass die Reflexionen in diesen unterschiedlichen Ausrichtungen mit der rechten Seite nach oben bleiben.

Die Spezifikation muss noch eine konkrete Formel enthalten, wie eine Tangente für ein einzelnes Grundelement unter Berücksichtigung eines Grundelements und seiner UV-Koordinaten berechnet werden kann und welches W-Zeichen für Bitangens verwendet werden soll. "OpenGL-Normalen" und "DX-Normalen" sind nicht präzise genug, um die Formel abzuleiten. Sie beziehen sich vielleicht auf Konventionen, aber ich habe als Implementierer keine Ahnung, was ich damit anfangen soll.

Was ich derzeit mache, ist gespiegeltes TangentW von MikkTSpace auszusenden, um mit diesem bestimmten Beispiel übereinzustimmen, aber genau das hat funktioniert.

Hat es andere glTF-Modelle speziell oder nur Beispiele im Allgemeinen gebrochen?

Gemeldete Fehler betrafen insbesondere glTF-Modelle. Ich bezweifle jedoch, dass es genug Vertrauen in den Materialexport über FBX oder COLLADA gibt, um zu sagen, dass diese normalen Kartenkonventionen jemals gründlich verstanden und getestet wurden.

Der Unterschied besteht speziell darin, dass der y-Kanal invertiert ist, was bedeutet, dass alle grünen Kanalwerte in der Textur invertiert sind. Das Multiplizieren von y * = -1 ist der richtige Weg, um eins in das andere umzuwandeln.

Vielen Dank, dies ist eine viel bessere Rechtfertigung für unseren "Hack" als bei der Implementierung. 😇

Es ist bedauerlich, dass die Spezifikation Mikktspace erfordert und die meisten Implementierungen in etwa dem mit Screen-Space-Derivaten entsprechen.

Die Spezifikation ist richtig, dass MikkTSpace der robusteste Weg ist, um Tangenten zu erzeugen. Ich denke, es ist nicht allgemein die richtige Wahl, dies automatisch zur Laufzeit zu tun. Wenn billigere Alternativen für ein bestimmtes Modell richtig aussehen, gibt es keinen Grund, etwas teureres zu tun, das nicht besser aussieht. Die Spezifikationssprache könnte gelockert werden, um Annäherungen zu ermöglichen, aber ich habe kein starkes Gefühl dafür.

Die Spezifikation muss noch eine konkrete Formel enthalten, wie eine Tangente für ein einzelnes Grundelement unter Berücksichtigung eines Grundelements und seiner UV-Koordinaten berechnet werden kann und welches W-Zeichen für Bitangens verwendet werden soll.

Ich bin mir nicht sicher, ob der MikkTSpace-Algorithmus so einfach als diskrete Formel darzustellen ist. Fragen Sie nach einer Alternative zum kanonischen MikkTSpace-Code? Oder einige zusätzliche Informationen, die über die Anweisung zur Verwendung von MikkTSpace hinausgehen? @Themaister


Für die ursprüngliche Ausgabe klingt es so, als ob wir den Multiplikator normal.y *= -1 irgendwo wiederherstellen sollten. Es gibt drei mögliche Orte, um dies zu tun:

  • (a) in GLTFLoader für Netze ohne Tangenten
  • (b) in GLTFLoader für alle Netze
  • (c) in WebGLRenderer für alle Netze

Wenn threejs wirklich die DirectX-Konvention verwendet und z. B. Blender nicht, könnte ich einen Fall für (c) sehen. Im Interesse einer schnellen und sicheren Lösung bin ich jedoch geneigt, mit (a) zu gehen.

Was ich vermute, ist, dass ThreeJS bei der automatischen Berechnung von Tangenten erwartet, dass die normale Karte mit dem gespiegelten Y-Stil (DirectX) erstellt wurde.

Nein, three.js geht nicht davon aus, dass ...

three.js geht davon aus, dass + Y für den Tangentenraum "up" ist und das Erhöhen von V für den UV-Raum "up" ist.

Das heißt, three.js geht davon aus, dass sich uv (0, 0) in der unteren linken Ecke der Textur befindet, während die glTF-Spezifikation die obere linke Ecke annimmt. Aus diesem Grund setzt GLTFLoader texture.flipY auf false . (three.js setzt texture.flipY standardmäßig auf true .)

Wenn keine Tangenten vorhanden sind, verwendet three.js Bildschirmraumableitungen, um Tangenten zu schätzen. Dies geschieht mithilfe der Kettenregel. Bei dieser Berechnung wird davon ausgegangen, dass der Tangentenraum und der UV-Raum dieselbe Ausrichtung haben.

Bei ordnungsgemäß erstellten glTF-Modellen ist diese Annahme nicht korrekt. Sie sollten jedoch in der Lage sein, dies zu kompensieren, indem Sie normalScale.y = - 1 für jedes Modell festlegen, das der glTF-Spezifikation ordnungsgemäß entspricht.

Es scheint mir auch, dass wir dies automatisch beheben können, indem wir das Flag flipY im Shader beachten.

Wenn das Setzen von normalScale.y nicht funktioniert, ist etwas anderes los.

Vielen Dank für diese Klarstellung. Ich denke, wir haben hier einen Weg nach vorne.

Es scheint mir auch, dass wir dies automatisch beheben können, indem wir das Flag flipY im Shader berücksichtigen.

Ja, mit Ausnahme von Fällen, in denen der glTF seine eigenen Tangentenvektoren liefert, richtig? Ich würde erwarten, dass nur die automatisch berechneten Tangenten den flipY -Test und die entsprechende Negation von y benötigen.

Wenn dies nicht der Fall ist, würde dies bedeuten, dass in meinem NormalTangentMirrorTest -Modell falsche Tangenten codiert sind, was bedeutet, dass der Blender-glTF-Exporter selbst die falschen Tangenten in glTF-Modelle einfügt.

Bearbeiten: Ich glaube, ich habe die Richtigkeit der exportierten Tangentenvektoren bestätigt und sie müssen nicht umgedreht werden. Ich kann bei Bedarf weitere Details dazu posten.

Es scheint jedoch die richtige Aktion zu sein, normalScale.y nur dann umzudrehen, wenn automatisch generierte Tangenten (nicht mitgelieferte Tangenten) mit dem Flag flipY verwendet werden. Gedanken?

In meinem vorherigen Beitrag habe ich erklärt, wie invertierte Normalen manuell kompensiert werden, wenn keine Attributtangenten vorhanden sind. Es sollte nichts zu kompensieren sein, wenn Tangenten vorhanden sind, da keine Ableitungen des Bildschirmraums verwendet werden.

Ich schlug auch vor, dass wir dies möglicherweise automatisch beheben können, indem wir das Flag flipY im Shader berücksichtigen. Ich habe nicht gesagt, dass wir dies automatisch beheben würden, indem wir normalScale.y umdrehen. Ich denke nicht, dass wir die Einstellungen des Benutzers ändern sollten.

Bevor wir diesen Weg gehen, denke ich jedenfalls, dass wir diese Hypothese unbedingt überprüfen müssen:

[Y] Sie sollten in der Lage sein, dies zu kompensieren, indem Sie normalScale.y = - 1 für jedes Modell festlegen, das die glTF-Spezifikation ordnungsgemäß einhält.

Wir müssen eine Erklärung für jedes Modell haben, das nicht korrekt gerendert wird.

Ich denke nicht, dass wir die Einstellungen des Benutzers ändern sollten.

Ja, entschuldigung, ich hatte nicht vor, diese Art von Implementierungsdetails zu diktieren. Ich versuche nur sicherzustellen, dass es kein Missverständnis darüber gibt, was _honoring the flipY flag_ mathematisch bedeutet, um eine Tangente für den Bildschirmraum zu erzeugen.

Wir müssen eine Erklärung für jedes Modell haben, das nicht korrekt gerendert wird.

Das klingt so, als könnte es sich möglicherweise um eine große Menge handeln. Wenn es tatsächlich Modelle gibt, die etwas radikal anderes tun als die offiziellen Testmodelle und dennoch als gültige Verwendung normaler Karten in glTF angesehen werden könnten, wäre es wichtig, dies zu entdecken. Die Testmodelle sollen gültige Verwendungen normaler Karten für statische (nicht transformierte) Geometrie abdecken. Insbesondere wenn Sie sich auf vom Betrachter erzeugte Tangentenvektoren verlassen, sollte es keine Möglichkeit geben, das Modell in einem anderen Koordinatensystem zu konstruieren und dennoch zu behaupten, dass es eine gültige glTF ist.

Ich gehe davon aus, dass dies in engem Zusammenhang mit diesem Problem steht. https://github.com/KhronosGroup/glTF-Sample-Models/issues/174

@ WestLangley Folgendes habe ich bisher gefunden. Standardmäßig sieht khronos-NormalTangentTest (ohne Tangenten) falsch aus:
NormalTangentTest
Wenn ich normalScale.y = -1 setze, ist es immer noch falsch:
NormalTangentTestNegY
Wenn ich stattdessen normalScale.x = -1 setze, sieht es richtig aus:
NormalTangentTestNegX
Mit der möglichen Ausnahme, dass das Rendering etwas pixelig aussieht, insbesondere auf dem Goldreflektor. Wird dies mit der Annäherung an den Bildschirmraum oder einem Indikator für einen anderen Fehler erwartet?

Wenn jemand andere gute Testmodelle ohne Tangenten hat, senden Sie sie mir bitte. Ich möchte sicherstellen, dass ich eine repräsentative Stichprobe habe, und feststellen, ob es eine gibt, die nicht der glTF-Spezifikation entspricht.

@elalish Das Testbed macht für mich keinen Sinn, es hat für mich nie Sinn gemacht und wird es wahrscheinlich auch nie. Also ... ich werde Ihnen nicht helfen, es zu erklären.

Dieses Beispiel ist meiner Meinung nach zu verschleiert. Wir brauchen einen kohärenten Testfall, der genügend Bilder liefert, um zu verstehen, was passiert.

Übrigens hatten wir früher ein VertexTangentHelper (# 3511), das wiederbelebt werden konnte, um die Puffergeometrie zu unterstützen.

@ WestLangley Ich wünschte, ich wüsste, wie man NormalTangentTest klarer macht. Es macht nichts Außergewöhnliches, es dreht einfach die Ausrichtung (im UV-Raum) jeder Probe. Die drei Säulen dienen nur zum Testen verschiedener Materialien, die Goldsäule könnte alleine ausreichen. Abgesehen davon denke ich nicht, dass das Testmodell viel einfacher werden kann und trotzdem diese unterschiedlichen UV-Orientierungen testet.

Trotz der UV-Rotationen ist das Bild der normalen Karte ziemlich konsistent darüber, in welche Richtung die Vektoren zeigen, wenn die normale Karte als 2D-Bild betrachtet wird. In einer 2D-Ansicht des Bildes weisen die rechten Seiten aller Halbkugeln hohe Rotkanalwerte auf, und die Oberkanten aller Halbkugeln weisen unabhängig von den UV-Koordinaten hohe Grünkanalwerte auf. Dies folgt der glTF-Spezifikation, dass Rot (+ X) im UV-Raum auf die rechte Seite der Textur und Grün (+ Y) am oberen Rand der Textur im UV-Raum zeigt. Man braucht keine Tangentenvektoren, um diese Arbeit zu machen: Eine einfache Schätzung des Bildschirmraums im Allgemeinen, in welche Richtung die + U-Achse für ein gegebenes Dreieck ist, reicht aus, um die Tangenten- und Bi-Tangentenvektoren zu berechnen, wie es BabylonJS und CäsiumJS tun. und natürlich auch ThreeJS, aber mit einigen noch ungeklärten NormalScale-Achsenflips.

Es gibt einen bekannten Punkt der Verwirrung mit der Verwendung des Flags flipY durch glTF, bei dem V -Koordinaten im UV-Raum invertiert werden. Ich glaube, Sie sind sich dessen bereits bewusst. Ich habe lange vermutet, dass dies eine Rolle im ungeklärten normalScale-Flip spielt.

Es gibt auch einen kleinen Backfehler im Bild (meine Schuld, ich war vor Jahren ein neuer Benutzer von Substance Painter). Besonders am flachen Teil der Goldhalbkugeln ist eine leichte diagonale Naht sichtbar. Dies sollte jedoch den Gesamteffekt nicht beeinträchtigen. Der Hauptrundteil des Backens kam gut heraus und zeigt gut, dass "oben" und "rechts" über das gesamte 2D-Bild der normalen Textur konstant sind, unabhängig davon, ob 3D- oder UV-Koordinaten in alle Richtungen und Tangenten gedreht werden weggelassen werden.

Dies ist ein wichtiger Effekt für Künstler, die vor dem Erstellen der 3D-Geometrie das Wiederholen normaler Kartentexturen erstellen, da der Künstler vor dem Erstellen des Texturbilds keinen Zugriff auf UV- oder Tangentenkoordinaten benötigt.

@ WestLangley Ich mag diesen Test nur, weil er der beste ist, den ich je gesehen habe, auch bekannt als der einzige. Gerne verwende ich jedes andere Testmodell, auf das ich verweise.

Außerdem wird die Handlung dicker: Der ursprüngliche Test ist ein doppelseitiges Material. Aufgrund von # 17804 habe ich beschlossen, es einseitig zu versuchen. Standardmäßig ist es immer noch falsch, aber jetzt bekomme ich die richtige Antwort, wenn ich normalScale.y = -1 setze:
NormalTangentTestFrontNegY
Zumindest hoffe ich, dass wir uns einig sein können, dass das Ändern von doubleSided keinen Einfluss auf das Rendering der Vorderseite haben sollte.

@emackey Ein weiteres Testmodell, das meiner Meinung nach hilfreich sein könnte, wäre ein glänzender Würfel mit geschweißten Normalen und einer entsprechenden Normalkarte, die so gestaltet ist, dass er würfelförmig statt abgerundet ist. Wahrscheinlich zwei Versionen, eine mit und eine ohne mitgelieferte Tangenten. Leider fehlt mir die Fähigkeit zum Verfassen, es selbst zu tun. Alles, was ich anbieten kann, ist vielen Dank, wenn Sie es für uns machen: beten Sie:

@emackey Vielen Dank für all Ihre Arbeit daran. Ich weiß das sehr zu schätzen. Ich verstehe all die verschiedenen Probleme, die bei Künstlern auftreten können - und Probleme, die überwunden werden müssen.

Vielleicht wären Sie bereit, mit @elalish zusammenzuarbeiten und die von ihm gewünschten glb-Modelle bereitzustellen. Ich gehe davon aus, dass uns das helfen würde zu verstehen.

@elalish Wir haben diese Probleme bereits angesprochen. Irgendwann hatte ich den Eindruck, dass alles funktioniert. Wenn es einen einfachen Testfall gibt, kann ich mit bisect feststellen, wo etwas kaputt gegangen ist.

glänzender Würfel mit geschweißten Normalen und einer entsprechenden normalen Karte, die würfelförmig statt abgerundet ist.

Fertig: normal_map_flat.zip . Ich habe das vom Draco-Team geschriebene Tangentenbeispiel genommen und eine zusätzliche Version ohne das Tangentenattribut erstellt.

Irgendwann hatte ich den Eindruck, dass alles funktioniert.

Ich denke, wir haben einen Zustand erreicht, in dem alles funktioniert, wenn das Modell Tangenten enthält. Wenn nicht, sind die Dinge normalerweise in Ordnung, aber es sind einige Randfälle möglich, insbesondere um UV-Nähte. In diesem Fall empfehlen wir Benutzern, Tangenten hinzuzufügen. Oder, wie @emackey in https://github.com/mrdoob/three.js/issues/11438#issuecomment -507027586 erwähnt, sollten wir den Flip normalScale.y *= -1 in GLTFLoader möglicherweise nur in Fällen wiederherstellen, in denen das Netz vorhanden ist lässt Scheitelpunkttangenten weg.

@donmccurdy Danke. Ich habe heute keine Zeit mehr für dieses Problem, aber ich habe immer noch Probleme mit den flachen Würfelseiten. Wenn Sie Ihr Modell so bearbeiten, dass es eine glänzende Oberfläche hat ( metallicFactor: 1, roughnessFactor: 0.1 ), werden die Reflexionen an den Seiten des Würfels ziemlich viel herumschwimmen.

Ich sehe den gleichen Effekt in meinem eigenen Testmodell. Schlimmer noch, es ist ein anderer Effekt, wenn ich das normale Backen in Substance Painter mache als das Backen in Blender-Zyklen. Jedes Programm backt es so, dass es für sein eigenes Ansichtsfenster korrekt ist, aber es ist nicht perfekt flach, wenn es in das andere Programm geladen wird, selbst ohne glTF im Mix. Es ist sehr nah, aber auf einer so flachen Oberfläche verwandeln die kleinsten Unterschiede es in einen Funhouse-Spiegel, und das nicht auf gute Weise.

Ich glaube, ich sehe einen subtilen Unterschied in der Art und Weise, wie normale Vektoren (oder TBN-Raum) zwischen Scheitelpunkten über die Fläche eines Dreiecks interpoliert werden, in SP gegen Blender gegen die verschiedenen WebGL-Engines. Ich habe Gimp verwendet, um einen "Unterschied" zwischen einem SP-Auflauf und einem Blender-Auflauf zu erzielen, und er wurde an jedem Scheitelpunkt schwarz (identische RGB-Werte) ausgegeben, aber der Abstand zwischen den Scheitelpunkten zeigt wirbelnde Unterschiede von sehr schwacher Intensität.

Ich würde subtile Fun-House-Effekte erwarten, aber nicht das, was ich derzeit bekomme (die No-Tangents-Version):
image
Die Version mit Tangenten ist nicht wirklich besser, was mich zu der Frage führt, ob dies wirklich eine gültige glTF ist:
image
@emackey Fühlen Sie sich qualifiziert, uns mitzuteilen, ob eines oder beide der bereitgestellten Modelle von @donmccurdy tatsächlich gültige glTF sind? Wenn ja, haben wir meiner Meinung nach ein großes Problem.

Dieser spezielle Würfel ist ein so extremes Beispiel, dass ich nicht wirklich weiß, was ich sagen soll oder ob physikalisch realistische Reflexionen eine faire Erwartung sind. Normale Karten dienen zum Hinzufügen von Details wie Unebenheiten und Beulen und nicht zum Verformen der gesamten Oberfläche des Netzes. Es war einfach eine sehr effektive Methode, um zu testen, ob Tangenten richtig gelesen oder generiert werden. Ich weiß, dass die Änderung von normalScale.y *= -1 nie ausreichte, um sie zu beheben. Dies war eines der Beispiele, die uns dazu veranlassten, gespeicherte Tangenten überhaupt zu unterstützen.

Die Reflexionen sehen auch in BabylonJS wild aus:
Screen Shot 2019-10-23 at 4 00 02 PM

Wenn das einzige festgestellte Problem bei NormalTangentTest liegt und keine Benutzer Modelle vorgeschlagen haben, die in der Praxis falsch gerendert werden, sollten wir hier möglicherweise eine Änderung vornehmen.

Ich bin immer noch damit einverstanden, den Multiplikator normalScale.y *= -1 wiederherzustellen, aber das Fehlen von Beispielen für das Problem scheint eher ein Hinweis darauf zu sein, dass das Problem geringfügig ist, als ein Hinweis darauf, dass wir solche extremen Beispiele erstellen müssen.

Wenn das einzige festgestellte Problem bei NormalTangentTest liegt und keine Benutzer Modelle vorgeschlagen haben, die in der Praxis falsch gerendert werden, sollten wir hier möglicherweise eine Änderung vornehmen.

Korrektur: https://github.com/mrdoob/three.js/issues/17804 deutet darauf hin, dass sich bei doppelseitigen Materialien tatsächlich etwas zurückgebildet hat. Das scheint eine weitere Untersuchung wert zu sein, obwohl wir der Einfachheit und Vernunft halber vielleicht den verfluchten Würfel vorerst in Ruhe lassen sollten. 😇

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen