Negeatives Blending, oder Blending rückgängig machen.



  • Ich habe, dass Problem, dass ich nachdem die Sky-Box gezeichnet wurde, Reflektionen zeichnen möchte und dafür die Blendingfunktion nutze. Das Problem, ist aber, dass die Skybox zuerst gezeichnet werden muss und dann das spiegelnde Objekt halt teilweise von Skybox umgefärbt wird.
    Wie kann ich das umgehen?

    if(m_eRendermode == REFLECTIVE_STENCIL) {
    		if(m_SceneGraphItems[0]->m_eMaterial == SKY)
    			m_SceneGraphItems[0]->RenderItem();
    
    		for(unsigned int i = 0; i < m_ReflectSceneGraphItems.size(); i++) {
    			SceneGraphItem *reflItem = m_ReflectSceneGraphItems.at(i);
    			for(unsigned int j = 0; j < m_SceneGraphItems.size(); j++) {
    				SceneGraphItem *item = m_SceneGraphItems.at(j);
    
    				if(reflItem->m_iSceneIdentifier == item->m_iSceneIdentifier || item->m_eMaterial == SKY)
    					continue;
    
    				glEnable(GL_STENCIL_TEST); 			//Enable using the stencil buffer
    				glColorMask(0, 0, 0, 0); 			//Disable drawing colors to the screen
    				glDisable(GL_TEXTURE_2D);
    				glDisable(GL_DEPTH_TEST); 			//Disable depth testing
    				glStencilFunc(GL_ALWAYS, 1, 1); 	//Make the stencil test always pass
    				glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);	//Make pixels in the stencil buffer be set to 1 when the stencil test passes
    					reflItem->RenderItem();
    				glColorMask(1, 1, 1, 1); 			//Enable drawing colors to the screen
    				glEnable(GL_DEPTH_TEST); 			//Enable depth testing
    				glDisable(GL_TEXTURE_2D);
    				glStencilFunc(GL_EQUAL, 1, 1);		//Make the stencil test pass only when the pixel is 1 in the stencil buffer
    				glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); 	//Make the stencil buffer not change
    					/* Draw the cube, reflected vertically, at all pixels where the stencil *
    					 * buffer is 1                                                          */
    					glPushMatrix();
    						/*
    						 * VERTICAL REFLECTION
    						 * calculate reflection relative to both objecs positions
    						 */
    						glScalef(1, -1, 1);
    
    						Vec3f reflectionPos = item->GetPosition();
    						reflectionPos.y -=  (reflItem->GetPosition().y - item->GetPosition().y)*2;
    
    						glTranslatef(reflectionPos.x, reflectionPos.y, reflectionPos.z);
    						glRotatef( 	item->GetRotationAngle(),
    									item->GetRotationAxis().x,
    									item->GetRotationAxis().y,
    									item->GetRotationAxis().z );
    
    						item->Draw();
    					glPopMatrix();
    				glDisable(GL_STENCIL_TEST); //Disable using the stencil buffer
    			}
    			glEnable(GL_BLEND);
    				glColor4f(1, 1, 1, 0.7f);
    				reflItem->RenderItem();
    			glDisable(GL_BLEND);
    		}
    		for(unsigned int i = 0; i < m_SceneGraphItems.size(); i++) {
    			if(	m_SceneGraphItems.at(i)->m_eMaterial != REFLECTIVE_STENCIL &&
    				m_SceneGraphItems.at(i)->m_eMaterial != SKY )
    
    				m_SceneGraphItems.at(i)->RenderItem();
    		}
    	}
    


  • Das Result des Blendings ist gar nicht so verkehrt, weil die Skybox (Cubemap?) selbst ja auch im "spiegelnden Objekt" reflektiert wird.
    Fuelle das (offenbar planare?) Objekt doch einfach zunaechst mit Reflection-Texgen (damit im Spiegel der "korrekte" Teil der Skybox zu sehen ist).



  • ich überspringe beim zeichnen im moment die skybos, weil es merkwürdige fehler gibt, wenn ich zwei reflektierende objekte habe. Die Skybox wird dann nur noch in das eine objekt gerendert. was auch nahe liegt, wenn das objekt den ganzen bildschirm einnimmt.
    Darum habe ich die skybox aus dem stenciltest erstmal rausgenommen. das problem was ich aber jetzt habe, ist das diese box vor allem gerendert wird und die spiegelnde fläche durch das blending transparent wirkt, was sie aber nicht sein muss.
    irgendwie ist das ne recht verzewickte angelegenheit und ich weis nicht so genau was du meinst.



  • Wenn Ich Dich richtig verstanden habe renderst Du zuerst die Skybox, setzt dann fuer die Spiegelflaeche den Stencil, renderst die gespiegelten Objekte (sofern der Stenciltest erfuellt ist) und danach die (transparente) Spiegeloberflaeche - jetzt stoert Dich, dass in der Spiegelflaeche noch die Skybox zu sehen ist.

    Dann fuell die Spiegelflaeche (in einem Durchgang mit dem Stencil) doch einfach schwarz (bzw "Spiegelgrundfarbe", eben das was im Spiegel zu sehen ist wenn sich kein Objekt drin spiegelt - eigentlich die Skybox) - dann ist die "falsche" Skybox wieder weg. Z-Write muss dabei aus.

    Wenn Du mehrere Spiegel hast musst Du jedem ein eindeutiges Stencilbit zuweisen und per Stencilmask pruefen.



  • Ach irgendwie ist die Blendingfunktion in dem Fall einfach nicht richtig zu gebrauchen, die Skybox wird nicht richtig reflektiert und als Hintergrund einfach über die Blendingfunktion vermischt.
    Kann man die Scene ohne Skybox rendern das Ergebnis zwischenspeichern und dann nach dem Rendern der Skybox wieder einfügen?

    -Die Reihenfolge bisher:
    - Skybox wird gerendert
    - Danach werden alle Objekte die Reflektiert werden sollen als Reflektion gezeichnet und die Reflektierenden Objekte auch
    - Zum Schluss male ich die Objekte selbst

    Also selbst wenn ich die Reflektion für die Skybox abschalte, wird sie immer mit zwischengeblendet.
    Die lösung wäre ja, die skybox zum schluss zu zeichnen, aber leider geht das wieder nicht, weil die box, sonst alles übermalt. darum dachte ich an das zwischenspeichern.

    http://img176.imageshack.us/img176/258/bildschirmfoto6qi7.th.jpg

    die skybox ist eine art cubemap, aber ich verstehe nicht, warum die nicht richtig reflektiert wird. das Ergebnis der Reflektion der skybox ist anscheinend gleich dem blending. Anstatt den Himmel zu rendern wenn ich daruf gucke, wird der Boden gerendert (also wie transparenz)

    void SkyBoxItem::DrawSkyBox() {
    	// if one texture isn't initialised, break rest of function
    
    	for(unsigned int i = 0; i < m_iSkyBoxT.size(); i++)
    		if(m_iSkyBoxT.at(i) == 0) {
    			//std::cout<<"break drawing the sky"<<std::endl;
    			glColor4f(0.50f, 1.0f, 0.0f, 1.0f);
    			return;
    		}
    
    	// Store the current matrix
    	glPushMatrix();
    	// Reset and transform the matrix.
    	glLoadIdentity();
    	// do not rotate the skybos if camera looks around
    	glRotatef(-m_pParentScene->m_pParentGraph->GetCamera()->GetRotationX(), 1.f, 0.f, 0.f);
    	glRotatef(-m_pParentScene->m_pParentGraph->GetCamera()->GetRotationY(), 0.f, 1.f, 0.f);
    	glRotatef(-m_pParentScene->m_pParentGraph->GetCamera()->GetRotationZ(), 0.f, 0.f, 1.f);
    
    	// Enable/Disable features
        glEnable(GL_TEXTURE_2D);
    	glPushAttrib(GL_ENABLE_BIT);
    	glDisable(GL_DEPTH_TEST);
    	glDisable(GL_LIGHTING);
    	//glEnable(GL_BLEND);
    
    	// Common Axis Z - FRONT Side
    	// Render the front quad
    	glBindTexture(GL_TEXTURE_2D, m_iSkyBoxT[0]);
    	glBegin(GL_QUADS);
    	glTexCoord2f(0, 0); glVertex3f(  0.5f, -0.5f, -0.5f );
    	glTexCoord2f(1, 0); glVertex3f( -0.5f, -0.5f, -0.5f );
    	glTexCoord2f(1, 1); glVertex3f( -0.5f,  0.5f, -0.5f );
    	glTexCoord2f(0, 1); glVertex3f(  0.5f,  0.5f, -0.5f );
    	glEnd();
    
    	// Render the left quad
    	glBindTexture(GL_TEXTURE_2D, m_iSkyBoxT[1]);
    	glBegin(GL_QUADS);
    	glTexCoord2f(0, 0); glVertex3f(  0.5f, -0.5f,  0.5f );
    	glTexCoord2f(1, 0); glVertex3f(  0.5f, -0.5f, -0.5f );
    	glTexCoord2f(1, 1); glVertex3f(  0.5f,  0.5f, -0.5f );
    	glTexCoord2f(0, 1); glVertex3f(  0.5f,  0.5f,  0.5f );
    	glEnd();
    
    	// Render the back quad
    	glBindTexture(GL_TEXTURE_2D, m_iSkyBoxT[2]);
    	glBegin(GL_QUADS);
    	glTexCoord2f(0, 0); glVertex3f( -0.5f, -0.5f,  0.5f );
    	glTexCoord2f(1, 0); glVertex3f(  0.5f, -0.5f,  0.5f );
    	glTexCoord2f(1, 1); glVertex3f(  0.5f,  0.5f,  0.5f );
    	glTexCoord2f(0, 1); glVertex3f( -0.5f,  0.5f,  0.5f );
    	glEnd();
    
    	// Render the right quad
    	glBindTexture(GL_TEXTURE_2D, m_iSkyBoxT[3]);
    	glBegin(GL_QUADS);
    	glTexCoord2f(0, 0); glVertex3f( -0.5f, -0.5f, -0.5f );
    	glTexCoord2f(1, 0); glVertex3f( -0.5f, -0.5f,  0.5f );
    	glTexCoord2f(1, 1); glVertex3f( -0.5f,  0.5f,  0.5f );
    	glTexCoord2f(0, 1); glVertex3f( -0.5f,  0.5f, -0.5f );
    	glEnd();
    
    	// Render the top quad
    	glBindTexture(GL_TEXTURE_2D, m_iSkyBoxT[4]);
    	glBegin(GL_QUADS);
    	glTexCoord2f(1, 1); glVertex3f( -0.5f,  0.5f, -0.5f );
    	glTexCoord2f(0, 1); glVertex3f( -0.5f,  0.5f,  0.5f );
    	glTexCoord2f(0, 0); glVertex3f(  0.5f,  0.5f,  0.5f );
    	glTexCoord2f(1, 0); glVertex3f(  0.5f,  0.5f, -0.5f );
    	glEnd();
    
    	// Render the bottom quad
    	glBindTexture(GL_TEXTURE_2D, m_iSkyBoxT[5]);
    	glBegin(GL_QUADS);
    	glTexCoord2f(1, 0); glVertex3f( -0.5f, -0.5f, -0.5f );
    	glTexCoord2f(0, 0); glVertex3f( -0.5f, -0.5f,  0.5f );
    	glTexCoord2f(0, 1); glVertex3f(  0.5f, -0.5f,  0.5f );
    	glTexCoord2f(1, 1); glVertex3f(  0.5f, -0.5f, -0.5f );
    	glEnd();
    
    	// Restore enable bits and matrix
    	glDisable(GL_TEXTURE_2D);
    	//glDisable(GL_BLEND);
    	glPopAttrib();
    	glPopMatrix();
    }
    

  • Mod

    gentoo schrieb:

    Ich habe, dass Problem, dass ich nachdem die Sky-Box gezeichnet wurde, Reflektionen zeichnen möchte und dafür die Blendingfunktion nutze. Das Problem, ist aber, dass die Skybox zuerst gezeichnet werden muss und dann das spiegelnde Objekt halt teilweise von Skybox umgefärbt wird.
    Wie kann ich das umgehen?

    ich verstehe leider nicht was du sagen willst.
    du zeichnest erst die skybox und dann reflektionen, wie soll die skybox dann noch einfluss nehmen wenn sie vorher gezeichnet wurde.
    wieso verwendest du blending bei reflektionen?

    dein screenshot sieht nett aus, aber ich weiss nicht was daran falsch sein soll. soll das ein objekt unter wasser darstellen? dann sieht es doch garnicht so falsch aus 😕



  • ich beschreibs mal an hand des screenshots:

    - erst mal ich die skybox (sieht man ja)
    - dann male ich die reflektierten torus' (über stencil puffer)
    - dann male ich die zwei torus' als objekt oben drüber
    - danach blende ich den spiegel ein (soll ein interpoliertes bild aus dem spiegel und den objekten sein die über den stencil puffer gemalt wurden ==> reflektionen)

    du zeichnest erst die skybox und dann reflektionen, wie soll die skybox dann noch einfluss nehmen wenn sie vorher gezeichnet wurde.

    die skybox wird in diesem beispiel nicht reflektiert, ich habes nur mal ausprobiert indem ich das eine

    if(item->m_eMaterial == SKY)
    

    ausgelassen habe. macht aber schwierigkeiten, die ich später angehen wollte. ist also für meine frage nicht so von bedeutung.

    wieso verwendest du blending bei reflektionen?

    wie soll ich die reflektierten objekte sonst auf den bereich des spiegels bringen?
    ich wäre sehr dankbar wenn du den code evtl. anpasst, so dass er ohne blending läuft - oder für andere ratschläge.

    dein screenshot sieht nett aus, aber ich weiss nicht was daran falsch sein soll. soll das ein objekt unter wasser darstellen? dann sieht es doch garnicht so falsch aus 😕

    da sind wir wieder beim blending, wenn man genau hinguckt, sieht man die skybox durchschimmern.
    Das soll nicht sein. es sollen im prinzip nur die beiden torus' gespiegelt werden. das problem ist aber, dass die skybox halt gerendert wird bevor ich das blending aufrufe und damit wird dann die skybox durchgeblendet. das lässt das obejt zwangsweise durchsichtig erscheinen und das möchte ich nicht.

    deshalb bin ich so scharf auf nen tipp wie ich die szene ohne blending rendere (wie du angemerkt hast, mit anderem beweggrund denke ich) oder das was in der schleife steht irgendwie zwischenzuspeichern und dann nach dem rendern der skybox anzuzeigen, wenn das geht ):

    naja man merkt ich bin relativ neu im bereich opengl. irgendwie sind die ganzen funktionen auch ziemlich unübersichtlich.

    ich glaube ich erkläre auch mal den code unten, dass keiner durcheinander kommt:

    Hier werden erst die reflektierenden objekte durchgelaufen (spiegel im bild) und dann werden alle objekte, die in der scene sind, außer der skybox und dem spiegelndem spiegel 😛 selbst, über den stencilpuffer gerendert.

    for(unsigned int i = 0; i < m_ReflectSceneGraphItems.size(); i++) {
                SceneGraphItem *reflItem = m_ReflectSceneGraphItems.at(i);
                for(unsigned int j = 0; j < m_SceneGraphItems.size(); j++) {
                    SceneGraphItem *item = m_SceneGraphItems.at(j);
    
    if(reflItem->m_iSceneIdentifier == item->m_iSceneIdentifier || item->m_eMaterial == SKY)
                        continue;
    

    hier setze ich die schablone in die gerendert wird:

    glEnable(GL_STENCIL_TEST);             //Enable using the stencil buffer
                    glColorMask(0, 0, 0, 0);             //Disable drawing colors to the screen
                    glDisable(GL_TEXTURE_2D);
                    glDisable(GL_DEPTH_TEST);             //Disable depth testing
                    glStencilFunc(GL_ALWAYS, 1, 1);     //Make the stencil test always pass
                    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);    //Make pixels in the stencil buffer be set to 1 when the stencil test passes
                        reflItem->RenderItem();
    

    reflektionen müssen noch verschoben werden.

    glColorMask(1, 1, 1, 1);             //Enable drawing colors to the screen
                    glEnable(GL_DEPTH_TEST);             //Enable depth testing
                    glDisable(GL_TEXTURE_2D);
                    glStencilFunc(GL_EQUAL, 1, 1);        //Make the stencil test pass only when the pixel is 1 in the stencil buffer
                    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);     //Make the stencil buffer not change
                        /* Draw the cube, reflected vertically, at all pixels where the stencil *
                         * buffer is 1                                                          */
                        glPushMatrix();
                            /*
                             * VERTICAL REFLECTION
                             * calculate reflection relative to both objecs positions
                             */
                            glScalef(1, -1, 1);
    
                            Vec3f reflectionPos = item->GetPosition();
                            reflectionPos.y -=  (reflItem->GetPosition().y - item->GetPosition().y)*2;
    
                            glTranslatef(reflectionPos.x, reflectionPos.y, reflectionPos.z);
                            glRotatef(     item->GetRotationAngle(),
                                        item->GetRotationAxis().x,
                                        item->GetRotationAxis().y,
                                        item->GetRotationAxis().z );
    
                            item->Draw();
                        glPopMatrix();
                    glDisable(GL_STENCIL_TEST); //Disable using the stencil buffer
    

    dieses gerenderte bild wird dann mit dem spiegelobjek selbst vermischt:

    glEnable(GL_BLEND);
                    glColor4f(1, 1, 1, 0.7f);
                    reflItem->RenderItem();
                glDisable(GL_BLEND);
            }
            for(unsigned int i = 0; i < m_SceneGraphItems.size(); i++) {
                if(    m_SceneGraphItems.at(i)->m_eMaterial != REFLECTIVE_STENCIL &&
                    m_SceneGraphItems.at(i)->m_eMaterial != SKY )
    
                    m_SceneGraphItems.at(i)->RenderItem();
            }
    


  • Also das Ding mit der Mauertextur(!) soll der Spiegel sein und das mit der Wassertextur(!) die Skybox? Das soll einer raffen... 😉
    Wie gesagt: Wenn keine (falsche) Skybox imSpiegel zu sehen sein soll dann fuell' den Spiegel vorher einfach ohne Z-Write schwarz - dann ist sie weg 🙂



  • das würde nur das spiegeln eines objektes verhindern, aber nicht das durchscheinen des hintergrundes des hintergrundes allgemein. oder ich habe das falsch verstanden.



  • Aber wenn der Hintergrund nicht mehr da ist, kann er auch nicht mehr durchscheinen.



  • ja genau, darum vermute ich, das der fehler wohl etwas mit dem drehen der skybox zu tun hat.

    im prizip ist es auch nicht soo wichtig die skybox zu spiegeln aber bissel komisch ist der fehler trotzdem. mich hatte das anfangs ziemlich verwirrt, da die beiden fehler das selbe resultat haben, aber unterschiedlich ursprünge haben müssen.


Anmelden zum Antworten