2015-06-30 26 views
5

Il mio obiettivo è passare una serie di punti allo shader, calcolare la loro distanza dal frammento e dipingerli con un cerchio colorato con un gradiente a seconda del calcolo.Uniform point array e gestione dei sistemi di coordinate dello shader di frammenti

Ad esempio:
enter image description here
(Da una working example I set up on shader toy)

Purtroppo non è chiaro per me come dovrei calcolare e convertire le coordinate passati per l'elaborazione all'interno del shader.

Quello che sto provando attualmente è passare due array di float - uno per le posizioni x e uno per le posizioni y di ciascun punto - allo shader anche se uniforme. Poi dentro lo shader scorrere ogni punto in questo modo:

#ifdef GL_ES 
precision mediump float; 
precision mediump int; 
#endif 

uniform float sourceX[100]; 
uniform float sourceY[100]; 
uniform vec2 resolution; 

in vec4 gl_FragCoord; 

varying vec4 vertColor; 
varying vec2 center; 
varying vec2 pos; 

void main() 
{ 
    float intensity = 0.0; 

    for(int i=0; i<100; i++) 
    { 
     vec2 source = vec2(sourceX[i],sourceY[i]); 
     vec2 position = (gl_FragCoord.xy/resolution.xy); 
     float d = distance(position, source); 
     intensity += exp(-0.5*d*d); 
    } 

    intensity=3.0*pow(intensity,0.02); 

    if (intensity<=1.0) 
     gl_FragColor=vec4(0.0,intensity*0.5,0.0,1.0); 
    else if (intensity<=2.0) 
     gl_FragColor=vec4(intensity-1.0, 0.5+(intensity-1.0)*0.5,0.0,1.0); 
    else 
     gl_FragColor=vec4(1.0,3.0-intensity,0.0,1.0); 
} 

Ma questo non funziona - e credo che può essere perché sto cercando di lavorare con le coordinate di pixel senza tradurli correttamente. Qualcuno potrebbe spiegarmi come farlo funzionare?

Aggiornamento:

Il risultato corrente è: current result codice del disegno è:

PShader pointShader; 

float[] sourceX; 
float[] sourceY; 


void setup() 
{ 

    size(1024, 1024, P3D); 
    background(255); 

    sourceX = new float[100]; 
    sourceY = new float[100]; 
    for (int i = 0; i<100; i++) 
    { 
    sourceX[i] = random(0, 1023); 
    sourceY[i] = random(0, 1023); 
    } 


    pointShader = loadShader("pointfrag.glsl", "pointvert.glsl"); 
    shader(pointShader, POINTS); 
    pointShader.set("sourceX", sourceX); 
    pointShader.set("sourceY", sourceY); 
    pointShader.set("resolution", float(width), float(height)); 
} 


void draw() 
{ 
    for (int i = 0; i<100; i++) { 
    strokeWeight(60); 
    point(sourceX[i], sourceY[i]); 
    } 
} 

mentre il vertex shader è:

#define PROCESSING_POINT_SHADER 

uniform mat4 projection; 
uniform mat4 transform; 


attribute vec4 vertex; 
attribute vec4 color; 
attribute vec2 offset; 

varying vec4 vertColor; 
varying vec2 center; 
varying vec2 pos; 

void main() { 

    vec4 clip = transform * vertex; 
    gl_Position = clip + projection * vec4(offset, 0, 0); 

    vertColor = color; 
    center = clip.xy; 
    pos = offset; 
} 
+0

Si può espandere su come esso "non funziona"? Oltre a non gestire la proporzione del punto o le proporzioni del viewport, nulla sembra immediatamente sbagliato. In realtà non sono sicuro degli array uniformi perché esiste un limite al numero di uniformi che puoi avere. Come imposti i loro valori? Usi buffer uniformi? – jozxyqk

+0

Ignora che, [l'impostazione di un array uniforme] (http://stackoverflow.com/a/8100273/1888983) va bene, e sembra che non si esauriranno le posizioni date [almeno 1024] (https://www.opengl.org/wiki/Uniform_(GLSL)), ma potresti voler guardare gli oggetti buffer uniformi. – jozxyqk

+0

Grazie per la risposta, il problema è che lo shader disegna tutti i cerchi in nero. Da quello che posso ottenere, ci sono alcuni problemi con il valore di d. Ecco cosa ottengo: [Immagine] (http://i.imgur.com/TIZ0TIq.png) – Giuseppe

risposta

2

Aggiornamento:

Sulla base delle osservazioni sembra aver confuso due diversi approcci:

  1. disegnare un singolo poligono pieno schermo, passare nei punti e calcolare il valore finale una volta per ogni frammento utilizzando un ciclo nello shader.
  2. Disegnare la geometria di delimitazione per ciascun punto, calcolare la densità per un solo punto nello shader di frammenti e utilizzare la miscelazione additiva per sommare le densità di tutti i punti.

L'altro problema è che i punti sono espressi in pixel ma il codice prevede un intervallo da 0 a 1, quindi d è grande ei punti sono neri. Risolvere questo problema come @RetoKoradi describes dovrebbe risolvere i punti neri, ma ho il sospetto che troverai problemi di clipping rampa quando molti sono nelle immediate vicinanze. Passare punti nello shader limita la scalabilità ed è inefficiente a meno che i punti coprano l'intera finestra.

Come di seguito, penso che attenersi all'approccio 2 sia migliore. Di ristrutturare il codice per esso, rimuovere il loop, non passare nella matrice di punti e utilizzare center come punto di coordinate invece:

//calc center in pixel coordinates 
vec2 centerPixels = (center * 0.5 + 0.5) * resolution.xy; 

//find the distance in pixels (avoiding aspect ratio issues) 
float dPixels = distance(gl_FragCoord.xy, centerPixels); 

//scale down to the 0 to 1 range 
float d = dPixels/resolution.y; 

//write out the intensity 
gl_FragColor = vec4(exp(-0.5*d*d)); 

Draw this to a texture (da osservazioni: opengl-tutorial.orgcode e this question) con additivo blending:

glEnable(GL_BLEND); 
glBlendFunc(GL_ONE, GL_ONE); 

Ora che trama conterrà intensity come è stato dopo il ciclo originale.In un'altra Shader frammento durante un passaggio a schermo intero (trascinare un triangolo che copre l'intera finestra), continua con:

uniform sampler2D intensityTex; 
... 
float intensity = texture2D(intensityTex, gl_FragCoord.xy/resolution.xy).r; 
intensity = 3.0*pow(intensity, 0.02); 
... 

Il codice avete mostrato è soddisfacente, supponendo che si sta tracciando una completo schermo poligono in modo che lo shader di frammenti venga eseguito una volta per ogni pixel. Potenziali problemi sono:

  • resolution non è impostato correttamente
  • Le coordinate del punto non sono nel range 0-1 sullo schermo.
  • Anche se di minore importanza, lo d verrà allungato dal rapporto aspetto, quindi è possibile che sia meglio ridimensionare i punti fino alle coordinate dei pixel e alla distanza di immersione entro resolution.y.

Sembra molto simile alla creazione di un campo di densità per 2D metaballs. Per le prestazioni, è meglio limitare la funzione di densità per ogni punto in modo che non avvenga per sempre, quindi spargere i dischi in una texture utilizzando la miscelazione aggiuntiva. Questo risparmia l'elaborazione di quei pixel che un punto non ha effetto (proprio come nelle sfumature differite). Il risultato è il campo di densità, o nel tuo caso per-pixel intensity.

questi sono un po 'correlato:

+0

Cosa intendi per un poligono a schermo intero? Da quello che ottengo (l'immagine sopra) le figure sono disegnate correttamente, mentre la logica sul colore non lo è. Penso che la risoluzione sia corretta - come dovrebbe essere passata da Processing - ma probabilmente ho fatto un errore riguardo le coordinate del punto passate attraverso l'uniforme, perché non sono nell'intervallo 0-1, ma l'ho randomizzato in 0-1023 , poiché il trattamento accetterebbe questo: potrei spiegare meglio come dovrebbero essere? Come posso convertirli manualmente in coordinate "glsl" prima di confrontarmi con le coordinate dello shader? Ho aggiornato il primo post – Giuseppe

+0

Sto iniziando a vedere come funziona la tua soluzione, sperando che almeno funzioni. Ti dispiacerebbe spiegare più in dettaglio come si disegna la trama? Ho letto i documenti che hai collegato, ma onestamente non sono molto chiari a me e non ho capito bene come fare quel passaggio. O potresti darmi un esempio per iniziare? Ho trovato questo [link] (http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/), ma non so se può essere applicato al soluzione che ti è stata fornita. – Giuseppe

+0

Inoltre, è strettamente necessario avviare un altro shader per rendere la texture? Elaborazione Afaik lascia il rendering di 1 shader per schizzo, quindi, non credo (e la documentazione \ esempi su questo sono penosamente scarse) è possibile usarne una per fare la "matematica" e un'altra per rendere efficacemente la trama. – Giuseppe

0

Sembra che il punto centrale e la posizione frammento sono in diversi spazi di coordinate quando le sottrai:

vec2 source = vec2(sourceX[i],sourceY[i]); 
vec2 position = (gl_FragCoord.xy/resolution.xy); 
float d = distance(position, source); 

In base alla spiegazione e al codice, source e source sono in coordinate di finestra, ovvero in unità di pixel. gl_FragCoord si trova nello stesso spazio di coordinate. E anche se non lo mostri direttamente, suppongo che resolution sia la dimensione della finestra in pixel.

Questo significa che:

vec2 position = (gl_FragCoord.xy/resolution.xy); 

calcola la posizione normalizzata del frammento all'interno della finestra, nell'intervallo [0.0, 1.0] per xey. Ma poi nella riga successiva:

float d = distance(position, source); 

si subtrace source, che è ancora in coordinate finestra, da questa posizione in coordinate normalizzate.

Poiché sembra che si voleva la distanza in coordinate normalizzate, che ha un senso, avrete anche bisogno di normalizzare source:

vec2 source = vec2(sourceX[i],sourceY[i])/resolution.xy; 
+0

Non sono sicuro, ma ho il sospetto che questo abbia problemi di proporzioni. Forse 'd = length ((position - source) * vec2 (resolution.x/resolution.y, 1.0))' o lascia source as is e 'position = gl_FragCoord.xy' seguito da' d/= resolution.y' ? – jozxyqk

+0

@jozxyqk La finestra è quadrata nel codice dell'OP. Sì, se la finestra non fosse quadrata, ciò creerebbe i puntini di sospensione. –

+0

Cercando di funzionare con la fonte di normalizzazione come hai detto, ma il risultato è che tutto il cerchio è ancora nero - non importa quanto cerco di regolare il valore di gl_FragColor. Ci deve essere qualcos'altro che non funziona, o questo tipo di soluzione per ottenere i valori nelle stesse coordinate non è giusto per alcune ragioni che non capisco. Accetterei volentieri qualsiasi altra idea, nel frattempo proverò a vedere se e come posso implementare la soluzione [@jozxyqk] (http://stackoverflow.com/a/31141725/5065842) proposta nel commento sopra – Giuseppe