Three.js: Normales retournées sur certaines parties du maillage qui ont des matériaux double face

Créé le 23 oct. 2019  ·  36Commentaires  ·  Source: mrdoob/three.js

description du problème

En passant de 107 à 108, j'ai remarqué que certaines parties de mon modèle semblent maintenant avoir inversé les normales. Cela se produit uniquement avec des matériaux double face.
Voir ici: https://vaulted-jonquil.glitch.me/

Voici à quoi cela devrait ressembler, le motif étant en retrait sur les deux roues. C'était comme ça en 107
Screen Shot 2019-10-23 at 3 51 35 PM

En 108, l'une des roues a le motif qui ressemble à une sortie:
Screen Shot 2019-10-23 at 3 51 27 PM

Version Three.js
  • [x] r108
Navigateur
  • [x] Tous
OS
  • [x] Tous
  • [ ] Les fenêtres
  • [] macOS
  • [] Linux
  • [ ] Android
  • [] iOS
Bug Regression

Commentaire le plus utile

Le corrige!
Screen Shot 2019-11-21 at 10 02 54 AM

Tous les 36 commentaires

@pushmatrix Pouvez-vous confirmer si ce modèle fournit ou non ses propres tangentes? Je suis curieux de savoir si cela peut être lié à # 11438.

Je ne crois pas qu'il spécifie ses propres tangentes

En utilisant un cas de test différent, git bisect pointe vers # 17586 comme PR qui a initié le problème si le maillage est double face et a une échelle négative X. C'était en r.109, pas en r.108, cependant.

Cela n'a pas été testé sur le modèle de ce PR car ce modèle n'est pas disponible.

Voici le test glb
roues.glb.zip

Depuis 3 ans: https://github.com/mrdoob/three.js/issues/10331#issue -194807426

Fondamentalement, il semble que ... gl_FrontFace ne fonctionne pas correctement avec des matériaux double face sur les GPU Adreno.

Est-ce encore un problème que nous devons résoudre?

//

Ce modèle semble s'afficher correctement sur ma machine si nous supprimons la solution de contournement Adreno dans normalmap_pars_fragment :

#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, je me souviens avoir lu ce commentaire aussi; Je pense que je l'ai rencontré en regardant ce bogue, qui a apparemment été corrigé dans r108 (au moins la mise à niveau l'a corrigé pour nous): https://github.com/GoogleWebComponents/model-viewer/issues/740

Peut-être que c'est lié? FWIW, j'ai eu des retours sur les anciens GPU Adreno, donc apparemment ils sont encore assez courants.

Juste pour confirmer, cela se produit toujours dans dev :

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

Juste pour confirmer, cela se produit toujours en dev:

Droite. Mais pas si vous supprimez la solution de contournement du bogue Adreno.

Mais pas si vous supprimez la solution de contournement du bogue Adreno.

Que diriez-vous de supprimer la solution de contournement pour le moment, puis de rechercher une solution différente? L'implémentation actuelle conduit à de mauvais visuels, quelle que soit la plate-forme que vous utilisez.

@ Mugen87 Dans ce cas particulier, je pense que les géométries sont des miroirs les unes des autres, mais elles partagent la même carte normale.

Je suis d'accord avec toi. J'ai investi de nombreuses heures à essayer de trouver une solution de contournement compatible Adreno qui soit correcte dans chaque cas d'utilisation.

En inspectant le modèle de modèle de roue, chaque roue a sa propre coque UV. Il n'en partage pas un.
Et l'ordre des sommets est opposé.

Cependant, l'orientation du visage est la même, du moins dans Blender.

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

Je ne sais donc pas s'il s'agit d'un bogue dans r108, ​​ou si r108 fait maintenant les choses correctement. ¯_ (ツ) _ / ¯

@pushmatrix pouvez-vous comparer avec Unity ou Blender?

@mrdoob

Blender 2.8

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

Unité

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

Sketchfab

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

@pushmatrix

Unity est difficile à voir car la lumière est dans la même direction que la caméra, mais on dirait que Unity a tort aussi? 🤔

@mrdoob

Oui, cela dépend un peu de l'éclairage, cela finit par être une illusion et semble avoir surgi à certains endroits. Mais lorsque vous faites pivoter, il disparaît.

Le voici sous un autre jour, là où il semble correct
Screen Shot 2019-11-20 at 2 36 16 PM

@mrdoob Les faces avant ont un ordre d'enroulement dans le sens inverse des aiguilles d'une montre en three.js. En règle générale, les UV des 3 sommets de chaque face ont également un ordre d'enroulement dans le sens anti-horaire sur la carte UV.

Dans cet exemple, ma _conjecture_ est le modèle de gauche a des UV dans le sens anti-horaire et le modèle de droite a des UV dans le sens des aiguilles d'une montre. Le modèle de droite est rendu incorrectement dans three.js lorsque doubleSide est true .

AFAIK, la suppression de la solution de contournement Adreno résout le problème des GPU non Adreno.

@pushmatrix Votre exemple Unity semble avoir des lumières directionnelles provenant de deux directions. Cela rend difficile de discerner ce qui se passe. Une seule lumière peut être préférable.

@WestLangley J'utilise la même carte d'environnement que le visualiseur de modèle , mais il n'a probablement pas la même rotation. J'essaierai avec une seule lumière.

@WestLangley Lumière directionnelle unique tournant autour. J'ai l'impression de regarder une illusion d'optique

unity

On dirait que Unity fait apparaître et sortir les grooves en fonction de la façon dont la lumière la frappe, mais au moins, c'est cohérent pour les deux.

Threejs est également cohérent, mais l'un semble toujours ressorti:
wheels

J'ai l'impression qu'il y a quelque chose qui ne va pas dans l'unité Unity ...
Comme s'il avait besoin de quelque chose comme. material.normalMapScale.x = -1 .

@WestLangley

@mrdoob Les faces avant ont un ordre d'enroulement dans le sens inverse des aiguilles d'une montre en three.js. En règle générale, les UV des 3 sommets de chaque face ont également un ordre d'enroulement dans le sens anti-horaire sur la carte UV.

Dans cet exemple, ma _conjecture_ est le modèle de gauche a des UV dans le sens anti-horaire et le modèle de droite a des UV dans le sens des aiguilles d'une montre. Le modèle de droite est rendu incorrectement dans three.js lorsque doubleSide est true .

AFAIK, la suppression de la solution de contournement Adreno résout le problème des GPU non Adreno.

Merci, cela a du sens. Je pense que cela mérite encore une enquête plus approfondie. Si Sketchfab semble correct sur tous les appareils, nous devrons peut-être examiner leurs shaders.

J'ai jeté un coup d'œil au code de shader respectif aujourd'hui et il semble qu'ils n'utilisent pas le "mappage normal de l'espace tangent par pixel".

Selon cet article , Sketchfab s'attend à des définitions de tangentes dans les actifs ou ces données sont
générer en fonction des coordonnées uv. Cela correspond à ce que j'ai vu dans le code GLSL.

Si j'ajoute des tangentes au modèle via BufferGeometryUtils.computeTangents() et que je fixe Material.vertexTangents à true , le résultat semble correct:

image

BTW: Est-il acceptable de partager des extraits de code de Sketchfab dans cet article ^^? Après tout, ce n'est pas open-source.

Pour plus de cohérence, voici Sketchfab avec 1 lumière directionnelle se déplaçant d'avant en arrière:

sketchfab

Oui, une chose à garder à l'esprit est que Sketchfab effectue un traitement de son côté lorsque vous téléchargez un modèle, il est donc très probable qu'il génère des choses / change des choses. Ce que vous visualisez n'est pas un glTF mais un fichier glTF converti dans leur propre format.

@pushmatrix Pouvez-vous _please_ démontrer que # 17958 fonctionne pour votre modèle?

three.js calcule les tangentes dans le shader de fragment. Je pense que cela fonctionne correctement si un piratage pour accueillir certains GPU Adreno buggy est supprimé. Voir # 17958.

//

Sketchfab calcule les tangentes sur la CPU lorsque des tangentes sont requises et ne sont pas fournies par le modèle. ( @donmccurdy C'est ce qu'exige la spécification glTF.)

three.js peut le faire aussi, mais cela signifie ajouter des tangentes correctes à toutes les géométries intégrées. three.js devra également implémenter l'algorithme MIKKTSpace pour remplacer ComputeTangents() . Étant donné que three.js prend en charge les géométries indexées et non indexées, je pense que cela nécessitera un effort considérable.

Le corrige!
Screen Shot 2019-11-21 at 10 02 54 AM

D'accord, il semble donc que la solution ici consiste à inverser la solution de contournement Adreno (# 17958) et à recommander aux gens d'utiliser BufferGeometryUtils.computeTangents() lorsque le modèle n'a pas de tangentes et qu'ils visent à prendre en charge les GPU Adreno (# 15850) .

Ça m'a l'air bien?

Une autre solution est d'appeler automatiquement BufferGeometryUtils.computeTangents() dans le moteur lorsque ce n'est pas fourni et de supprimer tout le code qui calcule les tangentes dans le shader de fragment ... 🤔

BufferGeometryUtils.computeTangents() nécessite actuellement un index donc il ne peut pas être utilisé dans le noyau. Cependant, je pense qu'il serait préférable que three.js puisse générer des tangentes selon MIKKTSpace à un moment donné, puis supprimer perturbNormal2Arb() .

@WestLangley a écrit:

cela signifiera l'ajout de tangentes correctes à toutes les géométries intégrées.

Je change d'avis ... Les tangentes ne sont pas forcément nécessaires. Au lieu de cela, je restaurerais la méthode BufferGeometry.computeTangents() et «remplacerais» cette méthode pour toutes les géométries intégrées pour lesquelles nous pouvons définir des tangentes exactes analytiquement.

//

Une autre solution consiste à appeler BufferGeometryUtils.computeTangents () dans le moteur automatiquement lorsque n'est pas fourni et de supprimer tout le code qui calcule les tangentes dans le fragment shader ...

Cela me semble juste.

BufferGeometryUtils.computeTangents () nécessite actuellement un index donc il ne peut pas être utilisé dans le noyau.

Je pense que cela est facilement résolu. Et il devra être corrigé pour prendre en charge https://github.com/mrdoob/three.js/issues/17804#issuecomment -557135610.

il serait préférable que three.js puisse générer des tangentes selon MIKKTSpace à un moment donné, puis supprimer perturbNormal2Arb () ...

Je ne sais pas si MikkTSpace devrait nécessairement remplacer le calcul du fragment shader. Le shader n'a pratiquement aucun coût de performance et fonctionne bien pour la majorité des modèles. Le précalcul des tangentes a un coût initial par sommet à chaque fois, et aucun avantage sauf dans ces cas spécifiques. 😕 Malgré ce que dit la spécification glTF, j'ai du mal à justifier cela par défaut.

Ce serait bien si BufferGeometryUtils.computeTangents pouvait implémenter l'approche MikkTSpace - c'est le meilleur algorithme, si vous devez les précalculer. Mais il serait probablement plus facile de mettre MikkTSpace dans des outils comme glTF-Pipeline ou gltfpack, qui peuvent utiliser l'implémentation native existante, et faire le calcul à l'avance, hors ligne.

@donmccurdy

Mais, disons ... dans le cas d'utilisation <model-viewer> , je ne pense pas qu'il existe un moyen fiable de savoir si l'utilisateur a un GPU Adreno, mais nous voudrions regarder correctement (https: // github. com / GoogleWebComponents / model-viewer / issues / 740).

Est-ce que <model-viewer> (et d'autres projets qui veulent la prise en charge de x-gpu) devraient appeler BufferGeometryUtils.computeTangents lorsque les tangentes ne sont pas fournies, ou trois?

@pushmatrix

Haha, je viens de réaliser d'où viennent ces roues 😁

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

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

@mrdoob 🕵

Bon alors, revenons à la solution de contournement pour le moment.

Cette page vous a été utile?
0 / 5 - 0 notes