2015-06-30 5 views
5

Mein Ziel ist es, ein Array von Punkten an den Shader zu übergeben, ihre Entfernung zum Fragment zu berechnen und sie mit einem Kreis mit einem Gradienten abhängig von dieser Berechnung zu malen.Uniform Punktarrays und Verwalten von Fragment Shader Koordinatensystemen

Zum Beispiel:
enter image description here
(Aus einem working example I set up on shader toy)

Leider ist es mir nicht klar, wie ich soll die Koordinaten für die Verarbeitung in den Shader übergeben berechnen und konvertieren.

Was ich derzeit versuche ist, zwei Array von Floats - eine für x-Positionen und eine für y-Positionen von jedem Punkt - an den Shader durch eine Uniform übergeben. Dann innerhalb des Shader durch jeden Punkt durchlaufen wie so:

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

Aber das funktioniert nicht - und ich glaube, es kann sein, weil ich versuche, mit der Pixel ohne sie richtig zu übersetzen Koordinaten zu arbeiten. Kann mir jemand erklären, wie man das macht?

Update:

Das aktuelle Ergebnis ist: current result Der Code der Skizze ist:

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

während der Vertex-Shader ist:

#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

Können Sie erweitern, wie es „funktioniert nicht“? Abgesehen davon, dass die Punktskala oder das Bildfenster-Seitenverhältnis nicht gehandhabt wird, sieht nichts sofort falsch aus. Eigentlich bin ich mir über die uniformen Arrays nicht sicher, da die Anzahl der Uniformen begrenzt ist. Wie stellen Sie ihre Werte ein? Verwenden Sie einheitliche Puffer? – jozxyqk

+0

Ignorieren Sie, dass [ein einheitliches Array festlegen] (http://stackoverflow.com/a/8100273/1888983) in Ordnung ist, und es sieht so aus, als ob Ihnen die angegebenen Orte nicht ausgehen [mindestens 1024] (https://www.opengl.org/wiki/Uniform_(GLSL)), aber Sie könnten sich auch gleichartige Pufferobjekte ansehen. – jozxyqk

+0

Danke für die Antwort, das Problem ist, der Shader zeichnet alle Kreise schwarz. Von dem, was ich bekommen kann, gibt es einige Probleme mit dem Wert von d. Hier ist, was ich bekomme: [Image] (http://i.imgur.com/TIZ0TIq.png) – Giuseppe

Antwort

2

Update:

Basierend auf den Kommentaren scheint es zwei verschiedene Ansätze verwechselt haben:

  1. Zeichnen Sie ein einzelnes Vollbild Polygon, in den Punkten passieren und den Endwert einmal pro Fragment mit einer Schleife im Shader berechnen.
  2. Zeichnen Sie die Begrenzungsgeometrie für jeden Punkt, berechnen Sie die Dichte für nur einen Punkt im Fragment-Shader und verwenden Sie additive Überblendung, um die Dichten aller Punkte zu summieren.

Das andere Problem ist Ihre Punkte in Pixel angegeben werden, aber der Code erwartet eine 0 auf 1 Bereich, so ist d groß und die Punkte sind schwarz. Behebung dieses Problems als @RetoKoradi describes sollte die Punkte ansprechen, die schwarz sind, aber ich vermute, dass Sie Ramp Clipping Probleme finden werden, wenn viele in unmittelbarer Nähe sind. Das Übergeben von Punkten in den Shader begrenzt die Skalierbarkeit und ist ineffizient, es sei denn, die Punkte decken das gesamte Ansichtsfenster ab.

Wie unten, denke ich bei Ansatz 2 ist besser. Um den Code zu, entfernen die Schleife neu strukturiert, nicht besteht in der Anordnung von Punkten und verwendet center als Koordinatenpunkt statt:

//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 (von Kommentaren: opengl-tutorial.orgcode und this question) mit additiven blending:

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

Jetzt wird die Textur enthalten intensity, wie es nach dem ursprünglichen Schleife war.In einem anderen Fragment-Shader während eines Vollbild-Pass (ein einzelnes Dreieck zeichnen, die das gesamte Ansichtsfenster abdeckt), weiter mit:

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

Der Code, den Sie gezeigt haben, ist in Ordnung, vorausgesetzt, du bist ein vollständigen Zeichnung Screen-Polygon, so dass der Fragment-Shader für jedes Pixel einmal ausgeführt wird. Potentielle Probleme sind:

  • resolution nicht korrekt
  • die Punktkoordinaten sind nicht in dem Bereich eingestellt ist, 0 bis 1 ist auf dem Bildschirm.
  • Obwohl kleinere, d wird durch das Seitenverhältnis gestreckt, so dass Sie möglicherweise besser skalieren die Punkte bis Pixel Koordinaten und Tauchabstand von resolution.y.

Dies ähnelt der Erstellung eines Dichtefelds für 2D metaballs. Um die Leistung zu optimieren, sollten Sie die Dichtefunktion für jeden Punkt so begrenzen, dass sie nicht für immer andauert und die Discs dann in eine Textur mit additivem Mischen einspritzt. Dies spart die Verarbeitung der Pixel, die ein Punkt nicht beeinflusst (genau wie in der verzögerten Schattierung). Das Ergebnis ist das Dichtefeld oder in Ihrem Fall pro Pixel intensity.

Diese sind ein wenig verwandten:

+0

Was meinst du für ein Vollbild-Polygon? Von dem, was ich bekomme (das Bild oben), sind die Figuren korrekt gezeichnet, während die Logik über Farbe nicht ist. Ich denke, die Auflösung ist korrekt - wie es von Processing durchgeführt werden sollte - aber ich habe wahrscheinlich einen Fehler gemacht über die Punktkoordinaten, die durch die Uniform gegangen sind, weil sie nicht im 0-1-Bereich liegen, sondern zufällig in 0-1023 inialisiert wurden , wie Verarbeitung würde akzeptieren, dass: Könnte ich besser erklären, wie sie sein sollten? Wie kann ich sie manuell in "Glsl" -Koordinaten konvertieren, bevor ich mit der Koordinate des Shaders konfrontiert werde? Ich habe erste Post – Giuseppe

+0

updated Ich beginne zu sehen, wie Ihre Lösung, hoffe, es funktioniert zumindest. Würde es Ihnen etwas ausmachen, mehr im Detail zu erklären, wie man das Textur-Zeichnen macht? Ich habe die Dokumente gelesen, die Sie verlinkt haben, aber sie sind mir ehrlich gesagt nicht sehr klar und ich habe nicht gut verstanden, wie diese Passage funktioniert. Oder könnten Sie mir ein Beispiel geben, von dem ich anfangen könnte? Ich habe dieses gefunden [link] (http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/), aber ich weiß nicht, ob es auf die Lösung, die Ihnen zur Verfügung gestellt wird. – Giuseppe

+0

Ist es außerdem unbedingt notwendig, einen anderen Shader zu starten, um die Textur zu rendern? Afaik Processing ließ 1 Shader pro Skizze rendern, also glaube ich nicht (und die Dokumentation \ Beispiele dafür sind schmerzhaft selten), es ist möglich, einen zu verwenden, um die "Mathematik" zu machen und einen anderen, um die Textur effektiv zu rendern. – Giuseppe

0

Es sieht aus wie der Punkt Zentrum und Fragmentposition sind in verschiedenen Räumen koordinieren wenn Sie sie subtrahieren:

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

Auf der Grundlage Ihrer Erklärung und Ihres Codes sind source und source in Fensterkoordinaten angegeben, was bedeutet, dass sie in Pixeleinheiten angegeben sind. gl_FragCoord ist im selben Koordinatenraum. Und obwohl Sie das nicht direkt zeigen, nehme ich an, dass resolution die Größe des Fensters in Pixeln ist. Diese

bedeutet:

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

die normierte Position des Fragments innerhalb des Fensters berechnet, im Bereich von [0,0, 1,0] für beide x und y. Aber dann in der nächsten Zeile:

float d = distance(position, source); 

Sie subtrace source, die noch in Fensterkoordinaten ist, von dieser Position in normierten Koordinaten.

Da es sieht aus wie Sie den Abstand in normalisierten Koordinaten wollte, was Sinn macht, werden Sie auch source normalisieren müssen:

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

Nicht sicher, aber ich vermute, dass dies Probleme mit dem Seitenverhältnis haben wird. Vielleicht entweder 'd = length ((position - source) * vec2 (resolution.x/resolution.y, 1.0)) 'oder lasse source unverändert und' position = gl_FragCoord.xy' gefolgt von 'd/= resolution.y' ? – jozxyqk

+0

@jozxyqk Das Fenster ist quadratisch im OP-Code. Ja, wenn das Fenster nicht quadratisch wäre, würde dies eine Ellipse erzeugen. –

+0

Der Versuch, mit normalisierender Quelle zu laufen, wie Sie gesagt haben, aber das Ergebnis ist, dass alle Kreise immer noch schwarz sind - egal wie ich den Wert von gl_FragColor anpassen möchte. Es muss etwas anderes geben, was nicht funktioniert, oder diese Art von Lösung, um die Werte in den gleichen Koordinaten zu erhalten, ist aus einigen Gründen, die ich nicht bekomme, nicht richtig. Ich würde gerne jede andere Idee akzeptieren, während ich versuchen werde, zu sehen, ob und wie ich die Lösung [@jozxyqk] (http://stackoverflow.com/a/31141725/5065842) in der obigen Kommentar vorgeschlagen – Giuseppe

Verwandte Themen