Cantos afiados com fontes de campos de distância assinados

49

Os campos de distâncias assinadas (SDFs) foram apresentados como uma solução rápida para obter renderização de fonte independente de resolução pela Valve neste documento .

Eu já tenho a solução Valve funcionando, mas gostaria de preservar a nitidez nos cantos. A Válvula afirma que seu método pode obter ângulos agudos usando um segundo canal de textura ANDed com o canal base, mas falta explicar como esse segundo canal seria gerado.

De fato, existem muitos detalhes de implementação deixados de fora deste documento.

Gostaria de saber se algum de vocês poderia me indicar uma direção para obter a renderização da fonte SDFs com cantos afiados.

Felipe Lira
fonte
De fato, Adam já postou o código fonte no shadertoy. Aqui está o link: shadertoy.com/view/ltXSDB
Felipe Lira
Você me excitou. Ele publicou o material mais bezier no shadertoy, mas não o material do campo de distância da textura!
21415 Alan Wolfe
@AlanWolfe Acho que ele fez apenas para definir curvas bezier processualmente. Não tenho certeza do esforço necessário para integrar isso em um arquivo ttf render lib. Quando tiver algum tempo, vou dar uma olhada.
Felipe Lira
parece que ele tem um pouco de molho mágico ao lado de realmente armazenar e recuperar as distâncias de uma textura. Sem uma textura em jogo, os exemplos shadertoy estão faltando essa parte da equação.
27715 Alan Wolfe
Tarde demais para a festa, mas esse tópico mais antigo do reddit tem muitas informações sobre vários métodos para melhorar a nitidez da renderização baseada em SDF: reddit.com/r/gamedev/comments/2879jd/…
Necrolis

Respostas:

7

Adam Simmons fez um trabalho interessante nessa área. Não sei especificamente como ele está conseguindo isso, mas sua renderização vetorial baseada em SDF é a mais nítida que já vi na prática fora da Valve. http://twitter.com/adamjsimmons/status/611677036545863680

warrenm
fonte
É claro que não tenho todos os detalhes, mas parece-me que essa pessoa simplesmente usou um campo de pseudo-distância em vez de um campo regular, o que já foi demonstrado em um artigo de 2006 por Qin, McCool e Kaplan ". Glifos vetoriais mapeados em textura em tempo real ", também referenciados no documento Valve. Afeta apenas as atenuações dos contornos e não faz nada para melhorar a aparência dos cantos. Suspeito que o motivo seja nítido, porque ele usa texturas de campo de distância praticamente grande. Eu posso estar errado embora.
Detheroc 7/03/16
69

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:

Decomposição multicanal de glifos

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.

insira a descrição da imagem aqui

Detheroc
fonte
5
Ótima primeira resposta, bem-vindo ao Computer Graphics SE! :) Sua tese está disponível ao público? (Ou será depois que você terminar o trabalho?) Nesse caso, provavelmente seria muito útil vincular-se a isso também.
Martin Ender
Ele deveria estar disponível ao público, mas parece que a escola ainda não o colocou. De qualquer forma, eu preferiria não divulgá-lo agora, já que o artigo que estou escrevendo realmente explica muito melhor as partes importantes e se concentra em como implementá-lo, e deve ser concluído em breve.
Detheroc 7/03/16
@Detheroc Notifique aqui e no gamedev Q quando terminar o artigo. A explicação ainda não está 100% clara para mim. Eu sugeriria mostrar a composição passo a passo nas imagens.
Engineer
11
gostaria de poder replicar seus resultados atuais, mesmo que não sejam tão bons quanto seus resultados futuros, +1 para compartilhar os detalhes que puder. muito exitante. Você já considerou a aplicação de qualquer uma das técnicas para marchar com raios (rastreamento de esferas)? Em texturas de volume ou similar ...
Alan Wolfe
4
A tese está disponível publicamente aqui: dspace.cvut.cz/bitstream/handle/10467/62770/…
Romain Guy
43

Desculpe a longa espera, mas ficou óbvio que, embora o artigo que prometi esteja basicamente completo, o processo de publicação levará algum tempo. Portanto, preparei um programa de código aberto com o meu novo algoritmo de construção de campo à distância multicanal, msdfgen , que você pode experimentar agora.

Está disponível no GitHub: https://github.com/Chlumsky/msdfgen

(Eu sou novo nisso, por favor, deixe-me saber se há algo errado com o repositório.)

Alguém também perguntou sobre como ele se compara a um campo de distância monocromático maior, então aqui está um teaser da diferença de qualidade. No entanto, isso realmente depende da fonte específica, e eu não diria que vale sempre a pena os dados extras.

Campo de distância multicanal 16x16 Campo de distância monocromático 32x32

Detheroc
fonte
3

Muito interessante! Sou o autor do papel distanciado com válvula. Lamentamos que seja um pouco escasso nos detalhes da implementação. Eu incluí apenas o exemplo de dois canais como trabalho futuro - eu não tinha um gerador. Imaginei algo como gerar um sdf de alta resolução e, em seguida, segmentar com base no ângulo do gradiente do sdf seria uma tática razoável. Mas nunca cheguei a isso. Qualquer esquema multicanal deve ser ponderado com o uso de dados de canal único de alta resolução com o mesmo espaço de memória, para as proporções de ampliação que seu aplicativo precisa.

chris green
fonte
0

Eu não sou um especialista no assunto, mas você pode, pelo menos em teoria, preservar cantos afiados em um pseudo-SDF monocromático se você usou um filtro Bilateral, um filtro Bicúbico Direcional em vez de um filtro Bilinear padrão. Além do benefício óbvio de economizar memória, você também pode ter vários canais para adesivos SDF multicoloridos.

Como alternativa, se você não se importa em usar um segundo canal, também pode tentar ter um canal para Distância Horizontal e outro para Distância Vertical e usar uma pirâmide de energia Diferença de Laplacean (DoL) para comprimir a textura para que informações redundantes não ocorram. ser gravado.

Uma terceira e última solução teórica seria experimentar uma Textura Amostrada Hexagonal via Endereçamento de Conjunto de Matrizes.

Infelizmente, atualmente não tenho como testar minhas idéias e não consegui encontrar nenhum documento descrevendo ou testando algo semelhante às minhas idéias. Vou ligar todos os artigos relevantes onde obtive minhas informações / idéias em breve.

Amaroq Starwind
fonte