Three.js: O deslocamento / repetição de UV deve fazer parte dos materiais e não das texturas

Criado em 10 jan. 2015  ·  73Comentários  ·  Fonte: mrdoob/three.js

Offset UV e repetição (e provavelmente algumas das outras propriedades de textura) são uniformes que são estranhamente passados ​​da textura para o material, o que leva a problemas onde você tem que clonar texturas por material (desperdiçando uma tonelada de memória) se você quiser -material desloca / repete, ou rola seu próprio sombreador personalizado. É muito ineficiente forçar as pessoas a fazer isso, o melhor caso é se alguém quiser colocar uma textura lado a lado em uma superfície com base no tamanho do objeto ao qual é aplicada, ou usar uma textura como uma spritesheet para animações. Eu só posso ver o sistema atual como um obstáculo sem vantagens reais, uma vez que a probabilidade de precisar de offsets / repetições UV compartilhados em uma textura "compartilhada" é baixa e normalmente seria melhor servida compartilhando um material. Em qualquer caso atualizar os uniformes fora da textura é estranho, pois realmente não tem por que fazer parte da textura, e acaba confundindo o usuário final. Por exemplo, alterar o deslocamento / repetição quando mais de um mapa é aplicado ao material, exemplo difuso + mapa normal, usa apenas o deslocamento / repetição do mapa difuso, então o valor do deslocamento / repetição normalmaps é completamente inútil nesse contexto , quando realmente sugere que deve afetar o deslocamento / repetição normal do mapa. É tudo confuso.

Tenho certeza de que a alteração é necessária na função "refreshUniformsCommon", mas provavelmente há mais do que isso. Existem algumas mudanças necessárias no plugin sprite também. Isso provavelmente quebraria muitos projetos das pessoas, mas é uma grande inconsistência na API de textura / material. Pode ser uma ideia melhor torná-lo um override que normalmente é nulo para materiais e, quando definido, ignora os valores nas texturas, apenas para não quebrar o material de todos.

Suggestion

Comentários muito úteis

este tópico é TL; DR para mim. mas acabei de descobrir este código em r68 (projeto antigo, sim):

        // uv repeat and offset setting priorities
        //  1. color map
        //  2. specular map
        //  3. normal map
        //  4. bump map
        //  5. alpha map

        var uvScaleMap;

        if ( material.map ) {

            uvScaleMap = material.map;

        } else if ( material.specularMap ) {

            uvScaleMap = material.specularMap;

        } else if ( material.normalMap ) {

            uvScaleMap = material.normalMap;

        } else if ( material.bumpMap ) {

            uvScaleMap = material.bumpMap;

        } else if ( material.alphaMap ) {

            uvScaleMap = material.alphaMap;

        }

        if ( uvScaleMap !== undefined ) {

            var offset = uvScaleMap.offset;
            var repeat = uvScaleMap.repeat;

            uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );

        }

então sim...

se você vai propor uma mudança fundamental para a biblioteca, como a que você propôs aqui, você deve fornecer um argumento claro e convincente para essa mudança

Eu estava tentando definir uma repetição diferente em mapas difusos e normais e puxando meu cabelo porque não funcionou. como a API coloca essa configuração na textura, pensei que poderia fazer isso. então, sim, que tal guardar meu cabelo para uma discussão convincente? este tíquete ainda está aberto, 3js ainda tem essa configuração nas texturas, e só é respeitado para uma das texturas = esta é, na verdade, já é configuração permaterial.

Se você não vai mover isso para onde ele pertence, pelo menos diga que não tem efeito nos documentos.

Todos 73 comentários

Postagem relacionada: https://github.com/mrdoob/three.js/issues/3549

você tem que clonar texturas por material (desperdiçando uma tonelada de memória)

Em que sentido toneladas de memória são perdidas?

a probabilidade de precisar de deslocamentos / repetições UV compartilhados em uma textura "compartilhada" é baixa

O que você quer dizer com isso?

Se mantivermos a abordagem atual, uma coisa que precisa ser alterada é que, quando uma textura é clonada, a imagem compartilhada deve ser passada para a GPU apenas uma vez.

se você tem um objeto com um grande número de quadros / folhas, muitos objetos inúteis são criados e, como você afirmou, a imagem é copiada várias vezes para a GPU, o que é extremamente desperdiçador. Ainda mais desperdiçador, se você tiver vários objetos que precisam estar em diferentes pontos em diferentes animações, você terá que criar um conjunto único de texturas por material / objeto único, então rapidamente se torna chato de manusear, onde um material uniforme poderia muito mais facilmente ser manipulado sem ter essas estruturas de dados de deslocamento / repetição de textura extras construídas em torno de uma API mal planejada apenas para fazê-la funcionar. Tenho uma grande lentidão em um determinado caso de uso do meu aplicativo em que tenho que criar esses grupos de textura exclusivos em todos os lugares, e sinto que a única solução seria substituir todos os materiais de estoque que uso por materiais de sombreamento para solucionar esse único problema, ou então faça um fork da minha versão THREE.js e faça as modificações necessárias.

Em relação à segunda declaração:

Eu quis dizer que o paradigma atual apenas facilita o trabalho nos casos em que você deseja aplicar a mesma textura com o mesmo deslocamento / repetição UV, mas isso geralmente é um caso raro, uma vez que parece muito mais provável que você queira definir isso como outro uniformes, por material, e compartilham um material em vez de apenas a textura.

A principal ressalva com o sistema atual. é que o deslocamento / repetição só existe realmente como um único uniforme que afeta todas as texturas no sombreador, mas o fato de ser anexado a TRÊS. A textura significa que não pode ser usado corretamente como um uniforme e engana as pessoas fazendo-as pensar que deslocamentos / repetições pode ser escolhido de forma diferente para as várias texturas que podem ser aplicadas em materiais de estoque (ou seja, você pode definir um deslocamento difuso diferente e um deslocamento normal do mapa, mas isso não é realmente possível, embora eles possam ser definidos exclusivamente nas diferentes texturas). Posso ver que pode ter sido remanescente do renderizador de tela, mas simplesmente não faz sentido com o sistema de materiais webGLrender / GLSL, que o usurpou em grande parte.

mrdoob afirmou que precisaria ser da seguinte forma como uma razão para não tê-lo por material,

material.map
material.mapOffset
material.mapRepeat
material.env
material.envOffset
material.envRepeat
... etc.

mas, novamente, o deslocamento / repetição não funciona por tipo de mapa mesmo agora, então este não é realmente um argumento válido. De qualquer forma, seria um desperdício de uniformes demais para tê-lo por tipo de mapa (sem mencionar que você normalmente usa apenas um conjunto de UVs, então você não teria realmente vários deslocamentos para um mapa normal / mapa de relevo / mapa difuso / mapa especular). Eu acho que se você pesar todas as opções razoáveis, realmente deve ser uma propriedade de material em vez de propriedade de textura. Realmente não sinto que haja vantagens no sistema atual. Acho que a animação de materiais por meio do offset UV é um dos principais motivos para ter a propriedade, e nem mesmo pode ser usado corretamente para isso. Sem mencionar que se você não precisasse desses uniformes, eles poderiam ser omitidos da compilação de shaders, ao passo que agora eles estão lá desde que haja um mapa.

@QuaziKb Com todo o respeito, se você vai propor uma mudança fundamental para a biblioteca, como a que você propôs aqui, você deve fornecer um argumento claro e convincente para essa mudança. Discutir a partir do quadro de referência de seu aplicativo em particular não vai resolver isso.

Dito isso, eu também gostaria de ver a compensação / repetição movida de Texture para os materiais.

Acredito que seja razoável supor que os seguintes mapas tenham os mesmos valores de deslocamento / repetição:

specularMap
normalMap
bumpMap
alphaMap
aoMap (future)
glossMap (future)
displacementMap (future)

A única exceção é


É assim que está implementado agora; mesmo que cada mapa tenha seus próprios valores de deslocamento / repetição, eles não são respeitados.

Assim, poderíamos adicionar a MeshPhongMaterial , MeshLambertMaterial , MeshBasicMaterial e SpriteMaterial , adicionaríamos

mapOffset // or mapTranslate
mapRepeat // or mapScale

Removeríamos offset e repeat de Texture .

Desta forma, implementar uma folha de sprite é simples. Cada sprite tem um material, e esses materiais compartilham uma única textura. A textura tem uma imagem. A textura não precisa mais ser clonada. No lado da GPU, os materiais compartilhariam um único programa de shader.

IMHO, esta é uma API mais natural.

Estou tentando lembrar por que a API foi implementada da maneira que estava. Acho que houve um bom motivo.

Desculpe, não quis sugerir que era particular para o meu exemplo, simplesmente que a API atual leva a um inchaço significativo quando usada para animar folhas / deslocamentos de sprites por objeto / material único, sem solução real. Naturalmente, o objetivo principal de ter isso como um uniforme, em vez de simplesmente assar o deslocamento / repetição nos UVs de vértice do modelo, é animar o deslocamento, e eu estava sugerindo que isso não pode ser feito sem passar pela API, tornando o uniforme muito menos útil anexado a texturas do que se fosse ao material.

Acredito que seja razoável supor que os seguintes mapas tenham os mesmos valores de deslocamento / repetição:
mapa
...
alphaMap

FWIW, esse comportamento (a implementação atual) está causando uma frustração significativa para mim neste exato momento. Estou tentando animar a revelação de uma malha interpolando o deslocamento alphaMap do material da malha independentemente de seu mapa difuso (que permanece fixo). Depois de alguma frustração descobri via https://github.com/mrdoob/three.js/pull/4987 e esse bug que isso não é possível.

@jcarpenter A que "bug" você está se referindo? Qual é a sua sugestão de melhoria?

Correção: por "bug" eu quis dizer esse problema. Uma confusão devido ao tempo excessivo em uma cultura Bugzilla. : p Eu entendo que este não é um bug, mas sim o comportamento pretendido.

WRT para uma melhoria, com base na minha experiência com aplicativos tradicionais de criação de conteúdo 3D como Cinema 4D, imagino que o usuário seja capaz de:

  • definir deslocamento / escala / repetição para cada textura dentro de um material, independente das outras texturas, _e_
  • definir o deslocamento / escala / repetição do material original

Como alternativa, para o caso de uso no qual estou trabalhando ("tentativa de animar a revelação de uma malha"), seria fantástico ter uma opção para wrapS e wrapT que não envolvam de forma alguma. De acordo com o GIF anexado do Cinema4D, que tem uma opção para desativar o ladrilho inteiramente para mapeamento UVW. Com base em testes bastante extensos com os métodos wrapS e wrapT existentes, nada como isso é possível. O que significa que minhas opções para animar a revelação de itens em three.js parecem limitadas à posição de interpolação e opacidade de toda a malha ... A menos que esteja faltando alguma coisa.

c4d-tile-2

Concordou. O plano é simplificar tudo isso (usando uma única matriz3 no shader) e ter um deslocamento / repetição (ou tradução / escala) por textura.

Quem quiser ajudar com isso ficaria muito grato!

@jcarpenter

infelizmente, a única maneira de fazer isso agora é com várias malhas com materiais diferentes ou um material de sombreador personalizado. Ambos são meio envolvidos para um usuário que está entrando no fluxo de trabalho do three.js.

Há uma troca constante entre usabilidade, desempenho e extensibilidade. Minha sugestão seria reescrever a maneira como as texturas e materiais funcionam atualmente na API, de modo que as texturas sejam estritamente parâmetros que você conecta e os valores que são realmente uniformes no sombreador, como modo de deslocamento / repetição / agrupamento, sejam vinculados especificamente ao material. Em alguns casos, você não quer um uniforme desperdiçado no controle de UVs para texturas que nunca precisam ser alteradas (seria um grande desperdício ter 4 * 5 uniformes extras em um material phong se você só precisar dele para difundir), então seria legal se houvesse alguma mágica nos bastidores que detectasse se UVs específicos são necessários e a textura é reconstruída para atender a essas demandas, ou se algum parâmetro pudesse opcionalmente ser passado para especificar o número de UVs ajustáveis ​​necessários e o que mapas eles compensam e como, mas é um problema difícil de resolver.

O plano é simplificar tudo isso (usando uma única matriz3 no shader) e ter um deslocamento / repetição (ou tradução / escala) por textura.

@mrdoob

  1. Você quer dizer _per material.map_ então a transformação da textura está no material? Infelizmente, existem muitos mapas de materiais. Poderíamos continuar assumindo que todas as transformações de textura são iguais, exceto para o mapa de luz.
  2. Você quer oferecer suporte à rotação também? Nesse caso, você também deve adicionar o centro de rotação - a menos que queira conectar o centro de rotação ao centro da textura.

Esta seria uma mudança muito apreciada. Ter que clonar texturas apenas para colocá-las em valores de repetição exclusivos parece terrivelmente complicado. É assim que outras bibliotecas fazem?

  1. Você quer dizer _per material.map_ então a transformação da textura está no material? Infelizmente, existem muitos mapas de materiais. Poderíamos continuar assumindo que todas as transformações de textura são iguais, exceto para o mapa de luz.

Acho que devemos ter um mat3 por mapa e deve ser composto a partir das propriedades Texture .

  1. Você quer oferecer suporte à rotação também? Nesse caso, você também deve adicionar o centro de rotação - a menos que queira conectar o centro de rotação ao centro da textura.

Rotação sim. Centralizado ou não ... Não tenho certeza, mas pelo que entendi, tudo isso pode ser codificado em um único mat3 para o shader (por mapa).

Aqui está um protótipo mostrando como um Matrix3 pode ser passado para um sombreador e representa uma transformação definida por offsetX , offsetY , repeatX , repeatY , rotation , rotationCenterX e rotationCenterY .

Se center não for permitido como uma opção, então deve ser conectado fisicamente a ( 0.5, 0.5 ) .

Comentários são bem-vindos.

EDIT: demonstração atualizada

rotateuvs

ISSO É ÓTIMO! : +1:: +1:

No entanto, acho que escolheria translation e scale (em vez de offset e repeat ).

Quais, exatamente, devem ser as novas propriedades do material? Existem muitos mapas de materiais.

O que deve ser removido das propriedades da textura?

Estou assumindo que wrapS/T deve permanecer na textura.

Acho que texture.offset e texture.repeat devem ser removidos.

Acho que as novas propriedades deveriam ser ... texture.translation , texture.rotation , texture.scale , texture.center e texture.matrix . Provavelmente também precisaremos de um método texture.updateMatrix() que seria chamado no momento da renderização. Isso, é claro, tem o desafio de garantir que faremos isso apenas uma vez, mesmo que a textura seja reutilizada.

Referindo-se ao título deste post e aos argumentos em https://github.com/mrdoob/three.js/issues/5876#issuecomment -69483293, pensei que o objetivo era mover essas propriedades para o material.

/ ping @bhouston para comentários.

Minha opinião é que o deslocamento / repetição da textura deve ser incorporado aos UVs o máximo possível. É mais fácil. É assim que UE4 / Unity 5 fazem isso na maior parte.

A exceção é que o Unity 5 tem a capacidade de especificar um deslocamento / repetição global por material que é compartilhado em todas as texturas - mas não afeta o que são considerados mapas preparados, como o lightMap ou mapas ambientOcclusion (aqueles não faz sentido ser ajustado.)

A razão pela qual não defendo muita flexibilidade aqui é que os modelos criados profissionalmente têm UVs adequados que geralmente tornam isso desnecessário - as ferramentas de criação de conteúdo têm maneiras de assar isso. O outro problema é que o WebGL tem um limite inferior ridiculamente baixo para Fragment Uniforms - 16 Vec4. Se você tiver que repetir / deslocar por mapa, e obteremos muitos mapas em breve, estamos desperdiçando Fragment Uniform por muito pouco valor.

Na verdade, adicionei controles de repetição / deslocamento e brilho / ganho por textura no Clara.io recentemente e irei desfazer essas alterações porque isso está causando o estouro de Fragment Uniforms em dispositivos de baixo custo - como todos os dispositivos Apple iOS. Embora ter repetição / deslocamento e brilho / ganho funcione muito bem em desktops com NVIDIA 980s, temos que projetar para todos, não para máquinas de última geração. ;)

Devemos tratar os Fragment Uniformes com respeito e apenas usá-los quando necessário. Acredito que esse não seja um desses casos.

A exceção é que o Unity 5 tem a capacidade de especificar um deslocamento / repetição global por material

Isso é basicamente o que three.js está fazendo agora - embora obtenha o deslocamento / repetição do mapa difuso, e todas as outras texturas de materiais usam a configuração desse mapa.

A proposta é remover o deslocamento / repetição da textura e adicioná-lo ao material - talvez com uma mudança de nome. Novamente, todas as texturas de materiais compartilhariam as mesmas configurações (embora alguns usuários não ficassem felizes com isso). Isso manteria o uso uniforme baixo.

Infelizmente, não estamos obtendo muito consenso sobre isso.

Fazer o que o Unity 5 está fazendo é uma boa ideia. Eu colocaria no material em vez da textura também. Você tem meu apoio.

Por mapa não é realmente ideal, mas pode ser resolvido especificando-o com flags / keys de alguma forma quando os materiais forem construídos, caso seja necessário.

Geralmente, a única razão para modificar os UVs no sombreador é porque você os deseja animados. Se você deseja apenas transformar os UVs estaticamente, não devemos modificar o sombreador para adicionar esta funcionalidade.

A única alteração proposta para o shader é substituir

vUv = uv * offsetRepeat.zw + offsetRepeat.xy;

com

vUv = ( uvTransform * vec3( uv, 1 ) ).xy;

OK. Que tal isso ... Adicionamos texture.dynamic ( false por padrão) que produz:

vUV = uv;

Se o usuário definir texture.dynamic para true então calculamos texture.matrix de texture.translation , texture.rotation , texture.scale e texture.center , passamos isso para o programa e produzimos:

vUv = ( uvTransform * vec3( uv, 1 ) ).xy;

Claro, se texture.dynamic mudar, precisamos recompilar o programa.

Assim obtemos o melhor dos dois mundos?

@mrdoob

  1. Em sua opinião, scale uma propriedade da textura ou texture.scale uma propriedade do material? Espero que seja o último, porque é disso que trata este tópico.
  2. Não precisamos de uma propriedade .matrix . O novo Matrix3 é um uniforme que substitui o uniforme material offsetRepeat . É calculado a partir de outros parâmetros no renderizador e passado para a GPU como qualquer outro uniforme.
  1. Em sua opinião, scale uma propriedade da textura ou texture.scale uma propriedade do material? Espero que seja o último, porque é disso que trata este tópico.

Eu discordo deste tópico. Não acho que devemos poluir os materiais com mapMatrix , envMapMatrix , ... Nem mapTranslation , mapRotation , mapScale . Acho que é mais limpo se THREE.Texture tiver translation , rotation , scale e talvez center .

  1. Não precisamos de uma propriedade .matrix . O novo Matrix3 é um uniforme que substitui o uniforme material offsetRepeat . É calculado a partir de outros parâmetros no renderizador e passado para a GPU como qualquer outro uniforme.

Precisamos de algo assim. Digamos que se reutilize a mesma textura em mapas diferentes. Não queremos calcular Matrix3 para cada instância.

Eu discordo deste tópico. Não acho que devemos poluir os materiais com mapMatrix, envMapMatrix, ... Nem mapTranslation, mapRotation, mapScale. Acho que é mais limpo se TRÊS. A textura tem translação, rotação, escala e, talvez, centro.

Uma textura ainda precisaria ser clonada para ter propriedades de repetição diferentes? Em cenas pequenas isso provavelmente não é grande coisa, mas em cenas grandes, onde já existem mais de 40 texturas, isso é um pesadelo de memória.

@titansoftime image deve ser desacoplado de THREE.Texture . Idealmente, um único THREE.Image poderia ser usado por diferentes THREE.Texture cada um com diferentes translation , rotation , ... configurações.

A imagem

Isso faz sentido. O texture.clone () já funciona assim ou tem que ser configurado manualmente?

texture.clone() funciona dessa forma, mas WebGLRenderer não pode saber que a imagem é a mesma, então é aí que o upload da textura é desnecessário ...

Eu discordo deste tópico. Não acho que devemos poluir os materiais com mapMatrix, envMapMatrix, ... Nem mapTranslation, mapRotation, mapScale. Acho que é mais limpo se TRÊS. A textura tem translação, rotação, escala e, talvez, centro.

Isso é basicamente o que fazemos agora. Cada textura tem sua própria propriedade offset , e os deslocamentos individuais não são respeitados - o renderizador usa o mesmo deslocamento para cada mapa do material.

FWIW, acho que devemos fazer o que disse em https://github.com/mrdoob/three.js/issues/5876#issuecomment -69483293.

Não vejo por que a API não pode permitir o que @jcarpenter deseja fazer (animar o deslocamento de alphaMap , enquanto map permanece o mesmo). Pode-se fazer isso no canvas, mas acho que é uma tarefa para a GPU.

Há uma tonelada de coisas que se poderia fazer brincando com deslocamentos de mapas diferentes ... compensando alphaMap apenas, escalando normalMap , etc.

Ter apenas um uvTransform por material parece muito limitador.

Oh espere. Acho que entendo porque vocês preferem por material. Dessa forma, um único vUv é calculado no sombreador de vértice, em vez de calcular o uv por pixel no sombreador de fragmento. Direito?

por material é ideal porque os deslocamentos são, na verdade, apenas implementados usando um uniforme do material e não têm nada a ver com a textura, então terminamos com uma solução alternativa sem sentido se precisarmos mudar o uniforme por material que está tendo que fazer toneladas de novos objetos / texturas (o que é muito ruim em JS / terrível em WebGL) apenas para controlar algo que é realmente apenas um recurso dos uniformes de material que estão ocultos dos usuários. De forma alguma, fazer parte da textura é vantajoso, mais eficiente, ou mesmo mais claro, e isso significa que a única aplicação real de especificar UVs que mudam em tempo de execução, animação, é renderizada lenta e ineficiente por causa da API.

As texturas devem especificar uma imagem e qualquer coisa relacionada a essa imagem. Os offsets de UV não têm nada a ver com as propriedades da imagem / imagem, e tudo a ver com o material que exibe a textura, é um absurdo ter esse recurso se não fizer parte do material, já que precisa haver toneladas de clonagem acontecendo por exemplo, e atualização de muitas texturas simultaneamente se alguém quiser realmente usar o recurso em muitos casos.

imagine que se tem uma imagem diferente para cada quadro de um ladrilho animado e também deseja controlar o deslocamento / repetição desse ladrilho. Eles teriam que atualizar cada quadro de entrada com os deslocamentos, bem como ter cópias de cada quadro para cada instância única de material usando aquele bloco, rapidamente se transformando em uma bola de neve em centenas de novos objetos e atribuições extras, para algo que na verdade está apenas controlando alguns flutuadores por material nos bastidores, usando todos esses objetos sem um bom motivo.

quanto às transformações por mapa, embora seja bom, o custo uniforme é muito alto sem motivo na maioria dos casos, exceto se tivermos uma API complexa para controlar quando e como as transformações devem ser exclusivas ou compartilhadas ou dinâmicas, IMO ter esse controle seria uma coisa boa, mas teria que ser cuidadosamente pensado.

Oh espere. Acho que entendo porque vocês preferem por material. Dessa forma, um único vUv é calculado no sombreador de vértice, em vez de calcular o uv por pixel no sombreador de fragmento. Direito?

Não. O uv é calculado no sombreador de vértice como sempre.

Imagine uma folha de sprites e 20 sprites. Atualmente, precisamos de 20 materiais clonados e 20 texturas clonadas - exatamente como em http://threejs.org/examples/misc_ubiquity_test2.html. (Aliás, observe que já temos SpriteMaterial.rotation .)

Movendo o deslocamento para o material, precisaríamos de 20 materiais clonados e uma textura.

Na verdade, movendo o offset para o sprite, precisaríamos de 1 material e 1 textura.

Imagine uma folha de sprites e 20 sprites. Atualmente, precisamos de 20 materiais clonados e 20 texturas clonadas

Ohm, eu não estava considerando este caso de uso. Obrigado!

Vou pensar sobre isso ...

Eu não defendo transformações UV na textura.

Por duas razões: (1) é confuso, (2) há mais eventos para propagar e (2) é um desperdício.

Confusão: A razão é que temos apenas uma única variável UV para os mapas principais, mas se houver uma transformação UV em uma das texturas, é confuso que esta transformação UV possa ser aplicada a todos os mapas que usam o primeiro UV canal, se as outras texturas têm uma transformação ou não. Se permitíssemos que cada mapa tivesse sua própria transformação UV no material, ficaria mais satisfeito com a transformação UV associada à textura - mas isso é difícil de fazer devido ao uso uniforme do fragmento.

Mais propagação de eventos: O outro problema que encontrei em Clara.io é a propagação de eventos ao tentar animar parâmetros de textura. Cada textura precisa ser rastreada para cada material que a está usando e, em seguida, informar a esses materiais que eles estão sujos e precisam ser recalculados. Não é impossível fazer isso, apenas mais trabalho.

Perdedor: O outro problema é que se você tiver várias instâncias de um modelo 3D ou despeito e todos eles tiverem a mesma textura animada. Nesse caso, você teria que ter cópias distintas da textura na memória apenas para que fossem animadas de forma diferente - mesmo que os dados da textura em si sejam os mesmos. É um pouco desperdício nesse sentido, em comparação com colocar os dados de transformação UV nos materiais.

Portanto, se tivermos apenas uma Transformação UV permitida por material, eu a colocaria no próprio material. Eu seguiria o modelo Unity 5 onde eles têm um deslocamento UV, rotação no material. Os desenvolvedores de jogos já estão familiarizados com essa abordagem.

Eu acho que sprites são bem controlados por UV Transform nos materiais também - é muito semelhante ao caso do modelo 3D acima.

Having only one uvTransform per material seems very very limiting.

Concordo totalmente aqui. Não ter essa funcionalidade é extremamente limitante. Existem efeitos fantásticos que poderiam ser fornecidos aqui, mas não são, porque todos os deslocamentos estão travados juntos.

Mas como essa funcionalidade pode ser disponibilizada sem engasgar com os clones?

Eu acho que ter os valores no Material ao invés da textura faz sentido para o caso de uso comum onde todas as suas texturas seriam combinadas.

Concordo totalmente aqui. Não ter essa funcionalidade é extremamente limitante. Existem efeitos fantásticos que poderiam ser fornecidos aqui, mas não são, porque todos os deslocamentos estão travados juntos.

Mas como essa funcionalidade pode ser disponibilizada sem engasgar com os clones?

THREE.ShaderMaterial ou THREE.RawShaderMaterial daria a você essa capacidade e, como não funciona atualmente com materiais regulares, esta é a rota que você teria que usar de qualquer maneira.

Se você está fazendo algo mais funky, provavelmente será mais funky do que apenas ajustar as repetições e deslocamentos de mapas de forma independente, então você provavelmente se inclinaria desta forma de qualquer maneira.

1 para isso, pessoal.

Seria muito útil quando você tem uma folha de sprite gigante (também conhecida como atlas) e deseja reutilizar sua textura em várias instâncias de THREE.Sprite .

Alguma novidade sobre isso? Este problema ainda é uma falha gritante na API. A maioria dos tipos de mapa tem deslocamentos / repetições que não são usados, e a propagação de eventos torna algo como um sprite animado em um plano muito mais lento / pesado da memória do que o necessário.

Flexibilidade para mapas animados NÃO EXISTE no sistema atual. O argumento continua surgindo de que estaríamos reduzindo a flexibilidade vinculando as configurações ao material. Este argumento é discutível porque essa flexibilidade não existe no sistema atual. Você só pode definir o deslocamento / repetição globalmente para o material, e é obtido do mapa difuso (?). Isso leva a um problema ainda pior, onde há configurações redundantes de "deslocamento" / "repetição" na maioria dos mapas em uso, e sempre que você quiser compartilhar texturas para animação que não puder, será necessário fazer um clone, portanto a flexibilidade é significativa reduzido. Você espera que cada textura / mapa tenha deslocamentos únicos, mas isso não é possível como as coisas estão, e na maioria dos casos você realmente quer um conjunto de deslocamentos UV porque seria irritante definir os deslocamentos para a mesma coisa para normal / especificação / diffuse (um mapa normal de rolagem sobre um mapa difuso fixo é um nicho de uso onde um material de sombreador pode ser usado).

Se você olhar para os shaders reais sendo construídos, o deslocamento / repetição da textura ESTÁ vinculado ao material, mas estranhamente copiado de um mapa que de forma alguma deveria estar sob controle. O material PRECISA estar sob controle para que seja rápido e elegante sem redundância.

O melhor dos dois mundos é possível com toneladas de sinalizadores extras, mas não acho que seja uma solução melhor do que apenas direcionar os usuários a tentar usar o material de sombreador para esses tipos de casos específicos de borda.

A solução para isso é o NodeMaterial de @sunag btw.

Também adicionando meu +1 para isso! Tornaria o trabalho com folhas de sprite muito mais agradável.

: +1: Achei isso surpreendente. Eu tive que começar a duplicar minhas texturas para cada sprite no jogo, já que todos os meus sprites repetidos estavam se animando uns aos outros. Parece que isso significa que estou carregando dados redundantes de sprite para a GPU?

Alguém tem uma solução alternativa para esse problema? Seria possível manipular o deslocamento de UV definindo diretamente o uniforme no sombreador, ignorando a interface de textura?

A solução para isso é o NodeMaterial de @sunag btw.

@bhouston , poderia fornecer um link? Não há repositório público na conta de @sunag com esse nome.

@ rhys-vdw está localizado aqui apenas no branch dev:

https://github.com/mrdoob/three.js/tree/dev/examples/js/nodes

É novo, então não tenho certeza se ele está pronto para uso em sprites, mas é um sistema de sombreador totalmente baseado em gráfico, portanto, dará a você a flexibilidade de modificar acessos de textura arbitrariamente.

É novo, então não tenho certeza se ele está pronto para uso em sprites, mas é um sistema de sombreador totalmente baseado em gráfico, portanto, dará a você a flexibilidade de modificar acessos de textura arbitrariamente.

@bhouston posso criar um exemplo com o Node, parece bom.

Sobre o THREE.SpriteMaterial você pode acessar o deslocamento / escala para criar o spritesheet com este, por exemplo:

var offsetX = frameX / mapWidth;
var scaleX = mapWidth / frameWidth;

sprite.material.map.offset.x = offsetX;
sprite.material.map.repeat.x = scaleX;

https://github.com/mrdoob/three.js/blob/master/src/renderers/webgl/plugins/SpritePlugin.js#L53

O sistema baseado em nó não é uma correção ... Ele ainda não resolve os problemas com a API. Leva 2 segundos para adicionar deslocamento / repetição ao protótipo do material e fazer o renderizador ler isso em vez da textura. Já fiz isso para o meu projeto, mas o fato continua sendo uma falha óbvia na API que deve ser oficialmente alterada para evitar dores de cabeça para novos usuários que encontrarão esse problema se estiverem tentando fazer algo comum.

... então isso lhe dará a flexibilidade de modificar acessos de textura arbitrariamente.

tbh eu não sei o que isso significa. Para animar uniformes de shader de conjuntos individuais para "deslocamento" e "repetição" por material.

Sobre o THREE.SpriteMaterial você pode acessar deslocamento / escala para criar a spritesheet com isso, por exemplo ...

@sunag , talvez o problema não esteja claro. O código que você compartilhou altera a textura, que é compartilhada por todas as instâncias desse material. Isso significa que é impossível ter dois materiais compartilhando uma textura, mas com deslocamentos únicos - por exemplo, dois sprites inimigos mostrando diferentes quadros de animação.

Já fiz isso para o meu projeto, mas o fato continua sendo uma falha óbvia na API que deve ser oficialmente alterada para evitar dores de cabeça para novos usuários que encontrarão esse problema se estiverem tentando fazer algo comum.

@QuaziKb Existe um PR que eu possa direcionar para o meu projeto?

Embora tudo isso não fosse um problema se, como disse @WestLangley , o seguinte fosse verdade:

Se mantivermos a abordagem atual, uma coisa que precisa ser alterada é que, quando uma textura é clonada, a imagem compartilhada deve ser passada para a GPU apenas uma vez.

Isso está correto?

@sunag , talvez o problema não esteja claro. O código que você compartilhou altera a textura, que é compartilhada por todas as instâncias desse material. Isso significa que é impossível ter dois materiais compartilhando uma textura, mas com deslocamentos únicos - por exemplo, dois sprites inimigos mostrando diferentes quadros de animação.

Hmm, para isso NodeMaterial certamente resolveria, você será capaz de compartilhar a mesma textura com diferentes materiais e deslocamento uv independente e vantagens como filtros personalizados e outras coisas que um material baseado em nó pode oferecer.

https://github.com/mrdoob/three.js/issues/7522

Mas no momento alguém tentou instanciar o uuid assim :?

THREE.Texture.prototype.createInstance = function() {

    var inst = this.clone();

    inst.uuid = this.uuid;
    inst.version = this.version;

    return inst;

}

se você usar needsUpdate atualize todas as instâncias version também.

Exemplo:

var uniqueTextureOffset = map.createInstance();
var material = new THREE.SpriteMaterial( { map: uniqueTextureOffset } );

Mantenha o mesmo uuid e version compartilhará texture na GPU.

https://github.com/mrdoob/three.js/blob/master/src/renderers/WebGLRenderer.js#L2832
https://github.com/mrdoob/three.js/blob/master/src/renderers/webgl/WebGLProperties.js#L11

Embora para mim seja uma solução provisória. Eu acredito em NodeMaterial para o futuro.

Podemos mover as transformações UV para o material?

Que tal o melhor dos dois mundos. Adicione um sinalizador overrideOffsetRepeat no material com um novo uvOffset e uvRepeat no material. Dessa forma, se o sinalizador for falso, é compatível com versões anteriores e esse é o padrão. E se for verdade, ele usa o deslocamento / repetição do material. Eu apoiaria isso, pois parece que a necessidade é intensa e generalizada. @WestLangley? @mrdoob?

(Embora eu realmente suporte o uso de NodeMaterial para tudo que está por vir, mas é uma dor mudar para ele.)

Ainda acho que a solução para isso é criar THREE.Image . https://github.com/mrdoob/three.js/issues/5876#issuecomment -81189892

THREE.Image

@mrdoob , isso significaria que cada Texture atribuído seria clonado junto com um Material ?

@mrdoob escreveu:

Ainda acho que a solução para isso é criar THREE.Image

Sim, isso funcionaria, seria um pouco menos compatível com as versões anteriores (se agora exigirmos que todos criem imagens antes de criar a textura), mas um design geral mais limpo. Talvez seja possível ter uma imagem criada automaticamente por textura se não for especificada separadamente, então isso alcançaria compatibilidade retroativa? E você só precisaria manipular a imagem diretamente se quisesse fazer algo complicado.

Eu acho que esta solução exigiria duas vezes os novos objetos para um conjunto de sprites - uma textura para cada sprite e um material? Onde está a outra abordagem que exigiria apenas um novo Material para cada sprite?

Eu sei que o Unity suporta repetição / deslocamento por material, mas ferramentas VFX de ponta, como 3DS Max, Maya, Softimage não - elas apenas têm um nó de bitmap e um nó de textura (que contém tanto o nó de bitmap quanto um mapeamento UV nod), que é semelhante ao design de

UE4 também é semelhante ao que @mrdoob está propondo, eles têm um nó "Texture" que é um carregador de bitmap, e então eles têm uma série de nós de Mapeamento UV para fazer vários tipos de mapeamentos UV.

As ferramentas avançadas dividem Imagem / Bitmap da Textura e também dividem um nó de mapeamento UV separado, desta forma:

 -> Bitmap
 -> UVMapping

Não permitimos muitas opções de UVMapping no StandardMaterial principal no momento. Mas vários tipos de UVMappings usados ​​em UE4, Maya, Softimage, 3DS Max, seriam qual canal usar, uma transformação para aplicar a ele, para usar Coordenadas Mundiais como a fonte, ou se alguém deveria fazer uma projeção Esférica, Cubo, Planar com base nos parâmetros necessários para essas projeções.

UE4 tem uma textura de sprite que permite a repetição / deslocamento dentro do material:

https://docs.unrealengine.com/latest/INT/Engine/Paper2D/Sprites/index.html

Maya, Softimage, 3DS Max e UE4 têm a separação de Bitmap / Imagem de Textura (e da Geração UV) como @mrdoob sugere, mas todos eles também usam gráficos de sombreamento para fazer isso. O Unity3D, que não possui gráficos de sombreador, é a ferramenta que incorpora o deslocamento / repetição no próprio material, provavelmente porque não pode separá-lo adequadamente em um nó de gráfico de sombreador.

Talvez seja possível ter uma imagem criada automaticamente por textura se não for especificada separadamente, então isso alcançaria compatibilidade retroativa? E você só precisaria manipular a imagem diretamente se quisesse fazer algo complicado.

Exatamente 😊

Provavelmente um pouco fora do lugar para mencionar, mas eu gostaria de recomendar que o PTEX seja incorporado o mais rápido possível.
http://ptex.us/PtexFile.html
Se houver uma maneira de fazer projeções típicas etc cast / converter para um NodeTexture (?) Ou a opção que é um novo sistema de mapeamento de textura de nível de base mais poderoso e abrangente? ... bem, então talvez isso seja algo a considerar com antecedência.
[Ainda no mesmo ponto:]
O conceito com ptex não é realmente uma imagem 2D, mas uma relação UV para que você possa pintar / estampar / projetar em torno de uma superfície complexa sem o conceito / desafio de como traduzir 2d para 3D, o que é matematicamente um hack na melhor das hipóteses ( sempre lutando tecnicamente com a destruição).
Eu apenas aponto que o ptex deveria ter feito mais sentido e ser uma prioridade há mais de 20 anos e não deveria ser considerado uma extensão ou executante de segunda classe, mas realmente para mim é o contrário. Deve ser a velha maneira original de declarar declaradamente como uma imagem 2d é projetada / estampada em um sistema de nível de base verdadeiro e sempre em funcionamento do ptex. De qualquer forma, apenas reforçando a ideia, ela deve ser integrada, se não o melhor, fazer um papel mais central.
Obrigado pela oportunidade de fazer sugestões grandiosas. Fiquei tão feliz que o ptex foi feito de acordo com as especificações. Eu mesma pensei nisso há mais de 10 anos, mas quando criança não tinha o poder de definir novas especificações, etc. Em retrospectiva, deveria ter percebido que talvez pudesse ter tentado fazer a diferença em vez do papel de observador que ainda mantenho. Portanto, aqui está uma tentativa de desfazer um erro antigo.

Talvez alguém possa iniciar um novo thread se alguém com um entendimento mais profundo dos métodos atuais potencialmente no Flux puder fazer uma proposta mais aplicável de como isso funcionaria no THREEjs.
Mais uma vez, obrigado pela oportunidade de ser ouvido.

@MasterJames meio fora do assunto ... crie um novo tópico, por favor?

Mesmo se tivéssemos uma imagem para que a "textura" ainda pudesse ser usada, todos os materiais precisariam ser reescritos, já que eles não suportam mais de um deslocamento / repetição UV. Obviamente, isso pode mudar, mas provavelmente acabaria adicionando complexidade, uma vez que seriam necessários uniformes redundantes (com que frequência você quer mais de um conjunto de deslocamentos / repetições para que, por exemplo, um mapa normal seja deslocado de um difuso), acho que no final para web onde o desempenho é premium, o caso de uso mais comum é aquele em que há um deslocamento / repetição global que afeta todos os mapas, e faz sentido que isso esteja no material, já que acaba sendo parte da arquitetura dos materiais. Materiais de sombreador personalizados podem lidar perfeitamente com casos de borda.

@QuaziKb Yep. Isso é o que NodeMaterial aborda.

Não é o caso que Texture usa a mesma instância de textura OpenGL para cada .clone() , ou estou faltando alguma coisa. É realmente recarregá-lo para cada clone? Se for esse o caso, então este é um problema _muito_ sério.

@evrimoztamur , acredito que copia a textura todas as vezes. Você pode verificar o que está acontecendo usando o WebGL Inspector .

Tentei todas as abordagens que pude pensar, incluindo a solução alternativa de @sunag , mas nada funcionou. Com base na minha experimentação não produzindo resultados, e na discussão acima, eu dei uma olhada em como outras bibliotecas lidam com a animação sprite. Eu descobri que a API Sprite e SpriteManager do Babylon.js é uma solução que atende às minhas necessidades específicas. Ele lida com folhas de sprite, deslocamento e repetição e animações. Talvez este seja um nível mais alto de abstração do que THREE.js pretende fornecer, mas pode valer a pena olhar como referência.

@ rhys-vdw: Para um projeto atual, acabei com uma versão bastardizada de MeshBasicMaterial:
https://gist.github.com/karimbeyrouti/790d2e1a8c0137b16bae

Quando você define o Mapa, isso atribui automaticamente os uniformes de deslocamento / repetição (que estão em material escondido). Você pode facilmente configurá-los separadamente - isso vai evitar que você precise clonar texturas por enquanto. (trabalhando com r73)

Acabei de enviar um PR que deve abordar esse problema, PR # 8278

@WestLangley escreveu:

Acredito que seja razoável supor que os seguintes mapas tenham os mesmos valores de deslocamento / repetição:

mapa
specularMap
normalMap
mapa de relevo
alphaMap
aoMap (futuro)
glossMap (futuro)
displacementMap (futuro)

Nem sempre. Atualmente, estou usando diferentes valores de repetição para um mapa e um mapa de relevo no mesmo material (asfalto) para esconder o fato de que ambos são ladrilhados com ladrilhos bastante pequenos. Dessa forma, não preciso gerar / ter uma textura grande. É muito conveniente. :-)

EDIT: Bem, isso é pelo menos o que eu pensei que tinha feito. O truque provavelmente foi ignorado. E posso obter resultados semelhantes adicionando ruído no shader ou algo assim. A demo do Matrix3 do WestLangley é legal.

Acho que isso resolve o problema de instâncias com diferentes UV no Sprite. É possível modificar o vertex e pixel shader preservando a mesma textura.

https://threejs.org/examples/#webgl_sprites_nodes

Ele usa SpriteNodeMaterial e Mesh com um PlaneBufferGeometry compartilhado. A interface não é apropriada para Sprite mas funciona. Talvez ele possa evoluir para SpriteMesh para tornar uma interface mais amigável

este tópico é TL; DR para mim. mas acabei de descobrir este código em r68 (projeto antigo, sim):

        // uv repeat and offset setting priorities
        //  1. color map
        //  2. specular map
        //  3. normal map
        //  4. bump map
        //  5. alpha map

        var uvScaleMap;

        if ( material.map ) {

            uvScaleMap = material.map;

        } else if ( material.specularMap ) {

            uvScaleMap = material.specularMap;

        } else if ( material.normalMap ) {

            uvScaleMap = material.normalMap;

        } else if ( material.bumpMap ) {

            uvScaleMap = material.bumpMap;

        } else if ( material.alphaMap ) {

            uvScaleMap = material.alphaMap;

        }

        if ( uvScaleMap !== undefined ) {

            var offset = uvScaleMap.offset;
            var repeat = uvScaleMap.repeat;

            uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );

        }

então sim...

se você vai propor uma mudança fundamental para a biblioteca, como a que você propôs aqui, você deve fornecer um argumento claro e convincente para essa mudança

Eu estava tentando definir uma repetição diferente em mapas difusos e normais e puxando meu cabelo porque não funcionou. como a API coloca essa configuração na textura, pensei que poderia fazer isso. então, sim, que tal guardar meu cabelo para uma discussão convincente? este tíquete ainda está aberto, 3js ainda tem essa configuração nas texturas, e só é respeitado para uma das texturas = esta é, na verdade, já é configuração permaterial.

Se você não vai mover isso para onde ele pertence, pelo menos diga que não tem efeito nos documentos.

@sunag Para RP:
https://github.com/mrdoob/three.js/pull/11531

Um problema que encontrei:
https://jsfiddle.net/f0j2v3s8/

Parece que SpriteNodeMaterial transparência foi perdida, não há combinação de mistura que eu possa usar para fazer este exemplo funcionar.

Alguma ideia?

@karimbeyrouti escreveu:

Quando você define o Mapa, isso atribui automaticamente os uniformes de deslocamento / repetição (que estão em material escondido). Você pode facilmente configurá-los separadamente - isso vai evitar que você precise clonar texturas por enquanto. (trabalhando com r73)

Acredito que isso seja obsoleto, pois uniforms.offsetRepeat foi alterado para uniforms.uvTransform (r88).

Em relação ao caso de uso 'reutilizar um atlas de textura com várias instâncias de Object3D', sugiro um passeio simples:

  1. armazenar os dados UVs (deslocamento, repetição) em um objeto atlas json;
  2. enganchar o par de funções onBeforeRender\onAfterRender de Object3D;
  3. no retorno de chamada antes da renderização, carregue os dados UVs do objeto atlas json e defina como material.map;
  4. no retorno de chamada após a renderização, redefina-o de volta;

Isso resultará em:

  1. apenas uma textura e um material compartilhados por vários objetos, nenhum clone é necessário e o contador info.memory.textures não aumentará;
  2. mas ainda todos os outros mapas (normal, ao, deslocamento ...) devem obedecer à mesma tradução UV;
Esta página foi útil?
0 / 5 - 0 avaliações