Shader Hintergrundfarbe ignorierenn
-
Hallo zusammen,
ich bin im Moment dabei ein Programm in Anaglyphen zu schreiben. Es sieht soweit auch super aus.
An den Rändern der Objekte stehen an der einen Seite blaue und an der anderen Seite rote Stücke über.Mein Problem bei der Sache ist, dass wenn ein Objekt komplett vor einem anderen liegt und ich die Hintergrundfarbe ändere (glClearColor), dann bleiben die Farben bestehen.
Allerdings wenn ein Objekt sozusagen direkt auf dem Hintergrund liegt, ändert sich das blau zu rot und das rot zu blau, wenn ich den Hintergrund von schwarz auf weiß ändere.
Ich möchte gerne, dass die Farben bestehen bleiben. Also die Hintergrundfarbe nicht mit einberechnet wird.
Das ganze geschieht wie folgt.
Ich rendere in 2 verschiedene Texturen. Einmal für das linke Auge und einmal für das rechte Auge.
Anschließend wende ich folgenden Shader an:uniform sampler2D left; uniform sampler2D right; void main(void) { vec4 cleft = texture2D(left, gl_TexCoord[0].st).rgba; vec4 cright = texture2D(right, gl_TexCoord[0].st).rgba; vec3 col; col.r = (cleft.r + cleft.g + cleft.b) / 3.0; col.g = 0.0; col.b = (cright.r + cright.g + cright.b) / 3.0; gl_FragColor = vec4(col, cleft.a+cright.a); }
und binde die texturen dann an ein Fullscreen-Quad.
Ich habe schon probiert das blending auszuschalten und mit verschiedenen Alpha-Werten zu arbeiten, aber habe nie das erreicht was ich gerne möchte.
Ich hoffe hier kann mir jemand einen Tipp geben.Zum Verständnis nochmal ein Bild. Links mit weißen Hintergrund, rechts mit schwarzem.
http://img651.imageshack.us/i/redblue.png/Wie man sehen kann bei dem Würfel in der Mitte ändern sich die "Randfarben" nicht. Allerdings bei der hinteren größeren Textur. Und zwar dort, wo sie den Hintergrund überlappt.
Danke schonmal!
-
Hast du die Vertices nach z-order sortiert? Das musst du bei Blending nämlich machen, sonst hast du genau diesen Effekt :). Bitte von hinten nach vorne zeichnen.
-
Wieso von hinten nach vorne zeichnen?
Wie sortiert man das denn? Vielleicht hab ich es ja gemacht aber nicht bewusst.Das was ich möchte geht also nur mittels Blending?
Also wenn ich es ausschalte geht es auf keinen Fall?
-
Nein, du hattest nur gesagt dass du Blending verwendest. Und da muss man die Vertices von hinten nach vorne sortieren, bzw alles was "tiefer" im Bildschirm drin liegt zuerst zeichnen.
Ansonsten sollte dem Shader die Hintergrundfarbe egal sein und sich das nicht vermischen.
-
Ok. Und wenn ich kein Blending benutze.
Was mach ich dann falsch?Mit Hintergrund meine ich auch den Hintergrund von den Objekten das dann alles in die Textur gerendert wurde.
-
die.krone schrieb:
Ok. Und wenn ich kein Blending benutze.
Was mach ich dann falsch?Mit Hintergrund meine ich auch den Hintergrund von den Objekten das dann alles in die Textur gerendert wurde.
Jetzt hast du mich verloren. Ich verstehe nicht ganz was du erreichen willst.^^
-
Das ist eigentlich nicht so schwer
Also wenn du dir das Bild anschaust, was ich gepostet habe.
Darauf sind ja die beiden Texturen zu sehen in die ich gerendert habe + den angewandten Shader.Auf dem linken Bild ist der Hintergrund von den Objekten die in die Textur gerendert werden weiß. Durch den Shader dann jetzt pink.
Auf dem rechten Bild ist der Hintergrund der Objekte schwarz.Und von dem hinteren Quad mit der Textur die einer Weltkarte ähnelt. Dort sieht man auf dem linken Bild, dass auf der linken Seite, sozusagen am Rand des Quads, ein Stück übersteht, was blau ist. Und am rechten Rand des Quads ein Stück was rot ist. Das ist bei weißem Hintergrund!
Und auf dem rechten Bild ist es umgekehrt. Am linken Rand ist ein Stück rot und am rechten ein Stück blau.
Was ich möchte ist, dass es gleich ist egal ob die Hintergrundfarbe weiß, schwarz oder sonstwie ist.
Aber ich weiß nicht wie ich es ausschalten kann oder was ich falsch mache, dass es so ist wie es ist
Ich hab halt schon einiges gelesen und Tipps bekommen. Zum Beispiel, dass man das Blending ganz ausschalten soll und es dann klappt. Aber ich habe standardmäßig gar kein Blending eingeschaltet.
Egal ob Blending ein oder aus, es gab nie den gewünschten Effekt. Vielleicht muss ich auch einen speziellen Modus oder so wählen.Das ist eben meine Frage. Wie krieg ich es hin, dass unabhängig von der Hintergrundfarbe die Ränder die am Quad überstehen immer die gleiche Farbe besitzen.
-
Ich würde das wie folgt machen:
Szene zweimal in voller Farbenpracht (Echtfarben) in eine Textur rendern. Dann den Composit-Shader aktivieren und ein Fullscreen-Quad zeichnen.
Ich vermute einfach mal du machst das über Framebuffer, dann sieht dein Renderpfad in Pseudocode ca. so aus:glBindFramebuffer( GL_FRAMEBUFFER, iFBLinkesAuge ); glClearColor( RGB | ALPHA ); translate_scene( posLinkesAuge ); RenderScene(); glBindFramebuffer( GL_FRAMEBUFFER, iFBRechtesAuge ); glClearColor( RGB | ALPHA ); translate_scene( posRechtesAuge ); RenderScene(); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); glClearColor( RGB | ALPHA ); BindLeftEyeTexture(); BindRightEyeTexture(); EnableShader( SHADER_COMPOSIT ); DrawFullscreenQuad(); glSwapBuffers();
Ich verstehe eigentlich auch nicht wo das Problem ist. Mit Blending hat das nichts zu tun, du colorierst deine fertigen Scene-Bilder ganz einfach mit deinem Fragment-Shader.
AHA: habe mir gerade mal deinen Shader nochmal genauer angeguckt.gl_FragColor = vec4(col, cleft.a+cright.a);
Du gibst in deinem Fragment Shader alpha Werte mit aus. Das sollte man nur bei wirklich (teil-)transparenten Objekten machen.
Versuch mal folgendes:gl_FragColor = vec4(col, 1.0);
-
Danke, ich probiere es mal.
Nein ich mache das nicht über den Framebuffer. Das Rendern in die Textur für das linke Auge sieht zB so aus:
glActiveTexture(GL_TEXTURE0); /* Define a view-port adapted to the texture */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); //frustum for left eye glFrustum(L_l, L_r, L_b, L_t, Near, Far); glViewport(0, 0, SIZE, SIZE); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(-IOD / 2, 0.0, 5.0, /* eye is at (0,0,5) */ 0.0, 0.0, 0.0, /* center is at (0,0,0) */ 0.0, 1.0, 0.); /* up is in positive Y direction */ /* Render to buffer */ // glClearColor(1, 1, 1, 0); glClearColor(background_color, background_color, background_color, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glScalef(zoom, zoom, zoom); drawCubes(); drawBackground(); glFlush(); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, leftTexture); /* Copy buffer to texture */ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, SIZE, SIZE);
Vorher in meiner init-Methode mache ich aber noch:
glBindTexture(GL_TEXTURE_2D, leftTexture); glTexImage2D(GL_TEXTURE_2D, 0, 4, SIZE, SIZE, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, textureL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glGenTextures(1, &rightTexture); glBindTexture(GL_TEXTURE_2D, rightTexture); glTexImage2D(GL_TEXTURE_2D, 0, 4, SIZE, SIZE, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, textureR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, leftTexture); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, rightTexture); setShaders(); texLeftSampler = glGetUniformLocation(program, "left"); glUniform1i(texLeftSampler, 1); ...
Und analog eben das fürs rechte Auge. Vielleicht liegt dort ja auch mein Fehler irgendwo.
-
Versuch mal anstatt
glClearColor(background_color, background_color, background_color, 0.0);
folgendes:
glClearColor(background_color, background_color, background_color, 1.0);
Zu allererst würde ich aber mal den Shader so verändern dass er wirklich nur jeweils das Bild für ein Auge ausgibt. Dann kannst du besser kontrollieren ob das gewünschte Ergebnis erreicht wird.
-
Also das richtige Ergebnis für links und rechtes Auge krieg ich:
http://img862.imageshack.us/i/rbleftright.png/Und wenn ich einzeln die Farbe des Hintergrundes ändere, bleibt auch die Farbe der Textur gleich und wechselt nicht.
Nur zusammen geht es nicht. Ich bin echt überfragt.
Das Alpha 1.0 hat gar nichts gebracht.
-
Hast du die Ergebnisse für die Augen per Fragment-Shader ausgegeben oder per Code?
Wenn du sie per Shader einzeln ausgibst und sie dann korrekt sind muss der Fehler im Shader liegen.
-
Hab sie über den Shader ausgegeben.
Also zBuniform sampler2D left; uniform sampler2D right; void main(void) { vec3 cleft = texture2D(left, gl_TexCoord[1].st).rgb; vec3 cright = texture2D(right, gl_TexCoord[2].st).rgb; vec3 col; col.r = (cleft.r + cleft.g + cleft.b) / 3.0; col.g = 0.0; col.b = (cright.r + cright.g + cright.b) / 3.0; gl_FragColor = vec4(vec3(col.rg,1.0), 1.0);
-
Die Ergebnisse sind doch völlig klar und nachvollziehbar.
Weisser Hintergrund (bezieht sich auf die Hintergrundfarbe beim erstelleln der beiden Texturen) http://img651.imageshack.us/i/redblue.png/, also linkes Bild:
Du versetzt ja beim erstellen der beiden Texturen ein wenig die Sicht, das heisst natürlich, dass die Position der beiden Objekte innerhalb der beiden Texturen ebenfalls versetzt ist.
Betrachten wir den linken blauen Rand - wie kommt der zustande?
An diesen Stellen hat Textur1 schwarze Farbwerte (nämlich die Farbwerte der "Weltkarte") wohingegen Textur2 weisse Farbwerte hat (Hintergrundfarbe beim erstellen der Textur).Im Shader addierst du die Komponenten des Farbwertes der Textur1 auf und speicherst das Ergebniss als Rot-Komponente. Die Rot-Komponente ist also 0.
Nun addierst du die Farbwertkomponenten der Textur2 und speicherst das Ergebnis als Blau-Komponente -> 1
Resultierende Farbe also: (0.0,0.0,1.0) -> BlauNehmen wir an die Hintergrundfarbe war schwarz:
Rot-Komponente bleibt natürlich 0, da ja hier der Farbwert der Weltkarte benutzt wurde, Blau-Komponente wird ebenfalls 0.
Resultierende Farbe also (0.0,0.0,0.0) -> SchwarzWie kommt es nun, dass du meinst dass dort der rote Balken wäre? Schau mal genau hin. Nicht die Stellen sind rot, die im ersten Fall blau waren, sondern es sind die Stellen rot, die im ersten Fall pink waren.
Grund: An diesen Stellen war in Textur1 die Farbe weiss anstelle von schwarz. Im ersten Fall wurde also die resultierende Rot-Komponente auf 1.0 (weil Farbwert der Weltkarte hier weiss war) gesetzt und die Blau-Komponente ebenfalls auf 1.0 (weil Hintergrundfarbe weiss war) -> (1.0,0.0,1.0)
Im zweiten Fall wird hier die resultiernde Rot-Komponente wieder 1.0 sein (s.o.) und die Blau-Komponente 0 (weil ja die Hintergrundfarbe schwarz ist) -> (1.0,0.0,0.0)Was du eigentlich möchtest ist doch, dass die Hintergrundfarbe beim erstellen der Texturen übehraupt keine Rolle spielt. Also setzt du den Alpha-Wert der Hintergrundfarbe auf 0.
Im shader überprüfst du nun, ob der Alphawert 0 ist oder nicht und nur im letzten Fall addierst du die Farbkomponenten auf und setzt den entsprechenden Kanal.
-
Du meinst also, wenn der Alpha-Wert 0 wäre, müsste das dann so im Shader aussehen:
uniform sampler2D left; uniform sampler2D right; void main(void) { vec3 cleft = texture2D(left, gl_TexCoord[1].st).rgb; vec3 cright = texture2D(right, gl_TexCoord[2].st).rgb; vec3 col; col.r = cleft.r; col.g = 0.0; col.b = cright.b; gl_FragColor = vec4(col, 1.0);
Hab ich das so richtig verstanden?
Danke für die Hilfe!
-
Nicht ganz.
Hm - wie erklär ich das nun.Momentan gehst du ja folgendermassen vor:
- du erstellst beide Texturen (offscreen rendering), wobei der Blickwinkel leicht versetzt ist (für linkes Auge + rechtes Auge).
- dann erstellst du ein fullscreen-quad und möchtest nun die Farbwerte der beiden Texturen vereinen und damit dann das quad texturieren.Dabei ist eigentlich die Hintergrundfarbe, die beim erstellen der beiden Texturen verwendet wurde, uninteressant und nicht erwünscht. Momentan berücksichtigst du sie aber noch - daher wird das Resultat auch so pink bei dir, was vermutlich so nicht sein sollte.
Was du nun machen könntest ist folgendes:
Während du die texturen erstellst setzt du die Hintergrundfarbe auf einen beliebegen Farbwert, aber der Alpha-Wert sollte 0 sein (bsp: glClearColor(1.0f,1.0f,1.0f,0.0f))
Alle anderen Farbinformationen sollten allerdings dann einen Alphawert ungleich 0 haben.Deinem shader, der nun die Farbwerte kombiniert würde in etwa folgendermassen aussehen:
uniform sampler2D left; uniform sampler2D right; void main(void) { vec4 cleft = texture2D(left, gl_TexCoord[0].st); vec4 cright = texture2D(right, gl_TexCoord[0].st); vec3 col(0.0); // falls sowohl in Textur1 als auch in Textur2 der Hintergrund sichtbar ist: if (cleft.a == 0.0 && cright.a == 0.0) { // entweder discard; oder konstante Farbe setzten } else { // falls texel in Textur1 einen Alphawert ungleich 0 hat -> blau-Kanal setzen if (cleft.a != 0) { col.b = (cleft.r + cleft.g + cleft.b) / 3.0; } // falls texel in Textur2 einen Alphawert ungleich 0 hat -> rot-Kanal setzen if (cright.a != 0){ col.r = (cright.r + cright.g + cright.b) / 3.0; } } gl_FragColor = vec4(col, 1.0); }
-
Okay. Aber was genau meinst du mit discard und wie mache ich das?
Dass würde doch dann heißen, dass wenn der Alphawert beider Texturen 0 ist, der Hintergrund nicht miteinbezogen wird oder?
-
discard verwirft das aktuelle Fragment - sprich, sobald der Fragment-Shader auf discard trifft, wird die Ausführung des shaders beendet und das Fragment verworfen (also es werden keine neuen Werte in den framebuffer / oder sonstige target-buffer geschrieben).
Richtig, wenn beide texel einen alpha-Wert von 0 haben würde dann im framebuffer weiterhin der von dir durch glClearColor festgelegte Wert stehen (also die Hintergrundfarben der Texturen würden nicht berücksichtigt). Auch in den depthbuffer wird kein Wert eingetragen.
-
Das Schlüsselwort discard verwirft den pixel. Das meint er damit :).
-
Kann mir jemand sagen, wieso ich keine RGBA textur verwenden kann.
Wenn ich folgendes schreibe,kriege ich immer ein "Segmentation fault".glTexImage2D(GL_TEXTURE_2D, 0, 4, SIZE, SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureL);
Verwende ich nur GL_RGB klappt es wunderbar.