Spigoli vivi con caratteri di campi di distanza firmati


49

In questo documento è stato presentato Signed Distance Fields (SDFs) come soluzione rapida per ottenere il rendering dei font indipendente dalla risoluzione da Valve .

Ho già la soluzione Valve funzionante ma vorrei preservare la nitidezza dietro gli angoli. Valve afferma che il loro metodo può ottenere spigoli vivi usando un secondo canale di trama ANDed con quello di base, ma manca di spiegare come questo secondo canale verrebbe generato.

In realtà, ci sono molti dettagli di implementazione lasciati fuori da questo documento.

Vorrei sapere se qualcuno di voi potrebbe indicarmi una direzione per ottenere il rendering dei caratteri SDF con spigoli vivi.


In effetti Adam ha già pubblicato il codice sorgente su shadertoy. Ecco il link: shadertoy.com/view/ltXSDB
Felipe Lira

Mi hai fatto eccitare. Ha pubblicato le cose più bezier su shadertoy ma non quelle sul campo della distanza delle trame!
Alan Wolfe,

@AlanWolfe Penso che abbia fatto solo per impostare proceduralmente curve di Bezier. Non sono sicuro dello sforzo richiesto per integrare questo in una libreria di rendering ttf. Quando avrò del tempo lo darò un'occhiata.
Felipe Lira,

sembra che abbia un po 'di salsa magica sul lato della memorizzazione e del recupero delle distanze da una trama. Senza una trama in gioco, agli esempi di shadertoy manca quella parte dell'equazione.
Alan Wolfe,

Un po 'tardi alla festa, ma questo vecchio thread di reddit ha un sacco di informazioni su vari metodi per migliorare la nitidezza del rendering basato su SDF: reddit.com/r/gamedev/comments/2879jd/…
Necrolis,

Risposte:


7

Adam Simmons ha svolto un lavoro interessante in questo settore. Non so esattamente come lo stia raggiungendo, ma il suo rendering vettoriale basato su SDF è il più nitido che abbia mai visto in pratica al di fuori di Valve. http://twitter.com/adamjsimmons/status/611677036545863680


Ovviamente non ho tutti i dettagli, ma mi sembra che questa persona abbia semplicemente usato un campo pseudo-distanza al posto di un campo normale, che è già stato dimostrato in un articolo del 2006 di Qin, McCool e Kaplan, " Glifi vettoriali con mappatura di texture in tempo reale ", a cui fa riferimento anche il documento Valve. Colpisce solo gli attenuatori dei contorni e non fa nulla per migliorare l'aspetto degli angoli. Ho il sospetto che il motivo per cui sembra nitido è perché usa trame di campi a distanza poco pratiche. Potrei sbagliarmi però.
Detheroc

69

EDIT: Vedi la mia altra risposta con una soluzione concreta.

In realtà ho risolto esattamente questo problema più di un anno fa per la tesi del mio maestro. Nel documento Valve, mostrano che puoi E due campi di distanza per raggiungere questo obiettivo, che funziona fintanto che hai solo un angolo convesso. Per gli angoli concavi, è necessaria anche l'operazione OR. Questo ragazzo in realtà ha sviluppato un sistema oscuro per passare tra le due operazioni usando quattro canali di trama.

Tuttavia, esiste un'operazione molto più semplice che può facilitare sia AND che OR a seconda della situazione, e questa è l'idea principale della mia tesi: la mediana di tre . Quindi, fondamentalmente, usi esattamente tre canali (ideali per RGB), che sono completamente intercambiabili, e combinali usando l'operazione mediana (scegli il valore medio tra i tre).

Per soddisfare l'antialiasing, non lavoriamo solo con valori booleani, ma a virgola mobile e l'operazione AND diventa il minimo e OR diventa il massimo di due valori. La mediana di tre può effettivamente fare entrambe le cose: se a < b , per ( a , a , b ), la mediana è il minimo e per ( a , b , b ), è il massimo.

Il processo di rendering è ancora estremamente semplice. L'intero shader di frammenti, incluso l'antialiasing, può assomigliare a questo:

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);
}

Quindi l'unica differenza rispetto al metodo originale è calcolare la mediana subito dopo aver campionato la trama. Dovrai tuttavia implementare la funzione mediana, che può essere eseguita con solo 4 min / max operazioni .

Ora, naturalmente, la domanda è: come posso costruire un campo di distanza così a tre canali?E questa è la parte difficile. L'approccio più ovvio che ho adottato all'inizio è stato quello di eseguire una decomposizione della forma / glifo di input in tre componenti e quindi generare un campo di distanza convenzionale da ciascuno di essi. Le regole per questa scomposizione non sono così complicate. Innanzitutto, l'area con almeno 2 canali su 3 attivi è l'interno. Quindi, se lo immagini come canali di colore RGB, gli angoli convessi devono essere fatti di un colore secondario e i suoi due componenti primari continuano verso l'esterno. Gli angoli concavi sono l'inverso: due colori secondari racchiudono il loro colore primario comune e il cuneo tra il punto in cui entrambi i bordi continuano verso l'interno è bianco. Ho anche scoperto che è necessaria una certa imbottitura in cui due colori primari o due secondari toccherebbero altrimenti per evitare artefatti (ad esempio, nel tratto centrale della "N"

L'immagine seguente è un esempio di scomposizione generata dal programma dalla mia tesi:

Decomposizione multicanale di glifi

Questo approccio presenta tuttavia alcuni inconvenienti. Uno di questi è che gli effetti speciali, come i contorni e le ombre, non funzioneranno più correttamente. Fortunatamente, ho anche escogitato un secondo metodo molto più elegante, che genera direttamente i campi di distanza e supporta persino tutti gli effetti grafici. È anche incluso nella mia tesi e quindi ha anche più di un anno. Non fornirò ulteriori dettagli in questo momento, perché attualmente sto scrivendo un documento che descrive in dettaglio questa seconda tecnica, ma la posterò non appena sarà finita.

Ad ogni modo, ecco un esempio della differenza di qualità. La risoluzione della trama è la stessa in ogni immagine, ma quella sinistra usa una trama normale, quella centrale usa un campo di distanza ordinario e quella destra usa il mio campo di distanza a tre canali. L'overhead delle prestazioni è solo la differenza tra il campionamento di una trama RGB rispetto a una monocromatica.

inserisci qui la descrizione dell'immagine


5
Ottima prima risposta, benvenuta su Computer Graphics SE! :) La tua tesi è disponibile al pubblico? (O sarà dopo che avrai finito di dire questo documento?) In tal caso, sarebbe probabilmente molto utile collegarti anche a quello.
Martin Ender,

Dovrebbe essere disponibile pubblicamente, ma sembra che la scuola non l'abbia ancora messo in piedi. Ad ogni modo, preferirei non diffonderlo in questo momento, poiché l'articolo che sto scrivendo spiegherà molto meglio le parti importanti e si concentrerà su come implementarlo, e dovrebbe essere completato molto presto.
Detheroc

@Detheroc Si ​​prega di avvisare qui e sul Gamedev Q quando hai finito con l'articolo. La spiegazione non è ancora chiara al 100% per me. Suggerirei di mostrare la composizione passo dopo passo nelle immagini.
Ingegnere

1
mi piacerebbe poter replicare i tuoi risultati attuali anche se non sono buoni come i tuoi risultati futuri, +1 per condividere tutti i dettagli che puoi. molto eccitante. Hai preso in considerazione l'applicazione di entrambe le tecniche alla marcatura dei raggi (tracciatura delle sfere)? Trame di volume o simili ...
Alan Wolfe

4
La tesi è disponibile al pubblico qui: dspace.cvut.cz/bitstream/handle/10467/62770/…
Romain Guy

43

Ci scusiamo per la lunga attesa, ma è diventato ovvio che sebbene l'articolo che ho promesso sia sostanzialmente completo, il processo di pubblicazione richiederà del tempo. Pertanto, ho invece preparato un programma open source con il mio nuovo algoritmo di costruzione di campi a distanza multicanale, msdfgen , che puoi provare subito.

È disponibile su GitHub: https://github.com/Chlumsky/msdfgen

(Sono nuovo a questo, quindi per favore fatemi sapere se c'è qualcosa di sbagliato nel repository.)

Qualcuno ha anche chiesto come si confronta con un campo di distanza monocromatico più grande, quindi ecco un teaser della differenza di qualità. Tuttavia, dipende davvero dal tipo di carattere particolare, e non direi che valga sempre la pena aggiungere altri dati.

Campo di distanza multicanale 16x16 Campo distanza monocromatico 32x32


3

Abbastanza interessante! Sono l'autore del documento sulla distanza firmato dalla valvola. Mi dispiace che sia un po 'scarso sui dettagli di implementazione. Ho incluso solo l'esempio dei due canali come lavoro futuro: non avevo un generatore. Ho immaginato qualcosa come generare un sdf ad alta risoluzione e quindi segmentare in base all'angolo del gradiente del sdf sarebbe una tattica ragionevole. Ma non ci siamo mai riusciti. Qualsiasi schema multicanale deve essere valutato rispetto all'utilizzo di dati a canale singolo ad alta risoluzione con lo stesso footprint di memoria, per i rapporti di ingrandimento richiesti dall'app.


0

Non sono affatto un esperto in materia, ma potresti essere in grado, almeno in teoria, di conservare angoli acuti in uno pseudo-SDF monocromatico se hai usato un filtro bilaterale un filtro bicubico direzionale invece di un filtro bilineare standard. Oltre all'ovvio vantaggio del risparmio di memoria, potresti anche avere più canali per le decalcomanie SDF multicolori.

In alternativa, se non ti dispiace usare un secondo canale, potresti anche provare ad avere un canale per la distanza orizzontale e un altro per la distanza verticale, e utilizzare una piramide di energia di differenza di Laplacea (DoL) per comprimere la trama in modo che le informazioni ridondanti non non essere registrato.

Una terza e ultima soluzione teorica sarebbe quella di sperimentare una trama campionata esagonalmente tramite indirizzamento di array.

Sfortunatamente, al momento non ho alcun mezzo per testare le mie idee e non sono stato in grado di trovare documenti che descrivono o testino qualcosa di simile alle mie idee. Collegherò tutti gli articoli pertinenti in cui ho ricevuto le mie informazioni / idee a breve.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.