Three.js: GLTFLoader: O resultado do modelo de teste normal-tangente está incorreto

Criado em 3 jun. 2017  ·  30Comentários  ·  Fonte: mrdoob/three.js

Descrição do problema

Tentei exibir o modelo de teste de tangente normal .
No entanto, o resultado exibido parece ser diferente da amostra de Khronos.

Resultado do modelo Three.js + Normal-Tangent Test:
image

Carregador de amostra Khronos + resultado do modelo de teste normal-tangente:
image

Acho que este modelo de amostra deve ter os mesmos resultados à esquerda e à direita.

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

/ cc @emackey

Versão Three.js
  • [x] Dev
  • [] r85
  • [] ...
Navegador
  • [x] Todos eles
  • [ ] Cromada
  • [ ] Raposa de fogo
  • [] Internet Explorer
SO
  • [x] Todos eles
  • [ ] Janelas
  • [ ] Mac OS
  • [] Linux
  • [] Android
  • [] iOS
Requisitos de hardware (placa gráfica, dispositivo VR, ...)

ThinkPad X260 + Windows 10 + Intel HD Graphics 520

Bug Loaders

Comentários muito úteis

Eu gostaria de mencionar uma frase da especificação glTF em mapas normais em particular:

Os vetores normais usam convenções OpenGL onde + X está certo e + Y está acima. + Z aponta para o visualizador.

Essa frase é o que permite que os modelos sejam enviados sem vetores tangentes, economizando espaço.

Vamos testar. Aqui, fiz um péssimo mapa de altura (mapa de relevo) de uma mancha em um programa de pintura:

TestHeightMap

Vamos definir este campo de altura como uma saliência externa, onde os pixels brancos estão mais próximos do visualizador e os pixels pretos estão mais distantes.

Usando um conversor online (de qualidade questionável, mas examinaremos o resultado em um momento), converti isso de um mapa de altura para um mapa normal. Tenha em mente que não há nenhum modelo 3D aqui, nenhuma coordenada UV ou cálculos de mikktspace ou qualquer geometria. Apenas um mapa de altura convertido em um mapa normal. Tive que configurar manualmente o conversor online de acordo com as instruções do glTF, de modo que X esteja certo, Y esteja ativado e Z fique de frente para o visualizador. Este é o resultado:

TestNormalMap

Vamos trazer isso de volta para um programa de pintura e analisar os canais de cores para ver para onde apontam esses vetores. Abaixo, cada canal de cor foi separado em uma imagem em tons de cinza própria. Lembre-se de que eles serão interpretados de forma que preto significa -1.0 , cinza médio significa 0.0 e branco significa +1.0 .

TestNormalMap-Decomposed

Então acho que o conversor online fez o que o glTF pediu, pelo menos depois de configurá-lo corretamente. Na imagem vermelha (X), podemos ver que a inclinação à direita tem pixels brancos (+1,0), apontando o vetor X para a borda direita da imagem. No lado esquerdo da imagem vermelha, pixels pretos (-1,0) apontam o vetor X para o lado esquerdo da imagem. Na imagem Verde (Y), os pixels brancos ao longo da inclinação superior da saliência apontam o vetor Y no topo da imagem. Os valores Z são os menos intuitivos, mas lembre-se de que a ponta da saliência e a placa traseira apontam para o observador e as inclinações em todos os lados apontam para fora, portanto, são todas uniformemente mais escuras.

E se carregarmos isso no Blender Eevee, que (assim como o glTF) aceita mapas normais no estilo OpenGL? O que acontece se o mapa UV for girado ou mesmo escalado para ser invertido?

NormalSpinTest

Acontece que isso funciona muito bem. Na verdade, o objetivo de definir o espaço tangente dessa forma não é permitir que o software enlouqueça com os vetores, é permitir aos artistas de textura alguma sanidade, garantindo que seus mapas normais estarão com o lado direito para cima, independentemente da geometria.

Mas nem todo software usa a convenção OpenGL. Alguns usam uma convenção diferente (às vezes chamada de convenção DirectX), onde os vetores Y apontam para a parte inferior da imagem em vez de para a parte superior. Aqui está o canal Y decomposto da minha imagem neste formulário. Os pixels mais claros são aqueles voltados para a parte inferior da imagem.

TestNormalMap_DirectX-Green

Se eu carregar um desses mapas normais do estilo DirectX no Blender Eevee, ainda posso esperar que funcione?

NormalSpinTest_DirectX_v3

Não. O Blender estava esperando + Y para cima. A matemática está errada e a linha do horizonte refletida gira ao redor.
A mesma coisa acontece se você carregar um mapa normal no estilo OpenGL em um mecanismo que esperava + Y para baixo.

Isso é o que o modelo NormalTangentTest está tentando testar. Cada linha gira as coordenadas UV em uma orientação diferente, tentando garantir que os reflexos permaneçam com o lado direito para cima nessas diferentes orientações.

Todos 30 comentários

Obrigado por escrever isso @ cx20.

Apenas para mais contexto, aqui estão algumas informações e problemas relacionados:

  • Eu relatei um problema semelhante no ThreeJS glTF viewer de @donmccurdy, donmccurdy / three-gltf-viewer # 10. Mas agora acho que este é um bug no carregador glTF do ThreeJS, não no visualizador. Portanto, este novo problema está melhor colocado do que o meu antigo.

  • Na edição anterior acima, o modelo costumava ficar voltado para o céu, mas depois girei-o para ficar voltado para o horizonte. Isso torna mais fácil ver quando os reflexos não estão certos, porque o horizonte gira loucamente, como mostrado acima.

  • O próprio uso do modelo de um mapa normal foi confirmado como correto pela discussão no KhronosGroup / glTF # 952.

  • O manuseio de mapas normais por ThreeJS foi questionado em # 11315.

  • BabylonJS teve recentemente um problema semelhante, relatado aqui e corrigido aqui . Aqui está uma demonstração ao vivo do carregador glTF 2.0 da BabylonJS com a correção aplicada .

Boa redação, obrigado!

O modelo parece ser renderizado corretamente com a adição desta linha:

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

Mas não tenho certeza se entendi bem o problema. Compreender o nº 11315 pode ajudar aqui.

@donmccurdy Obrigado pelo seu conselho.
Eu entendi que estava melhorando ajustando o normalScale.
No entanto, se o modelo glTF estiver correto, acho que é melhor para o glTF Loader lidar com ele.

@ cx20 concordou, esta correção agora está integrada em THREE.GLTF2Loader.

Eu confirmei que ele está sendo consertado.

Resultado do modelo Three.js + Normal-Tangent Test:
image

Isso regrediu, em algum momento entre r101 e r104:
Screenshot from 2019-06-11 16-38-27

Veja https://github.com/mrdoob/three.js/pull/15749 - a regressão é intencional e pode ser evitada incluindo tangentes no modelo.

Idealmente, teríamos uma implementação JS para gerar tangentes mikktspace, para resolver isso completamente, mas isso é bastante complexo.

Eu não estava ciente do # 15749 até agora. Fui pego de surpresa por isso, pensei que fizemos um trabalho bom o suficiente definindo as tangentes em glTF para que elas pudessem ser pelo menos aproximadas em tempo de execução.

Observe que o exportador do Blender não exportará nenhuma tangente glTF por padrão, pois ajuda a manter o tamanho do arquivo baixo, e as principais implementações de glTF foram todas passando neste teste sem tangentes. Eu suspeito que essa mudança pode ter quebrado o mapeamento normal para a maioria dos modelos glTF no ThreeJS.

Vou precisar de algum tempo para ler todas as questões vinculadas a uma compreensão mais profunda do que aconteceu e por quê. Mas acho que a comunidade glTF deve considerar esta alta prioridade para obter modelos sem tangentes renderizando corretamente novamente, pois acredito que a maioria dos modelos está nessa categoria por padrão.

Reabertura 😅

Eu suspeito que essa mudança pode ter quebrado o mapeamento normal para a maioria dos modelos glTF no ThreeJS.

Não acredito que seja algo tão grave - sempre geramos tangentes em tempo real no shader com derivados, e ainda geramos. Anteriormente, incluímos um hack ( normalScale.y *= -1 ) que corrigiu esse modelo de teste específico, mas também quebrou alguns outros exemplos. Não tenho explicação de quando isso ajudou ou não ajudou, então removemos o hack uma vez que suportamos tangentes armazenadas - caso em que certamente estaria errado. Agora os modelos que dependiam do hack (e não incluem tangentes) estão quebrados, e os modelos que foram quebrados pelo hack (e não incluem tangentes) estão corrigidos.

Mas acho que a comunidade glTF deve considerar esta alta prioridade para obter modelos sem tangentes renderizando corretamente novamente, pois acredito que a maioria dos modelos está nessa categoria por padrão.

Veja acima. Em geral, acredito que renderizamos modelos sem tangentes de forma adequada. No entanto, não geramos tangentes mikktspace conforme exigido pela especificação glTF. Até onde sei, não existe nenhuma implementação JS disso, e nossa implementação de sombreador baseada em derivados é simplesmente uma aproximação "boa o suficiente". Este modelo de amostra é um caso intencionalmente extremo que demonstra os limites dessa aproximação.

Ficaríamos felizes em ter uma implementação de geração de tangente JS mikktspace; isso seria um bom complemento para THREE.BufferGeometryUtils. Mas o código oficial (nativo) do mikktspace é bastante longo, e ainda não investiguei o suficiente para ver quanto dele é necessário para gerar tangentes.

Anteriormente, incluímos um hack ( normalScale.y *= -1 ) que corrigiu esse modelo de teste específico, mas também quebrou alguns outros exemplos

Ele quebrou outros modelos glTF especificamente ou apenas exemplos em geral?

Existem dois tipos diferentes de mapas normais de espaço tangente na natureza. O Substance Painter chama isso de "Normais DirectX" e "Normais OpenGL", que não é o melhor nome para isso. A diferença é especificamente que o canal y está invertido, o que significa que todos os valores do canal verde na textura estão invertidos. Multiplicar y *= -1 é a maneira correta de converter um para o outro. Os chamados "DirectX Normals" usam um sistema de coordenadas para canhotos e glTF define um sistema de coordenadas para destros para normal / tangente / bitangente.

O que eu suspeito que está acontecendo é que quando o ThreeJS calcula automaticamente as tangentes, ele espera que o mapa normal tenha sido criado com o estilo Y invertido (DirectX) e obtém esse canal para trás para glTF, então a inversão é necessária. No entanto, quando as tangentes são fornecidas, não é necessária tal inversão.

A questão do mikktspace, eu acho, é separada disso. É lamentável que a especificação exija mikktspace e a maioria das implementações se aproxime disso com derivados de espaço de tela. Não sei o quão semelhantes os dois são, mas os mapas normais gerados no mikktspace parecem funcionar razoavelmente bem quando mostrados com a aproximação, contanto que o lado esquerdo / direito do mapa seja feito corretamente.

(Também há alguma discussão sobre isso no ano passado no KhronosGroup / glTF-Sample-Models # 174)

Eu gostaria de mencionar uma frase da especificação glTF em mapas normais em particular:

Os vetores normais usam convenções OpenGL onde + X está certo e + Y está acima. + Z aponta para o visualizador.

Essa frase é o que permite que os modelos sejam enviados sem vetores tangentes, economizando espaço.

Vamos testar. Aqui, fiz um péssimo mapa de altura (mapa de relevo) de uma mancha em um programa de pintura:

TestHeightMap

Vamos definir este campo de altura como uma saliência externa, onde os pixels brancos estão mais próximos do visualizador e os pixels pretos estão mais distantes.

Usando um conversor online (de qualidade questionável, mas examinaremos o resultado em um momento), converti isso de um mapa de altura para um mapa normal. Tenha em mente que não há nenhum modelo 3D aqui, nenhuma coordenada UV ou cálculos de mikktspace ou qualquer geometria. Apenas um mapa de altura convertido em um mapa normal. Tive que configurar manualmente o conversor online de acordo com as instruções do glTF, de modo que X esteja certo, Y esteja ativado e Z fique de frente para o visualizador. Este é o resultado:

TestNormalMap

Vamos trazer isso de volta para um programa de pintura e analisar os canais de cores para ver para onde apontam esses vetores. Abaixo, cada canal de cor foi separado em uma imagem em tons de cinza própria. Lembre-se de que eles serão interpretados de forma que preto significa -1.0 , cinza médio significa 0.0 e branco significa +1.0 .

TestNormalMap-Decomposed

Então acho que o conversor online fez o que o glTF pediu, pelo menos depois de configurá-lo corretamente. Na imagem vermelha (X), podemos ver que a inclinação à direita tem pixels brancos (+1,0), apontando o vetor X para a borda direita da imagem. No lado esquerdo da imagem vermelha, pixels pretos (-1,0) apontam o vetor X para o lado esquerdo da imagem. Na imagem Verde (Y), os pixels brancos ao longo da inclinação superior da saliência apontam o vetor Y no topo da imagem. Os valores Z são os menos intuitivos, mas lembre-se de que a ponta da saliência e a placa traseira apontam para o observador e as inclinações em todos os lados apontam para fora, portanto, são todas uniformemente mais escuras.

E se carregarmos isso no Blender Eevee, que (assim como o glTF) aceita mapas normais no estilo OpenGL? O que acontece se o mapa UV for girado ou mesmo escalado para ser invertido?

NormalSpinTest

Acontece que isso funciona muito bem. Na verdade, o objetivo de definir o espaço tangente dessa forma não é permitir que o software enlouqueça com os vetores, é permitir aos artistas de textura alguma sanidade, garantindo que seus mapas normais estarão com o lado direito para cima, independentemente da geometria.

Mas nem todo software usa a convenção OpenGL. Alguns usam uma convenção diferente (às vezes chamada de convenção DirectX), onde os vetores Y apontam para a parte inferior da imagem em vez de para a parte superior. Aqui está o canal Y decomposto da minha imagem neste formulário. Os pixels mais claros são aqueles voltados para a parte inferior da imagem.

TestNormalMap_DirectX-Green

Se eu carregar um desses mapas normais do estilo DirectX no Blender Eevee, ainda posso esperar que funcione?

NormalSpinTest_DirectX_v3

Não. O Blender estava esperando + Y para cima. A matemática está errada e a linha do horizonte refletida gira ao redor.
A mesma coisa acontece se você carregar um mapa normal no estilo OpenGL em um mecanismo que esperava + Y para baixo.

Isso é o que o modelo NormalTangentTest está tentando testar. Cada linha gira as coordenadas UV em uma orientação diferente, tentando garantir que os reflexos permaneçam com o lado direito para cima nessas diferentes orientações.

Ainda precisa haver uma fórmula concreta na especificação de como calcular uma tangente para uma primitiva solitária, dada uma primitiva e suas coordenadas UV, e qual sinal W usar para bitangente. "OpenGL normais" e "DX normais" não são precisos o suficiente para derivar a fórmula. Eles podem se referir a convenções, mas não tenho ideia, como implementador, do que fazer com isso.

O que eu atualmente faço é emitir TangentW do MikkTSpace invertido para combinar com este exemplo específico, mas foi exatamente o que aconteceu para funcionar.

Ele quebrou outros modelos glTF especificamente ou apenas exemplos em geral?

Os bugs relatados estavam relacionados aos modelos glTF, especificamente. Dito isso, duvido que haja confiança suficiente na exportação de material via FBX ou COLLADA para dizer que essas convenções de mapas normais já foram totalmente compreendidas e testadas.

A diferença é especificamente que o canal y está invertido, o que significa que todos os valores do canal verde na textura estão invertidos. Multiplicar y * = -1 é a maneira correta de converter um para o outro.

Obrigado, esta é uma justificativa muito melhor para o nosso "hack" do que quando o implementamos. 😇

É lamentável que a especificação exija mikktspace e a maioria das implementações se aproxime disso com derivados de espaço de tela.

A especificação certa é que o MikkTSpace é a maneira mais robusta de gerar tangentes, eu acho, mas não é universalmente a escolha certa para fazer isso automaticamente em tempo de execução. Se alternativas mais baratas parecem corretas para um modelo específico, não há razão para fazer algo mais caro que não parece melhor. A linguagem de especificação pode ser afrouxada para permitir aproximações, mas não tenho uma opinião forte sobre isso.

Ainda precisa haver uma fórmula concreta na especificação de como calcular uma tangente para uma primitiva solitária, dada uma primitiva e suas coordenadas UV, e qual sinal W usar para bitangente.

Não tenho certeza se o algoritmo MikkTSpace é tão fácil de representar como uma fórmula discreta ... você está pedindo uma alternativa para o código MikkTSpace canônico? Ou alguma informação adicional além da instrução de uso do MikkTSpace? @Themaister


Para o problema original, parece que devemos restaurar o multiplicador normal.y *= -1 algum lugar. Existem três lugares possíveis para fazer isso:

  • (a) no GLTFLoader, para malhas que não possuem tangentes
  • (b) no GLTFLoader, para todas as malhas
  • (c) no WebGLRenderer, para todas as malhas

Se threejs está realmente usando a convenção DirectX e, por exemplo, o Blender não, eu poderia ver um caso para (c). No interesse de uma solução rápida e segura, porém, estou inclinado a escolher (a).

O que eu suspeito que está acontecendo é que, quando o ThreeJS calcula automaticamente as tangentes, ele espera que o mapa normal tenha sido criado com o estilo Y invertido (DirectX).

Não, three.js não assume que ...

three.js assume que + Y é "para cima" para espaço tangente, e aumentar-V é "para cima" para espaço uv.

Ou seja, three.js assume uv (0, 0) está no canto esquerdo inferior da textura, enquanto a especificação glTF assume o canto superior esquerdo. É por isso que GLTFLoader define texture.flipY para false . (three.js define texture.flipY para true por padrão.)

Quando as tangentes não estão presentes, three.js usa derivadas de espaço de tela para estimar tangentes. Ele faz isso usando a regra da cadeia. Uma suposição nesse cálculo é que o espaço tangente e o espaço UV têm a mesma orientação.

Para modelos glTF de autoria adequada, essa suposição não é correta. No entanto, você deve ser capaz de compensar definindo normalScale.y = - 1 para qualquer modelo que _propriadamente aderir à especificação glTF_.

Também me parece que poderíamos corrigir isso automaticamente honrando o sinalizador flipY no sombreador.

Se a configuração normalScale.y não estiver funcionando, algo mais está acontecendo.

Obrigado por este esclarecimento. Acho que temos um caminho a seguir aqui.

Também me parece que poderíamos corrigir isso automaticamente honrando o sinalizador flipY no sombreador.

Sim, com exceção dos casos em que o glTF fornece seus próprios vetores tangentes, certo? Eu esperaria que apenas as tangentes calculadas automaticamente precisassem do teste flipY e da negação correspondente de y .

Se esse não for o caso ... isso significaria que meu modelo NormalTangentMirrorTest tem tangentes incorretas codificadas nele, significando que o próprio exportador glTF do Blender está colocando as tangentes erradas nos modelos glTF.

Edit: Eu acredito que confirmei a exatidão dos vetores tangentes exportados e eles não precisam de nenhuma inversão de Y. Posso postar mais detalhes sobre isso, se necessário.

Mas parece que a ação correta é inverter normalScale.y apenas quando tangentes geradas automaticamente (não tangentes fornecidas) estão sendo usadas com a bandeira flipY . Pensamentos?

Em meu post anterior, expliquei como compensar manualmente os normais invertidos quando as tangentes de atributo não estão presentes. Não deve haver nada para compensar quando as tangentes estão presentes porque as derivadas do espaço da tela não estão sendo usadas.

Também sugeri que podemos consertar isso automaticamente, honrando o sinalizador flipY no shader. Eu não disse que corrigiríamos isso automaticamente ao inverter normalScale.y , entretanto. Não acho que devemos alterar as configurações do usuário.

De qualquer forma, antes de seguirmos por esse caminho, acho que é imperativo verificarmos esta hipótese:

[Você] deve ser capaz de compensar definindo normalScale.y = - 1 para qualquer modelo que esteja de acordo com as especificações glTF.

Devemos ter uma explicação para cada modelo que não está sendo renderizado corretamente.

Não acho que devemos alterar as configurações do usuário.

Sim, desculpas, eu não pretendia ditar esse tipo de detalhe de implementação. Estou apenas tentando ter certeza de que não há um mal-entendido sobre o que _honrar a flipY flag_ significa matematicamente, para o propósito de geração de tangente do espaço da tela.

Devemos ter uma explicação para cada modelo que não está sendo renderizado corretamente.

Parece que pode ser um conjunto grande. Se realmente existem modelos por aí que estão fazendo algo radicalmente diferente dos modelos de teste oficiais, e ainda assim podem ser considerados usos válidos de mapas normais no glTF, isso seria importante descobrir. Os modelos de teste destinam-se a cobrir usos válidos de mapas normais em geometria estática (não transformada). Não deveria haver uma maneira, particularmente quando depender de vetores tangentes gerados pelo visualizador, de construir o modelo em algum outro sistema de coordenadas e ainda afirmar que é glTF válido.

Presumo que isso esteja intimamente relacionado a esse problema. https://github.com/KhronosGroup/glTF-Sample-Models/issues/174

@WestLangley Aqui está o que descobri até agora. Por padrão, khronos-NormalTangentTest (sem tangentes incluídas) parece errado:
NormalTangentTest
Se eu definir normalScale.y = -1, ainda estará errado:
NormalTangentTestNegY
Se eu, em vez disso, definir normalScale.x = -1, parece correto:
NormalTangentTestNegX
Com a possível exceção de que a renderização parece um pouco pixelizada, especialmente no refletor dourado. Isso é esperado com a aproximação do espaço da tela ou um indicador de outro bug?

Se alguém tiver outros modelos de teste bons sem tangentes, envie-os em minha direção. Gostaria de ter certeza de que tenho uma amostra representativa e determinar se há alguma que não se encaixa nas especificações do glTF.

@elalish Esse testbed não faz sentido para mim, nunca fez sentido para mim e provavelmente nunca fará. Então ... não vou te ajudar a tentar explicá-lo.

Esse exemplo é IMHO muito ofuscado. Precisamos de um caso de teste coerente que forneça recursos visuais suficientes para entender o que está acontecendo.

BTW, costumávamos ter um VertexTangentHelper (# 3511), que poderia ser revivido para suportar a geometria do buffer.

@WestLangley Eu gostaria de saber como tornar o NormalTangentTest mais claro. Ele não faz nada de estranho, ele simplesmente gira a orientação (no espaço UV) de cada amostra. As três colunas são apenas para testar diferentes materiais, a coluna de ouro pode bastar por si só. Fora isso, não acho que o modelo de teste possa ficar muito mais simples e ainda testar essas diferentes orientações de UV.

Apesar das rotações UV, a imagem do mapa normal é bastante consistente sobre a direção que os vetores apontam, quando o mapa normal é visto como uma imagem 2D. Em uma visualização 2D da imagem, os lados direitos de todos os hemisférios têm altos valores de canal vermelho e as bordas superiores de todos os hemisférios têm altos valores de canal verde, independentemente das coordenadas UV. Isso segue a especificação glTF de que o vermelho (+ X) aponta para o lado direito da textura no espaço UV e o verde (+ Y) aponta para a borda superior da textura no espaço UV. Não é necessário fornecer vetores tangentes para fazer este trabalho: uma estimativa de espaço de tela simples de geralmente em que direção o eixo + U é para um determinado triângulo é suficiente para calcular os vetores tangente e bi-tangente, como BabylonJS e CesiumJS fazem, e, claro, o ThreeJS também, mas com alguma inversão do eixo normalScale ainda inexplicada.

Há um ponto conhecido de confusão com o uso do glTF do sinalizador flipY , invertendo as coordenadas V no espaço UV, que eu acredito que você já esteja bem ciente. Há muito suspeito que isso desempenha um papel na inversão de escala normal inexplicável.

Há também um pequeno erro de cozimento na imagem (culpa minha, eu era um novo usuário do Substance Painter na época, anos atrás). Uma ligeira costura diagonal é visível principalmente na parte plana dos hemisférios dourados. Mas isso não deve prejudicar o efeito geral. A parte redonda principal do assado ficou boa e demonstra bem o efeito de "para cima" e "direita" sendo constantes em toda a imagem 2D da textura normal, independentemente das coordenadas 3D ou UV sendo giradas em todas as direções diferentes e tangentes sendo omitido.

Este é um efeito importante para artistas que estão criando texturas normais de mapas antes da geometria 3D ser criada, já que o artista não precisa acessar as coordenadas UV ou tangentes antes de fazer a imagem da textura.

@WestLangley Gosto deste teste apenas porque é o melhor que já vi, ou seja, o único. Ficarei feliz em usar qualquer outro modelo de teste para o qual me indique.

Além disso, o gráfico fica mais espesso: o teste original é um material de dupla face. Devido ao # 17804, decidi tentar como um só lado. Ainda está errado por padrão, mas agora obtenho a resposta certa ao definir normalScale.y = -1:
NormalTangentTestFrontNegY
No mínimo, espero que possamos concordar que alterar os dois lados não deve afetar a renderização do lado frontal.

@emackey Outro modelo de teste que poderia ser útil, eu acho, seria um cubo brilhante com normais soldados e um mapa normal correspondente projetado para torná-lo em forma de cubo em vez de arredondado. Provavelmente duas versões, uma com e outra sem tangentes fornecidas. Infelizmente, não tenho a habilidade de autoria para fazer isso sozinho. Tudo o que posso oferecer é muito obrigado, se você fizer isso por nós: ore:

@emackey Obrigado por todo o seu trabalho nisso. Eu agradeço muito. Eu entendo todas as várias questões que podem surgir com os artistas - e questões que devem ser superadas.

Talvez você esteja disposto a trabalhar com @elalish e fornecer quaisquer modelos glb que ele solicitar. Espero que isso nos ajude a entender.

@elalish Já tratamos desses problemas anteriormente. A certa altura, tive a impressão de que tudo estava funcionando. Se houver um caso de teste simples, posso usar bisect para identificar onde as coisas quebraram.

cubo brilhante com normais soldados e um mapa normal correspondente projetado para torná-lo em forma de cubo em vez de arredondado.

Feito: normal_map_flat.zip . Peguei o exemplo das tangentes, escrito pela equipe Draco, e criei uma versão extra sem o atributo tangente.

A certa altura, tive a impressão de que tudo estava funcionando.

Acho que chegamos a um estado em que tudo funciona _se_ o modelo inclui tangentes. Se não, as coisas geralmente estão bem, mas existem alguns casos extremos possíveis, especialmente em torno de costuras UV. Nesse caso, aconselhamos os usuários a adicionar tangentes. Ou, como @emackey mencionado em https://github.com/mrdoob/three.js/issues/11438#issuecomment -507027586, talvez devêssemos restaurar o normalScale.y *= -1 flip no GLTFLoader, apenas nos casos em que a malha omite tangentes de vértice.

Obrigado @donmccurdy . Estou sem tempo para este problema hoje, mas ainda estou lutando com os lados planos do cubo. Se você editar seu modelo para ter uma superfície brilhante ( metallicFactor: 1, roughnessFactor: 0.1 ), você verá os reflexos nas laterais do cubo girando um pouco.

Estou vendo o mesmo efeito em meu próprio modelo de teste. Pior, é um efeito diferente se eu assar normalmente em Substance Painter e assar em Blender Cycles. Cada programa o coa para ser correto para sua própria janela de visualização, mas não é perfeitamente plano quando carregado no outro programa, mesmo sem glTF na mistura. É muito perto, mas em uma superfície tão plana as menores diferenças a transformam em um espelho de diversão, e não no bom sentido.

Acho que estou vendo uma diferença sutil na maneira como os vetores normais (ou espaço TBN) são interpolados entre os vértices na face de um triângulo, em SP vs Blender vs os vários motores WebGL. Eu usei o Gimp para executar uma "diferença" de um assado SP vs um assado Blender, e ficou preto (valores RGB idênticos) em cada vértice, mas o espaço entre os vértices mostra diferenças giratórias de intensidade muito fraca.

Eu esperaria efeitos divertidos sutis, mas não o que estou obtendo atualmente (a versão sem tangentes):
image
A versão com tangentes não é realmente melhor, o que me leva a perguntar se este é realmente um glTF válido:
image
@emackey Você se sente qualificado para nos dizer se um ou ambos os modelos @donmccurdy fornecidos são de fato glTF válidos? Se estiverem, acho que temos um grande problema.

Este cubo em particular é um exemplo tão extremo que realmente não sei o que dizer, ou se reflexos fisicamente realistas são uma expectativa justa. Os mapas normais são destinados a adicionar detalhes como saliências e amassados, não para deformar toda a superfície da malha. Aconteceu de ser uma maneira muito eficaz de testar se as tangentes são lidas ou geradas corretamente. Eu sei que a mudança normalScale.y *= -1 nunca foi suficiente para consertá-lo; este foi um dos exemplos que nos levou a apoiar tangentes armazenadas em primeiro lugar.

Os reflexos também parecem selvagens no BabylonJS:
Screen Shot 2019-10-23 at 4 00 02 PM

Se o único problema identificado for com NormalTangentTest, e nenhum usuário apresentou modelos que renderizam incorretamente na prática, talvez devêssemos adiar para fazer uma alteração aqui.

Ainda estou bem em restaurar o multiplicador normalScale.y *= -1 , mas a falta de exemplos do problema parece uma indicação de que o problema é menor, em vez de uma indicação de que precisamos criar tais exemplos extremos.

Se o único problema identificado for com NormalTangentTest, e nenhum usuário apresentou modelos que renderizam incorretamente na prática, talvez devêssemos adiar para fazer uma alteração aqui.

Correção: https://github.com/mrdoob/three.js/issues/17804 sugere que algo pode de fato ter regredido com materiais de dupla face. Parece que vale a pena investigar mais, embora, para simplicidade e sanidade, talvez devêssemos deixar o Cubo Amaldiçoado em paz por enquanto. 😇

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