Ombreggiatura Toon / cel con larghezza della linea variabile?


15

Vedo alcuni ampi approcci là fuori per fare l'ombreggiatura cel:

  1. Duplicazione e ingrandimento del modello con normali capovolte (non un'opzione per me)
  2. Lo shader Sobel filter / fragment si avvicina al rilevamento dei bordi
  3. Il buffer dello stencil si avvicina al rilevamento dei bordi
  4. Approcci shader di Geometria (o vertice) che calcolano le normali di faccia e bordo

Sono corretto nel ritenere che l'approccio incentrato sulla geometria offra il massimo controllo sull'illuminazione e sullo spessore della linea, ad es. per il terreno dove potresti vedere la sagoma di una collina che si fonde gradualmente in una pianura?

E se non avessi bisogno dell'illuminazione dei pixel sulle superfici del mio terreno? (E probabilmente non lo farò mentre pianifico di usare l'ombreggiatura / l'ombreggiatura basata su vertici o texturemap basati su celle.) Sarei quindi meglio attenermi all'approccio del tipo di geometria, o preferirei invece un approccio spazio su schermo / frammento per semplificare le cose? Se è così, come potrei ottenere il "inchiostrazione" delle colline all'interno della silhouette della mesh, piuttosto che solo il contorno dell'intera mesh (senza dettagli "inchiostro" all'interno di quel contorno? ( Contorni suggestivi , pieghe dell'AKA ).

Infine, è possibile emulare a buon mercato l'approccio a capovolto normale, usando uno shader di geometria? La mia preoccupazione per questo è che potrei certamente duplicare ogni singolo vertice e ridimensionarli di conseguenza, ma come approccerei capovolgendo le normali e distinguendo i colori nello shader di frammenti?

Quello che voglio - variare lo spessore della linea con linee intrusive all'interno della silhouette ...

inserisci qui la descrizione dell'immagine

Quello che non voglio ...

inserisci qui la descrizione dell'immagine


EDIT: ulteriori ricerche hanno rivelato il seguente ...

Dal momento che ho un enorme numero di vertici sul terreno, anche considerando il LoD basato sulla distanza, né le normali capovolte né un approccio basato sullo shader della geometria (anche con l'abbattimento del frustum) sarebbero un'opzione sensata a causa della pura complessità computazionale coinvolta nella duplicazione e nel ridimensionamento di tutti vertici caricati.

Considerando che non ho bisogno di illuminazione per pixel sotto forma di ombreggiatura a tono solido sulle superfici del terreno, diventa anche meno prudente considerare qualsiasi approccio basato sul normale al viso - altrimenti un requisito per una corretta illuminazione della superficie - in quanto questi sono naturalmente piuttosto costosi da calcolare. È tuttavia vero che offrono il massimo grado di controllo; per esempio, la capacità di sfumare i bordi usando tratti "artistici": bello, ma ancora non praticabile per un ambiente di gioco estremamente complesso.

I buffer di stencil sono qualcosa che preferirei evitare poiché preferirei fare tutto il lavoro negli shader. (L'esempio sopra con il contorno rosso è stato fatto con un buffer di stencil - vecchia scuola.)

Questo lascia frammenti di shader approcci spazio-immagine. La complessità computazionale è ridotta al numero di frammenti piuttosto che al numero di vertici (nel mio caso, si tratta di 10-100 volte meno operazioni di quelle che avrei dovuto fare nello shader della geometria). Ciò richiede più di un passaggio di rendering per generare un g-buffer (costituito da un buffer normale e facoltativamente anche da un buffer di profondità) al quale possiamo applicare filtri di discontinuità (es. Operatore Sobel). La discontinuità di profondità è ciò che consente contorni e pieghe suggestivi. Il mio unico cavillo con questo approccio è l'incapacità di fornire un controllo più preciso sulle larghezze dei bordi inchiostrati, sebbene con il giusto algoritmo nello shader di frammenti, sono sicuro che ciò sarebbe possibile.

Quindi la domanda ora diventa più specifica: come farei esattamente per ottenere larghezze dei bordi variabili, in particolare sulla sagoma esterna, in uno shader di frammenti?


Lo spessore della linea variabile è una caratteristica dell'approccio geometrico. Non è possibile ottenerlo in altro modo. Dato che lo desideri, non vedo i pixel shader come il "metodo più efficiente": numero di pixel da cercare = (line_thickness * 2 + 1) ^ 2 - 1. Ciò significherebbe sostanzialmente che il tuo shader post-process sarà molto (probabilmente indicativo: 10x) più lento se max. la larghezza della linea è uguale a 2. Basta rilasciare il pre-giudizio e provare l'approccio shader della geometria.
snake5,

@ snake5 Stai onestamente suggerendo di eseguire 150 milioni di vertici per aggiornamento del rendering (circa 25 milioni con la visualizzazione dell'abbattimento), nel GS? Non lo sto davvero comprando, ma grazie per l'input. Fai riferimento a ciò che ho detto sopra riguardo alla conta e alla complessità dei vertici. Anche con la tua figura 10x, lo shader di frammenti disegnerebbe almeno pari, e probabilmente farebbe molto meglio.
Ingegnere il

25 milioni di vertici (letture / scritture lineari) contro 23 milioni di campioni di trama (letture di memoria piuttosto scarsamente memorizzate nella cache + decompressione dei dati di destinazione del rendering) @ 1280x720. A proposito, limitare / ridurre il conteggio dei vertici è molto più semplice. Soprattutto in questi giorni, quando i grandi monitor (1920x1080 +) e le configurazioni multimonitor stanno diventando molto popolari.
snake5,

che dire di usare lo stesso algoritmo di quello che genera contorni rossi e quindi di assottigliare / aumentare le linee in base alla profondità?
Ali1S232,

@Gajoo, come dicevo nella domanda, non si tratta solo della silhouette. Nota le linee intrusive dietro la spalla della ragazza nella prima immagine. Quelle sono una funzione dell'approccio capovolto-normale e fungono da contorni / pieghe suggestivi. Ho bisogno dello stesso.
Ingegnere il

Risposte:


4

Ho deciso di seguire un approccio con shader di frammenti tramite il filtro di discontinuità del buffer di profondità. I motivi per questo sono:

  1. Il conteggio dei vertici mondiali è molto, molto elevato a causa delle immense distanze di visualizzazione, anche con mesh LoD;
  2. Sto facendo una serie di altre operazioni di shader di frammenti, come la sfocatura DoF, che può trarre vantaggio dalle stesse strutture (box o campionamento / filtro gaussiani) nello stesso passaggio.

Avendolo testato, direi che nei progetti futuri preferirei un approccio basato sulla geometria, per ragioni di complessità. Il motivo è che (come altri suggeriscono nei commenti), gli approcci di shader di frammenti alla rilevazione dei bordi possono essere intensi dal punto di vista computazionale, in particolare con implementazioni DoF in cui il cerchio del raggio di confusione, e quindi il numero di campioni per frammento, può essere piuttosto elevato. Questo per fortuna è meno preoccupante per gli shader di contorno.


Penso che andare con la discontinuità normale ti darebbe risultati migliori nel caso in cui avessi normali normali. È possibile variare la larghezza della linea allontanando i campioni.
Grieverheart,

@Grieverheart Questa è la risposta accettata, perché il metodo che sto usando funziona perfettamente. Grazie.
Ingegnere

0

In realtà esiste una soluzione generale molto semplice se è possibile utilizzare un effetto secondario. La cosa bella è che non importa quanto sia alto il tuo numero di poli. Rendering di una mappa di profondità come scala di grigi, quindi crea un punto nel colore della linea desiderato, quando il contrasto tra due pixel adiacenti è superiore a un valore di soglia. È possibile ingrandire il punto in base al contrasto e al livello di luce dell'immagine renderizzata.

Ho inventato l'algoritmo toonShader nel 2000/2001, anche prima di quel tizio francese, che ha creato questa soluzione. Il mio era basato sulla geometria dei materiali reali. Quindi ci sono fondamentalmente due modi per farlo: 1. guarda le normali, se le normali due piani collegati a una linea sono rivolte in direzione opposta e verso la telecamera, esegui il rendering di quella linea, puoi quindi usare la profondità, l'illuminazione ecc. Come spunti per gli allineamenti. 2. Guarda la geomeria renderizzata (quindi dopo la trasformazione prospettica) Prendi ogni segmento di linea, se i vertici dei piani di connessione sono sullo stesso lato di questo segmento di linea, esegui il rendering della linea .. Puoi quindi fare lo stesso per lo spessore della linea come in metodo 1. 3. Potresti creare combinazioni di queste tre tecniche, ma ho menzionato la prima, perché hai indicato un enorme conteggio dei poli.

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.