
Neste artigo, explicarei um algoritmo de splatting de textura que permite criar terrenos mais naturais. Este algoritmo pode ser usado em sombreadores de jogos em 3D e em jogos em 2D.
Uma das maneiras mais comuns de texturizar o terreno é misturar várias camadas lado a lado. Cada camada possui um mapa de opacidade que define a extensão da presença de textura no terreno. O método funciona aplicando um mapa de opacidade aos níveis mais altos, revelando as camadas abaixo de onde o mapa de opacidade é parcial ou completamente transparente. O mapa de opacidade é medido em porcentagem. Obviamente, em cada ponto de um terreno, a soma das opacidades de todas as camadas é cem por cento, pois o terreno não pode ser transparente. Em vez de texturas de ladrilhos, o mapa de opacidade se estende inteiramente em todo o terreno e, portanto, possui um nível de detalhe bastante baixo.
Agora passaremos à parte mais interessante - algoritmos de mistura de texturas. Por simplicidade e obviedade, nosso terreno será composto de areia e grandes pedras de calçada.

A maneira mais simples de mesclar é multiplicar a cor da textura pela opacidade e somar os resultados.
float3 blend(float4 texture1, float a1, float4 texture2, float a2) { return texture1.rgb * a1 + texture2.rgb * a2; }
Essa técnica é usada no Unity3D no editor de terreno padrão. Como você pode ver, a transição é suave, mas não natural. As pedras parecem uniformemente sujas pela areia, mas no mundo real isso não acontece assim. A areia não gruda nas pedras, mas cai e preenche fendas entre elas, deixando o topo das pedras puro.
Vamos tentar simular esse comportamento nos gráficos do Excel. Como queremos que a areia seja "caída" entre pedras de calçada, para cada textura precisamos do mapa de profundidade. Neste exemplo, consideramos que o mapa de profundidade é gerado a partir da imagem em escala de cinza e armazenado no canal alfa de uma textura. No Unity3D, isso pode ser feito no inspetor de textura, definindo a bandeira "Alpha From Grayscale".
Primeiro, consideraremos o modelo simplificado do mapa de profundidade de areia e pedras.

A linha azul na trama simboliza o mapa de profundidade da areia e o vermelho são pedras de calçada. Observe que os topos das pedras estão acima do nível da areia. Considerando esse fato, tentaremos desenhar pixels dessa textura que está acima.
float3 blend(float4 texture1, float a1, float4 texture2, float a2) { return texture1.a > texture2.a ? texture1.rgb : texture2.rgb; }

Excelente! Os topos de pedras de calçada permanecem puras, enquanto a areia está entre as rachaduras. Mas ainda não consideramos a opacidade da camada. Para usá-lo, basta somar o mapa de profundidade e o mapa de opacidade.
float3 blend(float4 texture1, float a1, float4 texture2, float a2) { return texture1.a + a1 > texture2.a + a2 ? texture1.rgb : texture2.rgb; }
À custa do somatório, a textura menos transparente será maior que o normal.


Portanto, temos uma transição mais natural da areia para as pedras. Como você pode ver, grãos de areia começam a encher rachaduras entre pedras de calçada, escondendo-as gradualmente. Porém, à medida que os cálculos acontecem pixel por pixel, os artefatos começam a aparecer na borda entre as texturas. Para obter um resultado suave, usaremos vários pixels de profundidade em vez de um e os misturaremos.
float3 blend(float4 texture1, float a1, float4 texture2, float a2) { float depth = 0.2; float ma = max(texture1.a + a1, texture2.a + a2) - depth; float b1 = max(texture1.a + a1 - ma, 0); float b2 = max(texture2.a + a2 - ma, 0); return (texture1.rgb * b1 + texture2.rgb * b2) / (b1 + b2); }
No código acima, primeiro obtemos parte de um terreno visto a uma certa profundidade.

E então normalizamos para obter novas opacidades.


Como resultado, encontramos o algoritmo de mistura de texturas, que nos permite chegar perto de uma imagem de terreno natural.