2013-03-07 9 views
14

È possibile aggiungere spessori di linea nel framment shader considerando che disegno la linea con GL_LINES? La maggior parte degli esempi che ho visto sembrano accedere solo ai texel della primitiva nello shader dei frammenti e uno shader di spessore della linea dovrebbe scrivere su texel al di fuori della linea primitiva per ottenere lo spessore. Se è possibile, tuttavia, un esempio molto piccolo, di base, sarebbe fantastico.È possibile disegnare lo spessore della linea in uno shader di frammenti?

risposta

12

Abbastanza è possibile con gli ombreggiatori di frammenti. Basta guardare what some guys are doing. Sono lontano da quel livello stesso ma questo codice può darvi un'idea:

#define resolution vec2(500.0, 500.0) 
#define Thickness 0.003 

float drawLine(vec2 p1, vec2 p2) { 
    vec2 uv = gl_FragCoord.xy/resolution.xy; 

    float a = abs(distance(p1, uv)); 
    float b = abs(distance(p2, uv)); 
    float c = abs(distance(p1, p2)); 

    if (a >= c || b >= c) return 0.0; 

    float p = (a + b + c) * 0.5; 

    // median to (p1, p2) vector 
    float h = 2/c * sqrt(p * (p - a) * (p - b) * (p - c)); 

    return mix(1.0, 0.0, smoothstep(0.5 * Thickness, 1.5 * Thickness, h)); 
} 

void main() 
{ 
    gl_FragColor = vec4(
     max(
     max(
      drawLine(vec2(0.1, 0.1), vec2(0.1, 0.9)), 
      drawLine(vec2(0.1, 0.9), vec2(0.7, 0.5))), 
     drawLine(vec2(0.1, 0.1), vec2(0.7, 0.5)))); 
} 

enter image description here

Un'altra alternativa è quella di verificare con texture2D per il colore dei pixel vicina - in questo modo si può fare voi l'immagine si illumina o si ispessisce (ad esempio se uno qualsiasi dei pixel di regolazione è bianco, rendi il pixel corrente bianco, se accanto al pixel vicino è bianco, rendi il pixel corrente grigio).

+0

Uomo, quel sito è grandioso! – Meda

+7

Mentre questo "funziona", va notato che questo è probabilmente il modo più inefficiente nel mondo per disegnare tre linee. Il 99% dei frammenti che vengono elaborati vengono gettati via durante la fusione. – Damon

+1

+ Damon è sicuro che non è stato concepito come best practice e il mio esempio è un po 'sciocco; ma solo per dimostrare il principio e le possibilità degli shader - il modo simile in cui si possono fare vari effetti di bagliore o di particelle o rendere tutti i terreni da heightmaps o complessi frattali geometrici dai campi di distanza che non usano un singolo vertice. Sorprendentemente gli shader possono essere piuttosto veloci. – defhlt

1

No, non è possibile nello shader dei frammenti. Tuttavia, puoi usare uno shader di geometria per espandere la tua linea su un quad (o, in realtà, due triangoli) che possono rappresentare una linea spessa.

Here's una bella discussione su questo argomento (con esempi di codice).

+0

così nello shader frammento si può solo accedere/modificare i frammenti all'interno delle primitive di disegno? Questo avrebbe senso. Per quanto riguarda la tua soluzione proposta, grazie ma non riesco a utilizzare gli shader geometrici :( – Meda

+0

Non accessibile: puoi leggere da qualsiasi sorgente, ma puoi solo scrivere in una posizione e ti viene data dal rasterizzatore. usa lo stesso metodo sulla CPU se non hai shader di geometria – ltjax

+2

non dire mai di no a meno che tu non possa provarlo – GottZ

2

Ecco il mio approccio. Lascia che p1 e p2 siano i due punti che definiscono la linea, e lascia che sia il punto la cui distanza dalla linea che vuoi misurare. Il punto è probabilmente gl_FragCoord.xy/resolution;

Ecco la funzione.

float distanceToLine(vec2 p1, vec2 p2, vec2 point) { 
    float a = p1.y-p2.y; 
    float b = p2.x-p1.x; 
    return abs(a*point.x+b*point.y+p1.x*p2.y-p2.x*p1.y)/sqrt(a*a+b*b); 
} 

Quindi utilizzarlo nelle funzioni di mix e smoothstep.

controllare anche questa risposta: https://stackoverflow.com/a/9246451/911207