2010-04-29 17 views
29

Ich versuche, in GLSL den Kopf um Shader zu wickeln, und ich habe einige nützliche Ressourcen und Tutorials gefunden, aber ich stolperte immer wieder in eine Wand für etwas, das grundlegend und trivial sein sollte: Wie holt mein Fragment - Shader die Farbe des aktuellen Fragments?Wie bekomme ich die aktuelle Farbe eines Fragments?

Sie legen die endgültige Farbe fest, indem Sie gl_FragColor = whatever sagen, aber anscheinend ist das ein Ausgabewert. Wie erhalten Sie die ursprüngliche Farbe der Eingabe, so dass Sie Berechnungen darauf durchführen können? Das muss irgendwo in einer Variablen sein, aber wenn jemand da draußen seinen Namen kennt, scheint er es in keinem Tutorial oder einer Dokumentation, die ich bisher gesehen habe, aufgezeichnet zu haben, und es treibt mich die Wand hoch.

+0

"Originalfarbe der Eingabe": meinst du die Materialeigenschaften, die deinem Fragment zugewiesen sind (Textur, Diffusfarbe ...)? – DamienD

Antwort

14

Der Fragment-Shader empfängt gl_Color und gl_SecondaryColor als Vertex-Attribute. Es erhält auch vier variierende Variablen: gl_FrontColor, gl_FrontSecondaryColor, und gl_BackSecondaryColor, dass es Werte schreiben kann. Wenn Sie die ursprünglichen Farben gerade durchlaufen wollen, würden tun Sie so etwas wie:

gl_FrontColor = gl_Color; 
gl_FrontSecondaryColor = gl_SecondaryColor; 
gl_BackColor = gl_Color; 
gl_BackSecondaryColor = gl_SecondaryColor; 

feste Funktionalität in der Pipeline nach den Vertex-Shader werden diese dann auf den Bereich klemmen [0..1] und Figur ob der Scheitelpunkt nach vorne oder nach hinten gerichtet ist. Es interpoliert dann wie gewohnt die gewählte (vordere oder hintere) Farbe. Der Fragment-Shader empfängt dann die ausgewählten, geklemmten, interpolierten Farben wie gl_Color und gl_SecondaryColor.

Zum Beispiel, wenn Sie den Standard "Todesdreieck" wie zog:

glBegin(GL_TRIANGLES); 
    glColor3f(0.0f, 0.0f, 1.0f); 
    glVertex3f(-1.0f, 0.0f, -1.0f); 
    glColor3f(0.0f, 1.0f, 0.0f); 
    glVertex3f(1.0f, 0.0f, -1.0f); 
    glColor3f(1.0f, 0.0f, 0.0f); 
    glVertex3d(0.0, -1.0, -1.0); 
glEnd(); 

Dann wird ein Vertex-Shader wie folgt aus:

void main(void) { 
    gl_Position = ftransform(); 
    gl_FrontColor = gl_Color; 
} 

mit einem Fragment-Shader wie folgt aus:

void main() { 
    gl_FragColor = gl_Color; 
} 

wird die Farben übertragen, genau wie wenn Sie die Pipeline mit fester Funktionalität verwenden würden.

+25

Das meiste, was Sie tun, ist nach Version 120 veraltet. In der Tat, nicht nur Warnungen, sondern auch Fehler. Funktioniert auch nicht mit OpenGL ES 2.0 (auch weg in 4.x?) – user697111

3

Der gesamte Punkt Ihres Fragment-Shaders ist zu entscheiden, was die Ausgabefarbe ist. Wie Sie das tun, hängt davon ab, was Sie tun möchten.

Sie können Dinge so einrichten, dass Sie eine interpolierte Farbe basierend auf der Ausgabe des Vertex-Shaders erhalten. Ein gebräuchlicherer Ansatz wäre jedoch eine Textur-Suche im Fragment-Shader mithilfe von Texturkoordinaten in der from die Vertex-Shader-Interpolanten. Sie würden dann das Ergebnis Ihrer Textur-Suche entsprechend den von Ihnen gewählten Beleuchtungsberechnungen und was auch immer Ihr Shader machen soll ändern und dann in gl_FragColor schreiben.

6

Wenn der aktuelle Wert des Fragments der Wert der Pixelfarbe im Renderziel ist, bevor der Fragment-Shader ausgeführt wird, dann ist er nicht verfügbar.

Der Hauptgrund dafür ist, dass zum Zeitpunkt, zu dem Ihr Fragment-Shader läuft, es noch nicht bekannt ist. Fragmentierungs-Shader laufen parallel, möglicherweise (abhängig von der Hardware), die dasselbe Pixel betreffen, und normalerweise ist ein separater Block, der aus irgendeiner Art von FIFO liest, dafür verantwortlich, diese zusammen später zusammenzufügen. Diese Zusammenführung wird "Blending" genannt und ist noch nicht Teil der programmierbaren Pipeline. Es ist eine feste Funktion, aber es gibt eine Reihe verschiedener Möglichkeiten, um das, was Ihr Fragment-Shader erzeugt hat, mit dem vorherigen Farbwert des Pixels zu kombinieren.

12

Wenn Sie Multi-Pass-Rendering, d.wenn Sie den Framebuffer verdient gemacht haben und wollen zu einem zweiten Render Pass, wo Sie den vorherigen Rendering als die Antwort verwenden ist:

  1. den ersten Durchgang auf eine Textur
  2. Bind diese Textur für den zweiten Durchlauf Render
  3. Zugriff auf die privously aufbereitete Pixel im Shader

Shader-Code für 3.2:

uniform sampler2D mytex; // texture with the previous render pass 

layout(pixel_center_integer) in vec4 gl_FragCoord; 
// will give the screen position of the current fragment 

void main() 
{ 
    // convert fragment position to integers 
    ivec2 screenpos = ivec2(gl_FragCoord.xy); 
    // look up result from previous render pass in the texture 
    vec4 color = texelFetch(mytex, screenpos, 0); 
    // now use the value from the previous render pass ... 
} 

Eine weitere Methode zur Bearbeitung eines gerenderten Bildes wäre OpenCL mit OpenGL -> OpenCL interop. Dies ermöglicht mehr CPU-ähnliche Berechnungen.

4

Sie müssen sich an aktuellen Pixelkoordinaten Textur probieren, so etwas wie dieses

vec4 pixel_color = texture2D(tex, gl_TexCoord[0].xy);

Hinweis, - wie ich Texture2D habe gesehen, in GLSL 4.00 Spezifikation ist veraltet - aussehen nur für ähnliche Textur ... holen Funktionen .

auch manchmal ist es besser, Ihr eigenes Pixel zu liefern Koordinaten statt gl_TexCoord [0] .xy - in diesem Fall Schreib Vertex-Shader so etwas wie:

varying vec2 texCoord; 

void main(void) 
{ 
    gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0); 
    texCoord = 0.5 * gl_Position.xy + vec2(0.5);  
}

Und in Fragment-Shader verwenden, die texCoord Variable statt gl_TexCoord [0] .xy.

Viel Glück.

-3

How-do-i-get-the-Strom-color-of-a-Fragment

Einige sagen, es nicht getan werden kann, aber ich sage das für mich funktioniert:

//Toggle blending in one sense, while always disabling it in the other. 
void enableColorPassing(BOOL enable) { 
//This will toggle blending - and what gl_FragColor is set to upon shader execution 
    enable ? glEnable(GL_BLEND) : glDisable(GL_BLEND); 
    //Tells gl - "When blending, change nothing" 
    glBlendFunc(GL_ONE, GL_ZERO); 
} 

Nach diesem Aufruf entspricht gl_FragColor der Farbe des Farbpuffers, wenn der Shader zum ersten Mal auf jedem Pixel ausgeführt wird, und die Ausgabe jedes Laufs ist die neue Eingabe bei jedem nachfolgenden Durchlauf.

Nun, zumindest funktioniert es für mich.

+5

-1: Für "es funktioniert für mich" Unsinn ohne auch nur zu sagen, welche Hardware Sie tatsächlich verwenden. Auch, um unbestimmtes Verhalten zu unterstützen, ohne zu sagen, welche Hardware Sie verwenden, die dies tut. –

1

Die GPU-Pipeline hat Zugriff auf die zugrunde liegenden Pixel Info sofort nach die Shader laufen. Wenn Ihr Material transparent ist, werden in der Mischphase der Pipeline alle Fragmente kombiniert.

Im Allgemeinen werden Objekte in der Reihenfolge gemischt, in der sie zu einer Szene hinzugefügt werden, es sei denn, sie wurden von einem z-Puffer-Algo bestellt. Sie sollten zuerst Ihre undurchsichtigen Objekte hinzufügen und dann vorsichtig Ihre transparenten Objekte in der Reihenfolge hinzufügen, in der sie gemischt werden sollen.

Wenn Sie beispielsweise ein HUD-Overlay in Ihrer Szene erstellen möchten, sollten Sie einfach ein Screen-Quad-Objekt mit einer geeigneten transparenten Textur erstellen und dieses zuletzt zu Ihrer Szene hinzufügen.

Wenn Sie die SRC- und DST-Mischfunktionen für transparente Objekte festlegen, erhalten Sie auf viele verschiedene Arten Zugriff auf die vorherige Mischung.

Sie können die Alpha-Eigenschaft Ihrer Ausgabefarbe hier verwenden, um wirklich zu mischen. Dies ist der effizienteste Weg, um auf Framebuffer-Ausgaben (Pixel) zuzugreifen, da es in einem einzigen Durchgang (Fig. 1) der GPU-Pipeline arbeitet.

enter image description here
Abb. 1 - Single Pass

Wenn Sie wirklich brauchen multi pass (Abb. 2), dann müssen Sie die Framebuffer-Ausgänge auf eine zusätzliche Textureinheit zielen nicht auf den Bildschirm, und Kopieren Sie diese Zieltextur in den nächsten Durchgang und richten Sie sie so auf den Bildschirm im letzten Durchgang aus. Jeder Durchlauf erfordert mindestens zwei Kontextwechsel.

Das zusätzliche Kopieren und Kontextwechsel verschlechtert die Renderleistung erheblich. Beachten Sie, dass Multi-Thread-GPU-Pipelines hier nicht viel helfen, da Multi-Pass inhärent serialisiert wird.

enter image description here
Abb. 2 - Multi Pass

Ich habe eine verbale Beschreibung mit Pipeline-Diagramme umsortiert deprecation, da Shader Language (Abkürzung/GLSL) zu vermeiden, kann sich ändern.

Verwandte Themen