Texturas de folhas de sprite captando bordas da textura adjacente


10

Eu tenho uma rotina de sprite personalizada (openGL 2.0) que usa uma planilha de sprite simples (minhas texturas são organizadas horizontalmente uma ao lado da outra).

Então, por exemplo, aqui está uma planilha de teste com 2 texturas simples:

insira a descrição da imagem aqui

Agora, o que faço ao criar meu objeto sprite openGL é especificar o número total de quadros em seu atlas e, ao desenhar, especificar qual quadro eu quero desenhar.

Em seguida, ele decide de onde pegar a textura:

Dividir o número de quadros exigido pelo número total de quadros (para obter a coordenada esquerda)

E depois mergulhe 1 pelo número total de quadros e adicione o resultado à coordenada esquerda calculada acima.

Isso parece funcionar, mas às vezes eu tenho problemas. Digamos, por exemplo, eu quero desenhar o X abaixo e recebo ...........

insira a descrição da imagem aqui

Já ouvi falar em colocar um 'preenchimento' de 1 px entre cada textura, mas alguém poderia explicar exatamente como isso funciona? Quero dizer, se eu fizer isso, certamente descartará os cálculos para obter a textura.

Se eu simplesmente incluir o preenchimento na textura coletada (para que o sprite seja desenhado com uma borda em branco), certamente isso causará problemas na detecção de colisão? (ou seja, sprites podem parecer colidir ao usar caixas delimitadoras quando as partes transparentes colidem).

Gostaria que alguém pudesse explicar.


Você está usando GL_NEARESTou GL_LINEARpara renderizar a textura?
MichaelHouse

Estou usando GL_Linear @ Byte56
BungleBonce 5/13

Respostas:


15

O problema com o uso de atlas de textura e vazamentos de texels adjacentes tem a ver com a maneira como a filtragem linear de textura funciona.

Para qualquer ponto da textura que não seja amostrado exatamente no centro de um texel, a amostragem linear amostrará 4 texels adjacentes e calculará o valor no local que você pediu como a média ponderada (com base na distância do ponto de amostra) de todas as 4 amostras.

Aqui está uma boa visualização do problema:

  

Como você não pode usar algo como GL_CLAMP_TO_EDGEem um atlas de textura, é necessário criar texels de borda em torno da borda de cada textura. Esses texels de borda impedirão que amostras vizinhas de texturas completamente diferentes no atlas alterem a imagem através da interpolação ponderada explicada acima.

Observe que quando você usa filtragem anisotrópica, pode ser necessário aumentar a largura da borda. Isso ocorre porque a filtragem anisotrópica aumentará o tamanho da vizinhança da amostra em ângulos extremos.


Para ilustrar o que quero dizer usando uma borda em torno da borda de cada textura, considere os vários modos de quebra disponíveis no OpenGL. Preste atenção especial CLAMP TO EDGE.

  http://lucera-project.com/blog/wp-content/uploads/2010/06/wrap.png

Apesar de haver um modo chamado "Fixar na borda", não é exatamente isso que interessa. Esse modo permite definir uma única cor para ser usada como uma borda em torno de sua textura para qualquer coordenada de textura que esteja fora da normalizada [0,0 -1,0].

O que queremos é replicar o comportamento de CLAMP_TO_EDGE, onde qualquer coordenada de textura fora do intervalo apropriado para a (sub) textura recebe o valor do último centro texel na direção em que estava fora dos limites. Como você tem controle quase completo sobre as coordenadas da textura em um sistema de atlas, o único cenário no qual as coordenadas (eficazes) da textura podem se referir a um local fora da textura é durante a etapa média ponderada da filtragem da textura.

Sabemos que GL_LINEARirá amostrar os 4 vizinhos mais próximos, como visto no diagrama acima, portanto, precisamos apenas de uma borda de 1 texel. Você pode precisar de uma borda texel mais ampla se usar a filtragem anisotrópica, porque aumenta o tamanho da vizinhança da amostra sob certas condições.

Aqui está um exemplo de textura que ilustra a borda com mais clareza, embora para seus propósitos você possa fazer a borda com 1 texel ou 2 texels de largura.

  

(OBSERVAÇÃO: A borda à qual me refiro não é o preto ao redor das quatro bordas da imagem, mas a área em que o padrão quadriculado para de se repetir regularmente)

Caso você esteja se perguntando, aqui está o porquê de eu continuar exibindo a filtragem anisotrópica. Ele altera a forma da vizinhança da amostra com base no ângulo e pode fazer com que mais de 4 texels sejam usados ​​para filtragem:

  http://www.arcsynthesis.org/gltut/Texturing/ParallelogramDiag.svg

Quanto maior o grau de anisotropia usado, maior será a probabilidade de lidar com bairros de amostras que contêm mais de 4 texels. Uma borda 2 texel deve ser adequada para a maioria das situações de filtragem anisotrópica.


Por último, mas não menos importante, eis como um atlas de textura compactado seria construído que replicaria o GL_CLAMP_TO_EDGEcomportamento na presença de um GL_LINEARfiltro de textura:

( Subtraia 1 de X e Y nas coordenadas em preto, não testei a leitura da imagem antes de postar. )   

Devido ao armazenamento de borda, o armazenamento de 4 texturas de 256x256 neste atlas requer uma textura com as dimensões 516x516. As bordas são codificadas por cores com base em como você as preencheria com dados texel durante a criação do atlas:

  • Vermelho = Substitua por texel diretamente abaixo
  • Amarelo = Substitua por texel diretamente acima
  • Verde = Substitua por texel diretamente à esquerda
  • Azul = Substitua por texel diretamente à direita

Efetivamente neste exemplo compactado, cada textura no atlas usa uma região de 258x258, mas você irá gerar coordenadas de textura que são mapeadas para a região visível de 256x256. Os tecidos limítrofes são usados ​​apenas quando a filtragem de textura é feita nas bordas das texturas no atlas, e a maneira como elas são projetadas imita o GL_CLAMP_TO_EDGEcomportamento.

Caso você esteja se perguntando, é possível implementar outros tipos de modos de quebra automática usando uma abordagem semelhante - GL_REPEATpode ser implementado trocando os texels de borda esquerda / direita e superior / inferior no atlas de textura e um pouco de matemática de coordenadas de textura inteligente em um shader. Isso é um pouco mais complicado, então não se preocupe com isso por enquanto. Como você está lidando apenas com folhas de sprite, limite-se a GL_CLAMP_TO_EDGE:)


Obrigado @AndonMColeman, você poderia mostrar a borda em um diagrama, pois ainda não tenho certeza de que entendi como isso funciona? Novamente significa que quando a textura é aplicada ao meu objeto, ela inclui a borda? Eu quero a textura real para ir direto para as bordas do meu quad - desculpe se eu não estou entendendo isso corretamente - gostaria de receber mais alguns detalhes - graças
BungleBonce

@ user22241 Certamente, o modo como essa borda funciona é duplicando o texel na borda da textura.
Andon M. Coleman

@ user22241: Não, essa borda não será visível em circunstâncias normais. Você tratará suas texturas compactadas como tendo as mesmas dimensões para o cálculo das coordenadas de textura, basta aplicar um deslocamento a elas para pular a borda. O ponto principal da borda é impedir que a amostragem linear de texturas alcance demais e amostragem texels que pertencem a imagens separadas em sua planilha de sprites. Se você usar a amostragem do vizinho mais próximo, nada disso será necessário, mas você obterá sprites desagradáveis.
Andon M. Coleman

Resposta brilhantemente detalhada - obrigado! Apenas uma última coisa, se eu pudesse. Como elaboraria o 'deslocamento' para adicionar às minhas coordenadas de textura? Estou certo ao dizer que seria simplesmente 1 / widthOfTexture?
BungleBonce 6/09

@ user22241: Sim, o início da imagem da textura seria + 1 / widthOfTexture na direção X e + 1 / heightOfTexture na direção Y. Você terá uma borda que contorna toda a textura. No momento em que você deseja calcular as coordenadas da textura para a terceira textura horizontal, o local compactado para essa textura é na verdade +5 texels (+2 texels para a borda da primeira textura, +2 para a borda da segunda textura e +1 para o início desta textura) além da largura das outras 2 texturas. Parece complicado apenas escrever; Eu posso chamar-lhe um diagrama de caso de necessidade :)
Andon M. Coleman
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.