Three.js: GLTFLoader: El resultado del modelo de prueba de tangente normal es incorrecto

Creado en 3 jun. 2017  ·  30Comentarios  ·  Fuente: mrdoob/three.js

Descripción del problema

Traté de mostrar el modelo de prueba de tangente normal .
Sin embargo, el resultado mostrado parece ser diferente al de la muestra de Khronos.

Resultado del modelo de prueba Three.js + Normal-Tangent:
image

Cargador de muestras Khronos + resultado del modelo de prueba de tangente normal:
image

Creo que este modelo de muestra debería tener los mismos resultados de izquierda y derecha.

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

/ cc @emackey

Versión Three.js
  • [x] Desarrollo
  • [] r85
  • [] ...
Navegador
  • [x] Todos ellos
  • [ ] Cromo
  • [] Firefox
  • [ ] Explorador de Internet
SO
  • [x] Todos ellos
  • [] Windows
  • [ ] Mac OS
  • [] Linux
  • [] Android
  • [] iOS
Requisitos de hardware (tarjeta gráfica, dispositivo VR, ...)

ThinkPad X260 + Windows 10 + Intel HD Graphics 520

Bug Loaders

Comentario más útil

Me gustaría mencionar una oración de la especificación glTF en mapas normales en particular:

Los vectores normales usan las convenciones de OpenGL donde + X es correcto y + Y es arriba. + Z apunta hacia el espectador.

Esta frase es la que permite que los modelos se envíen sin vectores tangentes, ahorrando espacio.

Probémoslo. Aquí hice un pésimo mapa de altura (mapa de relieve) a partir de una mancha en un programa de pintura:

TestHeightMap

Definamos este campo de altura como una protuberancia hacia afuera, donde los píxeles blancos están más cerca del espectador y los píxeles negros están más lejos.

Usando un convertidor en línea (de calidad cuestionable, pero examinaremos el resultado en un momento), he convertido esto de un mapa de altura a un mapa normal. Tenga en cuenta que aquí no hay un modelo 3D, ni coordenadas UV ni cálculos de mikktspace ni ninguna geometría. Solo un mapa de altura convertido en un mapa normal. Tuve que configurar manualmente el convertidor en línea según las instrucciones de glTF, de modo que X es correcto, Y está arriba y Z se enfrenta al espectador. Este es el resultado:

TestNormalMap

Traigamos eso de vuelta a un programa de pintura y saquemos los canales de color para ver dónde apuntan estos vectores. A continuación, cada canal de color se ha separado en una imagen en escala de grises propia. Recuerde que estos se interpretarán de manera que negro significa -1.0 , gris medio significa 0.0 y blanco significa +1.0 .

TestNormalMap-Decomposed

Así que creo que el convertidor en línea hizo lo que pidió glTF, al menos después de configurarlo correctamente. En la imagen Roja (X), podemos ver que la pendiente de la derecha tiene píxeles blancos (+1.0), apuntando el vector X al borde derecho de la imagen. En el lado izquierdo de la imagen roja, los píxeles negros (-1.0) apuntan al vector X al lado izquierdo de la imagen. En la imagen verde (Y), los píxeles blancos a lo largo de la pendiente superior del relieve señalan el vector Y en la parte superior de la imagen. Los valores Z son los menos intuitivos, pero recuerde que la punta de la protuberancia y la placa posterior en sí apuntan al espectador, y las pendientes en todos los lados apuntan hacia afuera, por lo que todas son uniformemente más oscuras.

¿Qué pasa si cargamos esto en Blender Eevee, que (al igual que glTF) acepta mapas normales de estilo OpenGL? ¿Qué sucede si el mapa UV se gira, o incluso se escala para invertirlo?

NormalSpinTest

Resulta que esto funciona bien. De hecho, el objetivo de definir el espacio tangente de esta manera no es permitir que el software se vuelva loco con los vectores, es permitir a los artistas de texturas algo de cordura asegurándose de que sus mapas normales estén del lado correcto hacia arriba independientemente de la geometría.

Pero no todo el software utiliza la convención OpenGL. Algunos usan una convención diferente (a veces llamada convención de DirectX), donde los vectores Y apuntan a la parte inferior de la imagen en lugar de a la parte superior. Aquí está el canal Y descompuesto de mi imagen en esta forma. Los píxeles más claros son los que miran hacia la parte inferior de la imagen.

TestNormalMap_DirectX-Green

Si cargo uno de estos mapas normales de estilo DirectX en Blender Eevee, ¿puedo esperar que funcione?

NormalSpinTest_DirectX_v3

No. Blender estaba esperando + Y arriba. La matemática es incorrecta y la línea del horizonte reflejada gira alrededor.
Lo mismo sucede si carga un mapa normal de estilo OpenGL en un motor que esperaba + Y abajo.

Esto es lo que intenta probar el modelo NormalTangentTest. Cada fila hace girar las coordenadas UV en una orientación diferente, tratando de asegurarse de que los reflejos permanezcan hacia arriba en estas diferentes orientaciones.

Todos 30 comentarios

Gracias por escribir esto @ cx20.

Solo para más contexto, aquí hay información y problemas relacionados:

  • Informé de un problema similar en el visor ThreeJS glTF de @donmccurdy, donmccurdy / three-gltf-viewer # 10. Pero ahora creo que esto es un error en el cargador glTF de ThreeJS, no en el visor. Por lo tanto, este nuevo número está mejor ubicado que el anterior.

  • En el número anterior anterior, el modelo solía mirar hacia el cielo, pero luego lo giré para mirar hacia el horizonte. Esto hace que sea más fácil ver cuando los reflejos no son correctos, porque el horizonte gira locamente, como se muestra arriba.

  • El propio uso del modelo de un mapa normal se confirmó como correcto mediante la discusión en KhronosGroup / glTF # 952.

  • El manejo de ThreeJS de mapas normales fue cuestionado en # 11315.

  • BabylonJS tuvo recientemente un problema similar, reportado aquí y solucionado aquí . Aquí hay una demostración en vivo del cargador glTF 2.0 de BabylonJS con la corrección aplicada .

Buen informe, gracias!

El modelo parece renderizarse correctamente con la adición de esta línea:

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

Pero no estoy seguro de entender bien el problema. Comprender el n. ° 11315 podría ayudar aquí.

@donmccurdy Gracias por tu consejo.
Entendí que mejoraba ajustando normalScale.
Sin embargo, si el modelo glTF es correcto, creo que es mejor que glTF Loader lo maneje.

@ cx20 estuvo de acuerdo, esta solución ahora se fusiona en THREE.GLTF2Loader.

He confirmado que se está reparando.

Resultado del modelo de prueba Three.js + Normal-Tangent:
image

Esto ha retrocedido, en algún momento entre r101 y r104:
Screenshot from 2019-06-11 16-38-27

Consulte https://github.com/mrdoob/three.js/pull/15749 : la regresión es intencional y se puede evitar al incluir tangentes en el modelo.

Idealmente, tendríamos una implementación JS para generar tangentes mikktspace, para resolver esto completamente, pero eso es bastante complejo.

No conocía el número 15749 hasta ahora. Esto me tomó por sorpresa, pensé que habíamos hecho un trabajo lo suficientemente bueno al definir las tangentes en glTF como para que pudieran al menos aproximarse en tiempo de ejecución.

Tenga en cuenta que el exportador de Blender no exportará ninguna tangente glTF de forma predeterminada, ya que ayuda a mantener el tamaño del archivo bajo, y las principales implementaciones de glTF estaban pasando esta prueba sin tangentes. Sospecho que este cambio puede haber roto el mapeo normal para la mayoría de los modelos glTF en ThreeJS.

Necesitaré algo de tiempo para leer todos los temas vinculados a fin de comprender mejor lo que sucedió y por qué. Pero creo que la comunidad glTF debería considerar esta alta prioridad para obtener modelos sin tangentes que se rendericen correctamente nuevamente, ya que creo que la mayoría de los modelos están en esa categoría por defecto.

Reapertura 😅

Sospecho que este cambio puede haber roto el mapeo normal para la mayoría de los modelos glTF en ThreeJS.

No creo que sea nada tan severo: siempre hemos generado tangentes en tiempo real en el sombreador con derivadas, y todavía lo hacemos. Anteriormente incluimos un truco ( normalScale.y *= -1 ) que corrigió este modelo de prueba específico, pero también rompió algunos otros ejemplos. No tengo una explicación de cuándo eso ayudó o no, así que eliminamos el truco una vez que admitimos las tangentes almacenadas, en cuyo caso ciertamente habría estado mal. Ahora los modelos que se basaron en el truco (y no incluyen tangentes) están rotos, y los modelos que fueron rotos por el hackeo (y no incluyen tangentes) están arreglados.

Pero creo que la comunidad glTF debería considerar esta alta prioridad para obtener modelos sin tangentes que se rendericen correctamente nuevamente, ya que creo que la mayoría de los modelos están en esa categoría por defecto.

Véase más arriba. En general, creo que renderizamos modelos sin tangentes de forma adecuada. Sin embargo, no generamos tangentes mikktspace como lo requiere la especificación glTF. Que yo sepa, no existe ninguna implementación JS de eso, y nuestra implementación de sombreadores basada en derivados es simplemente una aproximación "en su mayoría suficientemente buena". Este modelo de muestra es un caso intencionalmente extremo que demuestra los límites de esa aproximación.

Estaríamos encantados de tener una implementación de generación de tangente JS mikktspace; eso sería una buena adición a THREE.BufferGeometryUtils. Pero el código mikktspace oficial (nativo) es bastante largo, y todavía no he investigado lo suficiente para ver cuánto de eso se requiere para generar tangentes.

Anteriormente incluimos un truco ( normalScale.y *= -1 ) que solucionó este modelo de prueba específico, pero también rompió algunos otros ejemplos

¿Rompió otros modelos glTF específicamente, o solo ejemplos en general?

Hay dos tipos diferentes de mapas normales de espacio tangente en la naturaleza. Substance Painter los llama "DirectX normales" y "OpenGL normales", que no es el mejor nombre para ellos. La diferencia es específicamente que el canal y está invertido, lo que significa que todos los valores del canal verde en la textura están invertidos. Multiplicar y *= -1 es la forma correcta de convertir uno a otro. Los llamados "DirectX Normales" utilizan un sistema de coordenadas para zurdos, y glTF define un sistema de coordenadas para diestros para normal / tangente / bitangente.

Lo que sospecho que está sucediendo es que cuando ThreeJS calcula automáticamente las tangentes, espera que el mapa normal se haya creado con el estilo Y invertido (DirectX) y obtiene ese canal al revés para glTF, por lo que es necesario cambiarlo. Sin embargo, cuando se suministran las tangentes, no se necesita tal cambio.

La cuestión del mikktspace creo que está separada de esto. Es desafortunado que la especificación requiera mikktspace y la mayoría de las implementaciones se aproximan a eso con los derivados del espacio de pantalla. No sé qué tan similares son los dos, pero los mapas normales generados en mikktspace parecen funcionar razonablemente bien cuando se muestran con la aproximación, siempre y cuando la izquierda / derecha del mapa se haga correctamente.

(También hay una discusión sobre esto del año pasado en KhronosGroup / glTF-Sample-Models # 174)

Me gustaría mencionar una oración de la especificación glTF en mapas normales en particular:

Los vectores normales usan las convenciones de OpenGL donde + X es correcto y + Y es arriba. + Z apunta hacia el espectador.

Esta frase es la que permite que los modelos se envíen sin vectores tangentes, ahorrando espacio.

Probémoslo. Aquí hice un pésimo mapa de altura (mapa de relieve) a partir de una mancha en un programa de pintura:

TestHeightMap

Definamos este campo de altura como una protuberancia hacia afuera, donde los píxeles blancos están más cerca del espectador y los píxeles negros están más lejos.

Usando un convertidor en línea (de calidad cuestionable, pero examinaremos el resultado en un momento), he convertido esto de un mapa de altura a un mapa normal. Tenga en cuenta que aquí no hay un modelo 3D, ni coordenadas UV ni cálculos de mikktspace ni ninguna geometría. Solo un mapa de altura convertido en un mapa normal. Tuve que configurar manualmente el convertidor en línea según las instrucciones de glTF, de modo que X es correcto, Y está arriba y Z se enfrenta al espectador. Este es el resultado:

TestNormalMap

Traigamos eso de vuelta a un programa de pintura y saquemos los canales de color para ver dónde apuntan estos vectores. A continuación, cada canal de color se ha separado en una imagen en escala de grises propia. Recuerde que estos se interpretarán de manera que negro significa -1.0 , gris medio significa 0.0 y blanco significa +1.0 .

TestNormalMap-Decomposed

Así que creo que el convertidor en línea hizo lo que pidió glTF, al menos después de configurarlo correctamente. En la imagen Roja (X), podemos ver que la pendiente de la derecha tiene píxeles blancos (+1.0), apuntando el vector X al borde derecho de la imagen. En el lado izquierdo de la imagen roja, los píxeles negros (-1.0) apuntan al vector X al lado izquierdo de la imagen. En la imagen verde (Y), los píxeles blancos a lo largo de la pendiente superior del relieve señalan el vector Y en la parte superior de la imagen. Los valores Z son los menos intuitivos, pero recuerde que la punta de la protuberancia y la placa posterior en sí apuntan al espectador, y las pendientes en todos los lados apuntan hacia afuera, por lo que todas son uniformemente más oscuras.

¿Qué pasa si cargamos esto en Blender Eevee, que (al igual que glTF) acepta mapas normales de estilo OpenGL? ¿Qué sucede si el mapa UV se gira, o incluso se escala para invertirlo?

NormalSpinTest

Resulta que esto funciona bien. De hecho, el objetivo de definir el espacio tangente de esta manera no es permitir que el software se vuelva loco con los vectores, es permitir a los artistas de texturas algo de cordura asegurándose de que sus mapas normales estén del lado correcto hacia arriba independientemente de la geometría.

Pero no todo el software utiliza la convención OpenGL. Algunos usan una convención diferente (a veces llamada convención de DirectX), donde los vectores Y apuntan a la parte inferior de la imagen en lugar de a la parte superior. Aquí está el canal Y descompuesto de mi imagen en esta forma. Los píxeles más claros son los que miran hacia la parte inferior de la imagen.

TestNormalMap_DirectX-Green

Si cargo uno de estos mapas normales de estilo DirectX en Blender Eevee, ¿puedo esperar que funcione?

NormalSpinTest_DirectX_v3

No. Blender estaba esperando + Y arriba. La matemática es incorrecta y la línea del horizonte reflejada gira alrededor.
Lo mismo sucede si carga un mapa normal de estilo OpenGL en un motor que esperaba + Y abajo.

Esto es lo que intenta probar el modelo NormalTangentTest. Cada fila hace girar las coordenadas UV en una orientación diferente, tratando de asegurarse de que los reflejos permanezcan hacia arriba en estas diferentes orientaciones.

Todavía es necesario que haya una fórmula concreta en la especificación sobre cómo calcular una tangente para una primitiva solitaria, dada una primitiva y sus coordenadas UV, y qué signo W usar para la bitangente. Las "normales de OpenGL" y las "normales de DX" no son lo suficientemente precisas para derivar la fórmula. Pueden referirse a convenciones, pero no tengo ni idea de qué hacer con eso como implementador.

Lo que hago actualmente es emitir TangentW invertido desde MikkTSpace para que coincida con esta muestra en particular, pero eso fue lo que sucedió para funcionar.

¿Rompió otros modelos glTF específicamente, o solo ejemplos en general?

Los errores informados estaban relacionados con los modelos glTF, específicamente. Dicho esto, dudo que haya suficiente confianza en la exportación de material a través de FBX o COLLADA para decir que esas convenciones de mapas normales se comprendieron y probaron a fondo.

La diferencia es específicamente que el canal y está invertido, lo que significa que todos los valores del canal verde en la textura están invertidos. Multiplicar y * = -1 es la forma correcta de convertir uno en otro.

Gracias, esta es una justificación mucho mejor de nuestro "truco" que la que teníamos cuando lo implementamos. 😇

Es desafortunado que la especificación requiera mikktspace y la mayoría de las implementaciones se aproximan a eso con los derivados del espacio de pantalla.

La especificación es correcta en que MikkTSpace es la forma más sólida de generar tangentes, creo que no es universalmente la opción correcta para hacer esto automáticamente en tiempo de ejecución. Si las alternativas más baratas parecen correctas para un modelo en particular, no hay razón para hacer algo más caro que no se vea mejor. El lenguaje de especificaciones podría aflojarse para permitir aproximaciones, pero no estoy muy convencido de esto.

Todavía es necesario que haya una fórmula concreta en la especificación sobre cómo calcular una tangente para una primitiva solitaria, dada una primitiva y sus coordenadas UV, y qué signo W usar para la bitangente.

No estoy seguro de que el algoritmo MikkTSpace sea tan fácil de representar como una fórmula discreta ... ¿estás pidiendo una alternativa al código canónico MikkTSpace? ¿O alguna información adicional más allá de las instrucciones para usar MikkTSpace? @Themaister


Para el problema original, parece que deberíamos restaurar el multiplicador normal.y *= -1 alguna parte. Hay tres lugares posibles para hacer esto:

  • (a) en GLTFLoader, para mallas que no tienen tangentes
  • (b) en GLTFLoader, para todas las mallas
  • (c) en WebGLRenderer, para todas las mallas

Si threejs realmente está usando la convención de DirectX y, por ejemplo, Blender no lo está, podría ver un caso para (c). Sin embargo, en aras de una solución rápida y segura, me inclino por (a).

Lo que sospecho que está sucediendo es que cuando ThreeJS calcula automáticamente las tangentes, espera que el mapa normal se haya creado con el estilo Y invertido (DirectX).

No, three.js no asume que ...

three.js asume que + Y está "arriba" para el espacio tangente, y V creciente es "arriba" para el espacio uv.

Es decir, three.js asume que uv (0, 0) está en la esquina inferior izquierda de la textura, mientras que la especificación glTF asume la parte superior izquierda. Es por eso que GLTFLoader establece texture.flipY en false . (three.js establece texture.flipY en true de forma predeterminada).

Cuando las tangentes no están presentes, three.js usa derivadas del espacio de pantalla para estimar las tangentes. Lo hace usando la regla de la cadena. Una suposición en ese cálculo es que el espacio tangente y el espacio ultravioleta tienen la misma orientación.

Para los modelos glTF con la autoría adecuada, esa suposición no es correcta. Sin embargo, debería poder compensar configurando normalScale.y = - 1 para cualquier modelo que _ se adhiera correctamente a la especificación glTF_.

También me parece que podríamos arreglar esto automáticamente honrando la bandera flipY en el sombreador.

Si la configuración normalScale.y no funciona, entonces está sucediendo algo más.

Gracias por esta aclaración. Creo que tenemos un camino a seguir aquí.

También me parece que podríamos arreglar esto automáticamente respetando la bandera flipY en el sombreador.

Sí, con la excepción de los casos en los que glTF proporciona sus propios vectores tangentes, ¿verdad? Esperaría que solo las tangentes calculadas automáticamente necesiten la prueba flipY y la negación correspondiente de y .

Si ese no es el caso ... eso significaría que mi modelo NormalTangentMirrorTest tiene tangentes incorrectas codificadas, lo que significa que el exportador de Blender glTF en sí mismo está poniendo las tangentes incorrectas en los modelos glTF.

Editar: creo que he confirmado la exactitud de los vectores tangentes exportados, y no necesitan ningún cambio de Y. Puedo publicar más detalles sobre eso si es necesario.

Pero parece que la acción correcta es voltear normalScale.y solo cuando las tangentes generadas automáticamente (no las tangentes suministradas) se están utilizando con la bandera flipY . Pensamientos

En mi publicación anterior, expliqué cómo compensar manualmente las normales invertidas cuando las tangentes de atributos no están presentes. No debe haber nada que compensar cuando hay tangentes porque no se utilizan derivadas del espacio de pantalla.

También sugerí que podríamos solucionar esto automáticamente respetando la bandera flipY en el sombreador. Sin embargo, no dije que arreglaríamos esto automáticamente cambiando normalScale.y . No creo que debamos alterar la configuración del usuario.

En cualquier caso, antes de seguir ese camino, creo que es imperativo que verifiquemos esta hipótesis:

[Usted] debería poder compensar estableciendo normalScale.y = - 1 para cualquier modelo que se adhiera correctamente a la especificación glTF.

Debemos tener una explicación para cada modelo que no se esté renderizando correctamente.

No creo que debamos alterar la configuración del usuario.

Sí, disculpas, no tenía la intención de dictar ese tipo de detalles de implementación. Solo estoy tratando de asegurarme de que no haya un malentendido de lo que _honrar la bandera flipY _ significa matemáticamente, con el propósito de generar la tangente del espacio de la pantalla.

Debemos tener una explicación para cada modelo que no se esté renderizando correctamente.

Eso parece que podría ser un conjunto grande. Si de hecho existen modelos que están haciendo algo radicalmente diferente a los modelos de prueba oficiales y, sin embargo, podrían considerarse usos válidos de mapas normales en glTF, sería importante descubrirlo. Los modelos de prueba están destinados a cubrir usos válidos de mapas normales en geometría estática (no transformada). No debería haber una forma, especialmente cuando se depende de vectores tangentes generados por el espectador, de construir el modelo en algún otro sistema de coordenadas y, sin embargo, afirmar que es glTF válido.

¿Supongo que esto está estrechamente relacionado con este problema? https://github.com/KhronosGroup/glTF-Sample-Models/issues/174

@WestLangley Esto es lo que he encontrado hasta ahora. De forma predeterminada, khronos-NormalTangentTest (no se incluyen tangentes) se ve mal:
NormalTangentTest
Si configuro normalScale.y = -1, todavía está mal:
NormalTangentTestNegY
Si en cambio configuro normalScale.x = -1, parece correcto:
NormalTangentTestNegX
Con la posible excepción de que el renderizado parece un poco pixelado, especialmente en el reflector dorado. ¿Se espera esto con la aproximación del espacio de la pantalla o un indicador de otro error?

Si alguien tiene otros buenos modelos de prueba sin tangentes, envíelos a mi manera. Me gustaría asegurarme de tener una muestra representativa y determinar si hay alguna que no se ajuste a la especificación glTF.

@elalish Ese banco de pruebas no tiene sentido para mí, nunca lo ha tenido y probablemente nunca lo tendrá. Entonces ... no te ayudaré a tratar de explicarlo.

Ese ejemplo es demasiado confuso en mi humilde opinión. Necesitamos un caso de prueba coherente que proporcione suficientes imágenes para comprender lo que está sucediendo.

Por cierto, solíamos tener un VertexTangentHelper (# 3511), que podría revivirse para admitir la geometría del búfer.

@WestLangley Ojalá supiera cómo hacer que NormalTangentTest sea más claro. No hace nada extravagante, simplemente rota la orientación (en el espacio ultravioleta) de cada muestra. Las tres columnas son solo para probar diferentes materiales, la columna de oro podría ser suficiente por sí sola. Aparte de eso, no creo que el modelo de prueba pueda ser mucho más simple y aún probar estas diferentes orientaciones UV.

A pesar de las rotaciones UV, la imagen del mapa normal es bastante consistente acerca de hacia dónde apuntan los vectores, cuando el mapa normal se ve como una imagen 2D. En una vista 2D de la imagen, los lados derechos de todos los hemisferios tienen valores altos de canal rojo y los bordes superiores de todos los hemisferios tienen valores altos de canal verde, independientemente de las coordenadas UV. Esto sigue la especificación glTF de que el rojo (+ X) apunta al lado derecho de la textura en el espacio UV, y el verde (+ Y) apunta al borde superior de la textura en el espacio UV. No se necesitan vectores tangentes suministrados para que esto funcione: una simple estimación del espacio de pantalla de, en general, qué dirección es el eje + U para un triángulo dado es suficiente para calcular los vectores tangente y bitangente, como hacen BabylonJS y CesiumJS y, por supuesto, ThreeJS también lo hace, pero con algunos cambios de eje de escala normal aún inexplicables.

Existe un punto conocido de confusión con el uso de glTF de la bandera flipY , que invierte las coordenadas V en el espacio UV, que creo que ya es muy consciente. Durante mucho tiempo sospeché que esto juega un papel en el cambio de escala normal inexplicable.

También hay un pequeño error de horneado en la imagen (mi culpa, yo era un nuevo usuario de Substance Painter en ese momento, hace años). Una ligera costura diagonal es visible particularmente en la parte plana de los hemisferios dorados. Pero esto no debería restar valor al efecto general. La parte redonda principal del horneado salió bien y demuestra bien que el efecto de "arriba" y "derecha" son constantes en toda la imagen 2D de la textura normal, independientemente de que las coordenadas 3D o UV estén giradas en diferentes direcciones y tangentes. siendo omitido.

Este es un efecto importante para los artistas que crean texturas de mapas normales repetidas antes de crear la geometría 3D, ya que el artista no necesita acceso a coordenadas UV o tangentes antes de crear la imagen de textura.

@WestLangley Me gusta esta prueba solo porque es la mejor que he visto, también conocida como la única. Estaré feliz de usar cualquier otro modelo de prueba que me señalen.

Además, la trama se complica: la prueba original es un material de doble cara. Debido al # 17804, decidí probarlo como de una sola cara. Todavía está mal por defecto, pero ahora obtengo la respuesta correcta cuando configuro normalScale.y = -1:
NormalTangentTestFrontNegY
Al menos, espero que podamos estar de acuerdo en que el cambio de doble cara no debería afectar el renderizado de la parte frontal.

@emackey Otro modelo de prueba que podría ser útil, creo, sería un cubo brillante con normales soldadas y un mapa normal correspondiente diseñado para hacerlo en forma de cubo en lugar de redondeado. Probablemente dos versiones, una con y otra sin tangentes suministradas. Desafortunadamente, no tengo la habilidad de autor para hacerlo yo mismo. Todo lo que puedo ofrecer es muchas gracias si lo hace por nosotros: ore:

@emackey Gracias por todo su trabajo en esto. Te lo agradezco mucho. Entiendo todos los diversos problemas que pueden surgir con los artistas y los problemas que deben superarse.

Quizás estaría dispuesto a trabajar con @elalish y proporcionar cualquier modelo glb que solicite. Espero que eso nos ayude a entender.

@elalish Ya hemos abordado estos problemas anteriormente. En un momento tuve la impresión de que todo estaba funcionando. Si hay un caso de prueba simple, puedo usar bisect para identificar dónde se rompieron las cosas.

cubo brillante con normales soldadas y un mapa normal correspondiente diseñado para hacerlo en forma de cubo en lugar de redondeado.

Hecho: normal_map_flat.zip . Tomé el ejemplo de tangentes, escrito por el equipo de Draco, y creé una versión adicional sin el atributo de tangente.

En un momento tuve la impresión de que todo estaba funcionando.

Creo que llegamos a un estado en el que todo funciona _si_ el modelo incluye tangentes. De lo contrario, las cosas suelen estar bien, pero existen algunos casos extremos, especialmente alrededor de las costuras UV. En ese caso, recomendamos a los usuarios que agreguen tangentes. O, como @emackey mencionó en https://github.com/mrdoob/three.js/issues/11438#issuecomment -507027586, tal vez deberíamos restaurar el normalScale.y *= -1 flip en GLTFLoader, solo en los casos en que la malla omite las tangentes de vértices.

@donmccurdy Gracias. Hoy no tengo tiempo para este problema, pero todavía estoy luchando con los lados planos del cubo. Si edita su modelo para que tenga una superficie brillante ( metallicFactor: 1, roughnessFactor: 0.1 ), verá que los reflejos en los lados del cubo se mueven un poco.

Veo el mismo efecto en mi propio modelo de prueba. Peor aún, es un efecto diferente si hago el horneado normal en Substance Painter en lugar de hornearlo en Blender Cycles. Cada programa lo hornea para que sea correcto para su propia ventana gráfica, pero no es perfectamente plano cuando se carga en el otro programa, incluso sin glTF en la mezcla. Está muy cerca, pero en una superficie tan plana las pequeñas diferencias lo convierten en un espejo de la casa de la diversión, y no en el buen sentido.

Creo que veo una diferencia sutil en la forma en que los vectores normales (o espacio TBN) se interpolan entre los vértices a lo largo de la cara de un triángulo, en SP vs Blender vs los diversos motores WebGL. Usé Gimp para ejecutar una "diferencia" de un horneado SP frente a un horneado Blender, y salió negro (valores RGB idénticos) en cada vértice, pero el espacio entre los vértices muestra diferencias arremolinadas de intensidad muy tenue.

Esperaría efectos sutiles de diversión, pero no lo que obtengo actualmente (la versión sin tangentes):
image
La versión con tangentes no es realmente mejor, lo que me lleva a preguntarme si esto es realmente un glTF válido:
image
@emackey ¿Se siente calificado para decirnos si uno o ambos de estos modelos provistos por @donmccurdy son de hecho glTF válidos? Si es así, creo que tenemos un problema importante.

Este cubo en particular es un ejemplo tan extremo que realmente no sé qué decir, o si los reflejos físicamente realistas son una expectativa justa. Los mapas normales están destinados a agregar detalles como golpes y abolladuras, no para deformar toda la superficie de la malla. Simplemente resultó ser una forma muy efectiva de probar que las tangentes se leen o generan correctamente. Sé que el cambio normalScale.y *= -1 nunca fue suficiente para solucionarlo; este fue uno de los ejemplos que nos impulsó a admitir tangentes almacenadas en primer lugar.

Los reflejos también se ven salvajes en BabylonJS:
Screen Shot 2019-10-23 at 4 00 02 PM

Si el único problema identificado es con NormalTangentTest, y ningún usuario ha presentado modelos que se renderizan incorrectamente en la práctica, ¿quizás deberíamos dejar de hacer un cambio aquí?

Todavía estoy de acuerdo con restaurar el multiplicador normalScale.y *= -1 , pero la falta de ejemplos del problema parece una indicación de que el problema es menor, más que una indicación de que necesitamos crear ejemplos tan extremos.

Si el único problema identificado es con NormalTangentTest, y ningún usuario ha presentado modelos que se renderizan incorrectamente en la práctica, ¿quizás deberíamos dejar de hacer un cambio aquí?

Corrección: https://github.com/mrdoob/three.js/issues/17804 sugiere que algo puede haber retrocedido con materiales de doble cara. Parece que vale la pena seguir investigando, aunque por simplicidad y cordura quizás deberíamos dejar el Cubo Maldito en paz por ahora. 😇

¿Fue útil esta página
0 / 5 - 0 calificaciones