Three.js: El nuevo MeshStandardMaterial en r112 tiene artefactos de bandas en algunas GPU

Creado en 30 dic. 2019  ·  18Comentarios  ·  Fuente: mrdoob/three.js

A partir de r112, el MeshStandardMaterial predeterminado (en este caso específicamente como se usa cuando se cargan archivos glTF, pero probablemente también en otros escenarios) muestra artefactos de bandas en algunas GPU. Específicamente, he visto este problema en un Pixelbook y en todas las generaciones de teléfonos Pixel. El problema no ocurre en las GPU de escritorio de Nvidia que he probado, ni en Oculus Go u Oculus Quest.

También debe tenerse en cuenta que he observado que el nuevo sombreador del material sufrió un impacto de rendimiento notable en relación con r111 para mi aplicación particular en varios dispositivos móviles, incluidos los que no exhiben los artefactos de renderizado.

Los artefactos se ven así (renderizados con Three.js r112 en un Pixelbook)

Screenshot 2019-12-29 at 9 15 19 PM

El resultado esperado se ve así (renderizado con Three.js r111 en el mismo Pixelbook)

Screenshot 2019-12-29 at 9 24 31 PM

Enlace en vivo, actualmente usando r112: https://xrdinosaurs.com

Todos los dinosaurios en esa página exhiben el problema, pero los que tienen grandes áreas de colores planos o suaves (como el vientre del TRex) tienden a destacar más.

El material de la captura de pantalla (pegado en su totalidad a continuación) utiliza la extensión glTF "KHR_materials_pbrSpecularGlossiness", y tiene texturas difusas, normales y especulares / brillantes.

    {
      "doubleSided": true,
      "emissiveFactor": [
        0,
        0,
        0
      ],
      "extensions": {
        "KHR_materials_pbrSpecularGlossiness": {
          "diffuseFactor": [
            0.46512957319999998,
            0.46512957319999998,
            0.46512957319999998,
            1
          ],
          "diffuseTexture": {
            "index": 4,
            "texCoord": 0
          },
          "glossinessFactor": 0.27610518290000002,
          "specularFactor": [
            0.92244664629999995,
            0.92244664629999995,
            0.92244664629999995
          ],
          "specularGlossinessTexture": {
            "index": 6,
            "texCoord": 0
          }
        }
      },
      "name": "TRex",
      "normalTexture": {
        "index": 5,
        "scale": 1,
        "texCoord": 0
      }
    }
Bug Device Issue

Comentario más útil

@elalish después de ejecutar algunas pruebas en varios ejemplos, pude identificar la causa real de estos artefactos. Contrario a lo que dije en mi publicación anterior, la causa raíz del problema no está relacionada con el muestreo de coordenadas incorrectas, sino con la forma en que PMREMGenerator maneja devicePixelRatio .

En dispositivos con punto flotante nominal pixelRatio estamos obteniendo coordenadas mipmap "malas" en la textura generada. Por tanto, hay pequeñas lagunas y regiones superpuestas. También descubrí que mi máquina tiene devicePixelRatios dependiendo de si estoy viendo el ejemplo localmente (0.899 ..) o en línea (1) y es por eso que solo estaba experimentando estos artefactos localmente.

Configuré una prueba simple al deshabilitar setPixelRatio y parece resolver el problema, si ese es el caso de otros, entonces sería mejor refactorizar la forma en que PMREMGenerator está manejando.

@toji @ plut0nist ¿Le importaría comprobar los siguientes ejemplos en los dispositivos que presentaban estos artefactos?

Ejemplo DEV
Ejemplo de prueba

Todos 18 comentarios

Puedo confirmar el glich en mi Pixel (1). Sin embargo, los artefactos solo parecen ocurrir cuando se usa KHR_materials_pbrSpecularGlossiness .

18042 introdujo el suavizado geométrico. Sin embargo, GLTFLoader reemplaza el código del fragmento de sombreado lights_physical_fragment con lo siguiente:

https://github.com/mrdoob/three.js/blob/3ba0553208cfc9113152f5f39b4036a448cf3f25/examples/js/loaders/GLTFLoader.js#L683 -L688

@toji ¿Puedes modificar la copia GLTFLoader de tu aplicación reemplazando el código anterior con:

var lightPhysicalFragmentChunk = [
    'PhysicalMaterial material;',
    'material.diffuseColor = diffuseColor.rgb;',
    'vec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );',
    'float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );',

    'material.specularRoughness = max( 1.0 - glossinessFactor, 0.0525 );// 0.0525 corresponds to the base mip of a 256 cubemap.',
    'material.specularRoughness += geometryRoughness;',
    'material.specularRoughness = min( material.specularRoughness, 1.0 );',
    'material.specularColor = specularFactor.rgb;',
].join( '\n' );

@elalish Incluso si este parche no resuelve el problema, deberíamos agregar esto a GLTFLoader en cualquier caso, ¿verdad?

@ Mugen87 Sí, seguro. Veré si también puedo reproducir en mi Pixel 3.

@toji No todos los píxeles ...

¿Error del controlador? Sin embargo, no estoy seguro de qué línea lo está activando. La presencia / ausencia de anti-aliasing geométrico no haría ese tipo de artefacto de todos modos, estoy bastante seguro.

@toji También acabo de probar mi teléfono probador de mierda dedicado (un Alcatel que

Uf, el cielo negro en realidad significa que la generación PMREM falló por completo, y se debe a este extraño error y solución que encontramos: https://github.com/GoogleWebComponents/model-viewer/pull/920. Tenía la intención de poner esto en r112, pero se me escapó. Sin embargo, probablemente no esté relacionado con el error del OP.

Reproduje el error de OP en mi OnePlus 5T tanto en Chrome como en Firefox.

¡Gracias! Aplicó el parche a GLTFLoader y observó que el artefacto de bandas se redujo, pero no se eliminó.

Antes del parche:

Screenshot 2019-12-30 at 12 11 36 PM

Después de parche:

Screenshot 2019-12-30 at 12 10 35 PM

Básicamente, parece que arregló una de las bandas. :) (Capturas de pantalla tomadas en un Pixelbook, pero también observadas en un Pixel 4 XL. No tengo otros dispositivos de prueba conmigo en este momento).

Feliz de parchear cualquier otro cambio que desee probar, o puede consultar https://github.com/toji/xr-dinosaurs si desea probarlo localmente. (No requiere ningún componente de servidor).

En cuanto a perf: no es exactamente mantecoso, pero no está mal.

Gracias. 😁 He estado trabajando duro para mejorar el rendimiento. En este caso, durante la actualización a r112, noté la regresión perf y le pregunté a @mrdoob al respecto. Sugirió que podría ser el sombreador estándar nuevo y más preciso y sugirió intercambiar algunos materiales con MeshLambertMaterial para verificar. Dado que el modelo de entorno no tenía los materiales PBR configurados correctamente de todos modos, lo obligué a Lambert y lo dejé allí, lo que recuperó las regresiones de rendimiento y algo más (ya que ocupa una gran parte de la ventana gráfica). Dejó a los dinosaurios con la material estándar ya que son el activo "héroe".

Nota al margen: Scene.environment actualmente no funciona cuando GLTFLoader carga mallas usando materiales especulares / brillantes ya que el renderizador busca MeshStandardMaterial eg

https://github.com/mrdoob/three.js/blob/dd81aad5513d66e35e51f3a3b42555bc8aef5cbc/src/renderers/WebGLRenderer.js#L1633

Sin embargo, GLTFLoader crea un ShaderMaterial para cada material especular / brillante. Me di cuenta de esto hoy al probar con el modelo T-Rex ^^. Bueno, una razón más para completar finalmente # 14099.

No puedo reproducir los artefactos de bandas cuando no se utiliza ningún mapa de entorno. Todo se ve bien en un Pixel (1) con una configuración de iluminación simple como un ambiente y una luz puntual.

Parece que hay más problemas con los materiales físicos que utilizan un mapa del entorno. Vea cómo se ven los siguientes ejemplos en un Pixel 1, Android 10.

https://threejs.org/examples/webgl_materials_envmaps_exr

Screenshot_20200106-111923

https://threejs.org/examples/webgl_materials_physical_clearcoat

Screenshot_20200106-111856

https://threejs.org/examples/webgl_materials_envmaps_hdr

Screenshot_20200106-111809

No puedo reproducir estos artefactos en mi iMac.

Algo bastante extraño está sucediendo en mi máquina, puedo reproducir estos artefactos en todos los ejemplos que utilizan el nuevo PMREMGenerator . Pero solo cuando se ejecutan localmente; al verlos en línea (desde la página threejs.org), todos parecen correctos.

Nunca he experimentado tal problema y estoy completamente perdido en cuanto a qué lo causa.

Estoy ejecutando Windows 10 con una GeForce GTX 750 TI, por lo que no creo que este sea un problema específico del dispositivo.

Pero solo cuando se ejecutan localmente; al verlos en línea (desde la página threejs.org), todos parecen correctos.

Tenga en cuenta que la versión dev tiene cambios que aún no están presentes en prod . ¿Puede consultar la rama actual master y luego realizar una prueba local?

¿Puede consultar la rama maestra actual y luego realizar una prueba local?

Lo primero que intenté después de notar este comportamiento, los mismos resultados. Realmente curioso.

¿Puedes probar con ventanas de incógnito? A veces, las cosas pueden almacenarse en caché o las extensiones del navegador interfieren, lo que puede ser realmente confuso

Probado con incógnito, mismos resultados :(

Creo que sé por qué está ocurriendo esta banda.
Durante la generación de mip, mi versión local (incorrecta) está creando una banda negra que no existe en la versión en vivo.

local
online

Esto también se replica a niveles más bajos de mip.

Es probable que esto suceda debido a un muestreo de coordenadas incorrecto. He experimentado con la desactivación manual del filtrado anisotrópico, pero el problema persiste. Es difícil precisar exactamente lo que está sucediendo, especialmente porque no puedo entender por qué presenta dos comportamientos diferentes en la misma máquina.

@elalish después de ejecutar algunas pruebas en varios ejemplos, pude identificar la causa real de estos artefactos. Contrario a lo que dije en mi publicación anterior, la causa raíz del problema no está relacionada con el muestreo de coordenadas incorrectas, sino con la forma en que PMREMGenerator maneja devicePixelRatio .

En dispositivos con punto flotante nominal pixelRatio estamos obteniendo coordenadas mipmap "malas" en la textura generada. Por tanto, hay pequeñas lagunas y regiones superpuestas. También descubrí que mi máquina tiene devicePixelRatios dependiendo de si estoy viendo el ejemplo localmente (0.899 ..) o en línea (1) y es por eso que solo estaba experimentando estos artefactos localmente.

Configuré una prueba simple al deshabilitar setPixelRatio y parece resolver el problema, si ese es el caso de otros, entonces sería mejor refactorizar la forma en que PMREMGenerator está manejando.

@toji @ plut0nist ¿Le importaría comprobar los siguientes ejemplos en los dispositivos que presentaban estos artefactos?

Ejemplo DEV
Ejemplo de prueba

@sciecode ¡ Muchas gracias por descubrir la causa raíz! Veré si puedo encontrar una solución.

@sciecode : verificado en mis dispositivos. La prueba del ejemplo DEV muestra una línea negra muy obvia en el mapa del entorno, mientras que el ejemplo TEST no. ¡Depuración impresionante, gracias!

Tenía mucha curiosidad por saber por qué PMREMGenerator necesitaba dar cuenta de devicePixelRatio , así que me puse a investigar. Resulta que se debe a que renderer.setViewport() factoriza automáticamente el DPR en cualquier valor que le envíe, lo que parece claramente un comportamiento incorrecto para los objetivos de renderizado distintos del framebuffer predeterminado, que se asignan con valores de píxeles exactos que no lo hacen. tenga en cuenta la proporción de píxeles en absoluto. Sugeriría que el comportamiento "correcto" aquí es que internamente rendere.setViewport() debería estar usando getTargetPixelRatio() , que devuelve 1 cuando el destino de renderizado activo no es el predeterminado. Sin embargo, definitivamente puedo ver cómo eso podría introducir problemas de compatibilidad con versiones anteriores.

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