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:
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 ...........
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.
fonte
GL_NEAREST
ouGL_LINEAR
para renderizar a textura?Respostas:
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_EDGE
em 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
.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_LINEAR
irá 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_EDGE
comportamento na presença de umGL_LINEAR
filtro 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:
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_EDGE
comportamento.Caso você esteja se perguntando, é possível implementar outros tipos de modos de quebra automática usando uma abordagem semelhante -
GL_REPEAT
pode 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 aGL_CLAMP_TO_EDGE
:)fonte