EDIT: Por favor, veja minha outra resposta com uma solução concreta.
Na verdade, eu resolvi esse problema exato há mais de um ano para a minha tese de mestrado. No artigo da Valve, eles mostram que você pode AND dois campos de distância para conseguir isso, o que funciona desde que você tenha apenas um canto convexo. Para cantos côncavos, você também precisa da operação OR. Esse cara realmente desenvolveu um sistema obscuro para alternar entre as duas operações usando quatro canais de textura.
No entanto, há uma operação muito mais simples que pode facilitar tanto AND quanto OR, dependendo da situação, e esta é a principal idéia da minha tese: a mediana de três . Então, basicamente, você usa exatamente três canais (ideais para RGB), que são completamente intercambiáveis, e os combina usando a operação mediana (escolha o valor do meio dos três).
Para acomodar a suavização de serrilhado, não trabalhamos apenas com booleanos, mas com valores de ponto flutuante, e a operação AND se torna o mínimo, e o OR se torna o máximo de dois valores. A mediana de três pode de fato fazer as duas coisas: se a < b , para ( a , a , b ), a mediana é o mínimo e, para ( a , b , b ), é o máximo.
O processo de renderização ainda é extremamente simples. Todo o shader de fragmento, incluindo anti-aliasing, pode se parecer com isso:
int main() {
// Bilinear sampling of the distance field
vec3 s = texture2D(sdf, p).rgb;
// Acquire the signed distance
float d = median(s.r, s.g, s.b) - 0.5;
// Weight between inside and outside (anti-aliasing)
float w = clamp(d/fwidth(d) + 0.5, 0.0, 1.0);
// Combining the background and foreground color
gl_FragColor = mix(outsideColor, insideColor, w);
}
Portanto, a única diferença do método original é calcular a mediana logo após a amostragem da textura. Você precisará implementar a função mediana, o que pode ser feito com apenas 4 min / max de operações .
Agora, é claro, a questão é: como faço para construir um campo de distância de três canais?E esta é a parte complicada. A abordagem mais óbvia que tomei no início foi realizar uma decomposição da forma / glifo de entrada em três componentes e, em seguida, gerar um campo de distância convencional de cada um. As regras para essa decomposição não são tão complicadas. Em primeiro lugar, a área com pelo menos 2 dos 3 canais é interna. Então, se você imaginar isso como os canais de cores RGB, os cantos convexos deverão ser feitos de uma cor secundária e seus dois componentes principais continuarão para fora. Os cantos côncavos são o inverso: duas cores secundárias incluem sua cor primária comum, e a cunha entre o local em que as duas bordas continuam para dentro é branca. Também descobri que é necessário algum preenchimento onde duas cores primárias ou duas cores secundárias tocariam para evitar artefatos (por exemplo, no traçado do meio do "N"
A imagem a seguir é um exemplo de decomposição gerada pelo programa da minha tese:
Essa abordagem, no entanto, tem algumas desvantagens. Uma delas é que os efeitos especiais, como contornos e sombras, não funcionarão mais corretamente. Felizmente, eu também criei um segundo método, muito mais elegante, que gera diretamente os campos de distância e até suporta todos os efeitos gráficos. Também está incluído na minha tese e também tem mais de um ano de idade. Não vou dar mais detalhes agora, porque atualmente estou escrevendo um artigo que descreve essa segunda técnica em detalhes, mas vou publicá-la aqui assim que terminar.
Enfim, aqui está um exemplo da diferença de qualidade. A resolução da textura é a mesma em cada imagem, mas a esquerda usa uma textura regular, a do meio usa um campo de distância comum e a direita usa o meu campo de distância de três canais. A sobrecarga de desempenho é apenas a diferença entre a amostragem de uma textura RGB e uma monocromática.