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 um GL_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:
- 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_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 a GL_CLAMP_TO_EDGE
:)
GL_NEAREST
ouGL_LINEAR
para renderizar a textura?