Three.js: O novo MeshStandardMaterial no r112 tem artefatos de bandas em algumas GPUs

Criado em 30 dez. 2019  ·  18Comentários  ·  Fonte: mrdoob/three.js

A partir do r112, o MeshStandardMaterial padrão (neste caso especificamente como é usado ao carregar arquivos glTF, mas provavelmente também em outros cenários) está exibindo artefatos de faixas em algumas GPUs. Especificamente, vi esse problema em um Pixelbook e em todas as gerações de smartphones Pixel. O problema não ocorre nas GPUs de desktop da Nvidia que experimentei, nem em um Oculus Go ou Oculus Quest.

Também deve ser observado que observei que o novo shader do material sofreu um impacto perceptível no desempenho em relação ao r111 para meu aplicativo específico em vários dispositivos móveis, incluindo aqueles que não exibem os artefatos de renderização.

Os artefatos têm a seguinte aparência (renderizado com Three.js r112 em um Pixelbook)

Screenshot 2019-12-29 at 9 15 19 PM

A saída esperada é parecida com esta (renderizado com Three.js r111 no mesmo Pixelbook)

Screenshot 2019-12-29 at 9 24 31 PM

Link ao vivo, atualmente usando r112: https://xrdinosaurs.com

Todos os dinossauros nessa página exibem o problema, mas aqueles com grandes áreas de cores planas ou suaves (como a barriga do TRex) tendem a se destacar mais.

O material na captura de tela (colado por completo abaixo) usa a extensão glTF "KHR_materials_pbrSpecularGlossiness" e tem texturas difusas, normais e especulares / brilhantes.

    {
      "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

Comentários muito úteis

@elalish depois de executar alguns testes em vários exemplos, consegui localizar a causa real desses artefatos. Ao contrário do que disse no meu post anterior, a causa raiz do problema não está relacionada com a amostragem de coordenadas incorretas, mas com a maneira PMREMGenerator está lidando com devicePixelRatio .

Em dispositivos com ponto flutuante nominal pixelRatio , estamos obtendo coordenadas mipmap "ruins" na textura gerada. Portanto, há pequenas lacunas e regiões sobrepostas. Eu também descobri que minha máquina tem devicePixelRatios dependendo se estou vendo o exemplo localmente (0,899 ..) ou online (1) e é por isso que eu só estava experimentando esses artefatos localmente.

Eu configurei um teste simples desabilitando setPixelRatio e parece resolver o problema, se esse for o caso de outros, então seria melhor refatorar a maneira PMREMGenerator está lidando com isso.

@toji @ plut0nist se importou em verificar os exemplos a seguir nos dispositivos que apresentaram esses artefatos?

DEV Exemplo
Exemplo de TESTE

Todos 18 comentários

Posso confirmar o glich no meu Pixel (1). No entanto, os artefatos só parecem ocorrer quando KHR_materials_pbrSpecularGlossiness é usado.

18042 introduziu o anti-aliasing geométrico. No entanto, GLTFLoader substitui o código do fragmento de sombreador lights_physical_fragment pelo seguinte:

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

@toji Você pode modificar a cópia GLTFLoader de seu aplicativo substituindo o código acima por:

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 Mesmo que este patch não resolva o problema, devemos adicioná-lo a GLTFLoader em qualquer caso, certo?

@ Mugen87 Sim, com certeza. Vou ver se consigo reproduzir no meu Pixel 3 também.

@toji Eu não reproduzo no meu Pixel 3 com Android 10, então pelo menos não são todos Pixels ...

Bug do driver? Não tenho certeza de qual linha está acionando isso. A presença / ausência de anti-aliasing geométrico não faria esse tipo de artefato de qualquer maneira, tenho certeza.

@toji Eu também tentei meu telefone dedicado de teste de custa cerca de US $ 30 da Target). Não entendo os artefatos de bandas, embora tenha notado que o céu está preto. Quanto ao perf: não é exatamente amanteigado, mas não é ruim. Honestamente, essa visualização 3D responde melhor do que a IU do teclado 2D neste telefone. Vai saber.

Ugh, o céu preto na verdade significa que a geração do PMREM falhou totalmente, e é devido a este bug estranho e solução alternativa que encontramos: https://github.com/GoogleWebComponents/model-viewer/pull/920. Eu pretendia colocar isso no r112, mas passou por mim. Provavelmente não relacionado ao bug do OP.

Reproduzi o erro de OP no meu OnePlus 5T no Chrome e no Firefox.

Obrigado! Aplicou o patch a GLTFLoader e observou que o artefato de bandas foi reduzido, mas não eliminado.

Antes do patch:

Screenshot 2019-12-30 at 12 11 36 PM

Após o patch:

Screenshot 2019-12-30 at 12 10 35 PM

Basicamente, parece que consertou uma das bandas. :) (Capturas de tela tiradas em um Pixelbook, mas também observadas em um Pixel 4 XL. Não tenho outros dispositivos de teste comigo no momento.)

Fico feliz em corrigir qualquer outra mudança que você queira testar, ou você pode verificar https://github.com/toji/xr-dinosaurs se quiser testá-lo localmente. (Não requer nenhum componente de servidor.)

Quanto ao perf: não é exatamente amanteigado, mas não é ruim.

Obrigado. 😁 Tenho trabalhado muito para melhorar o desempenho. Neste caso, durante a atualização para r112, percebi a regressão de desempenho e perguntei a @mrdoob sobre isso. Ele sugeriu que pode ser o novo e mais preciso shader padrão e sugeriu trocar alguns materiais com MeshLambertMaterial para verificar. Uma vez que o modelo de ambiente não configurou corretamente os materiais PBR de qualquer maneira, eu forcei para Lambert e o deixei lá, que recuperou quaisquer regressões de desempenho e depois algumas (uma vez que ocupa uma grande parte da janela de visualização). Deixei os dinossauros com o material padrão, uma vez que eles são o ativo "herói".

Nota secundária: Scene.environment atualmente não funciona quando GLTFLoader carrega malhas usando materiais especulares / brilhantes, pois o renderizador verifica MeshStandardMaterial por exemplo

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

No entanto, GLTFLoader cria um ShaderMaterial para cada material especular / brilhante. Percebi isso hoje ao testar com o modelo T-Rex ^^. Bem, mais uma razão para finalmente concluir o # 14099.

Não consigo reproduzir os artefatos de faixas quando nenhum mapa de ambiente é usado. Tudo fica bem em um Pixel (1) com uma configuração de iluminação simples, como um ambiente e uma luz pontual.

Hum, parece haver mais problemas com materiais físicos usando um mapa de ambiente. Confira a aparência dos exemplos a seguir em um 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

Não consigo reproduzir esses artefatos no meu iMac.

Algo muito estranho está acontecendo em minha máquina, sou capaz de reproduzir esses artefatos em todos os exemplos que utilizam o novo PMREMGenerator . Mas apenas ao executá-los localmente; ao visualizá-los online (na página threejs.org), todos parecem corretos.

Nunca experimentei esse problema e estou completamente perdido quanto ao que causa isso.

Estou executando um Windows 10 com uma GeForce GTX 750 TI, então não acho que este seja um problema específico do dispositivo.

Mas apenas ao executá-los localmente; ao visualizá-los online (na página threejs.org), todos parecem corretos.

Esteja ciente de que a versão dev possui alterações que ainda não estão presentes em prod . Você pode verificar o branch atual master e, em seguida, realizar um teste local?

Você pode verificar o branch master atual e, em seguida, realizar um teste local?

A primeira coisa que tentei depois de notar esse comportamento, os mesmos resultados. Muito curioso.

Você pode testar com janelas anônimas? Às vezes, as coisas podem ser armazenadas em cache ou as extensões do navegador interferem, o que pode ser muito confuso

Tentativa de navegação anônima, mesmos resultados :(

Eu acredito que sei por que essa banda está ocorrendo agora.
Durante a geração do mip, minha versão local (incorreta) está criando uma faixa preta que não existe na versão ao vivo.

local
online

Isso também é replicado para reduzir os níveis de mip.

Isso provavelmente está acontecendo devido a alguma amostragem de coordenadas incorreta. Eu experimentei desabilitar manualmente a filtragem anisotrópica, mas o problema permanece. É difícil apontar exatamente o que está acontecendo, especialmente porque não consigo entender por que ele apresenta dois comportamentos diferentes na mesma máquina.

@elalish depois de executar alguns testes em vários exemplos, consegui localizar a causa real desses artefatos. Ao contrário do que disse no meu post anterior, a causa raiz do problema não está relacionada com a amostragem de coordenadas incorretas, mas com a maneira PMREMGenerator está lidando com devicePixelRatio .

Em dispositivos com ponto flutuante nominal pixelRatio , estamos obtendo coordenadas mipmap "ruins" na textura gerada. Portanto, há pequenas lacunas e regiões sobrepostas. Eu também descobri que minha máquina tem devicePixelRatios dependendo se estou vendo o exemplo localmente (0,899 ..) ou online (1) e é por isso que eu só estava experimentando esses artefatos localmente.

Eu configurei um teste simples desabilitando setPixelRatio e parece resolver o problema, se esse for o caso de outros, então seria melhor refatorar a maneira PMREMGenerator está lidando com isso.

@toji @ plut0nist se importou em verificar os exemplos a seguir nos dispositivos que apresentaram esses artefatos?

DEV Exemplo
Exemplo de TESTE

@sciecode Muito obrigado por descobrir a causa raiz! Vou ver se consigo encontrar uma solução.

@sciecode : verificado em meus dispositivos. O teste de exemplo DEV exibe uma linha preta muito óbvia no mapa de ambiente, enquanto o exemplo de TESTE não. Depuração incrível, obrigado!

Eu estava extremamente curioso para saber por que PMREMGenerator precisava para contabilizar devicePixelRatio em tudo, então eu fui cavar. Acontece que é porque renderer.setViewport() fatora automaticamente o DPR em quaisquer valores que você enviar, o que parece ser claramente o comportamento errado para destinos de renderização diferentes do framebuffer padrão, que são alocados com valores de pixel exatos que não levar em conta a proporção de pixels em tudo. Eu sugeriria que o comportamento "correto" aqui é que internamente rendere.setViewport() deve estar usando getTargetPixelRatio() , que retorna 1 quando o alvo de renderização ativo é qualquer coisa diferente do padrão. Eu posso definitivamente ver como isso poderia introduzir problemas de compatibilidade retroativa, no entanto.

Esta página foi útil?
0 / 5 - 0 avaliações