Sign in to follow this  
fazekaim

how to render water reflection

Recommended Posts

Hello, I tried to create water reflection. I made my render-to-texture code with framebuffer object:
public void reshape(GLDrawable glDrawable, int xstart,int ystart, int width, int height) {
        gl.glViewport(0,0,width,height);
        gl.glMatrixMode( GL.GL_PROJECTION);
        gl.glLoadIdentity();

        createNewFrameBuffer( width, height, MeadowLand.FBO, MeadowLand.FBORenderBuffer, MeadowLand.FBOTexture );

        gluPerspective(45,(double)width/height,1,10000);

        gl.glMatrixMode( GL.GL_MODELVIEW);
        gl.glLoadIdentity();
    }
public static void createNewFrameBuffer(int width, int height, int[] FBO, int[] FBORenderBuffer, int[] FBOTexture ){

        if( FBO[0] > 0) gl.glDeleteFramebuffersEXT( 1, FBO  );
        if( FBOTexture[0] > 0) gl.glDeleteTextures( 1, FBOTexture  );

        gl.glGenFramebuffersEXT( 1, FBO  );
        gl.glGenTextures( 1, FBOTexture );
        gl.glBindFramebufferEXT( GL.GL_FRAMEBUFFER_EXT, FBO[0] );

        gl.glGenRenderbuffersEXT( 1, FBORenderBuffer );
        gl.glBindRenderbufferEXT( GL.GL_RENDERBUFFER_EXT, FBORenderBuffer[0] );
        gl.glRenderbufferStorageEXT( GL.GL_RENDERBUFFER_EXT, GL.GL_DEPTH_COMPONENT24, width, height );
        gl.glFramebufferRenderbufferEXT( GL.GL_FRAMEBUFFER_EXT, GL.GL_DEPTH_ATTACHMENT_EXT, GL.GL_RENDERBUFFER_EXT, FBORenderBuffer[0] );

        gl.glBindTexture( GL.GL_TEXTURE_2D, FBOTexture[0] );
        gl.glTexImage2D( GL.GL_TEXTURE_2D, 0, GL.GL_RGB, width, height, 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, BufferUtils.bufferOffset(0) );
        gl.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST );
        gl.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST );
        gl.glFramebufferTexture2DEXT( GL.GL_FRAMEBUFFER_EXT, GL.GL_COLOR_ATTACHMENT0_EXT, GL.GL_TEXTURE_2D, FBOTexture[0], 0 );

        if( !checkFrameBufferStatus( width, height ) ){
            JOptionPane.showMessageDialog(null, "FBO ohhh", "Some Error", JOptionPane.ERROR_MESSAGE);
            System.exit( -1 );
        }
        gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);

    }


My render code:
            gl.glBindFramebufferEXT( GL.GL_FRAMEBUFFER_EXT, FBO[0] );
            gl.glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
            gl.glClear( GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
            gl.glPushMatrix();
                gl.glScalef( 1.0f, -1.0f, 1.0f );
                renderScene();
            gl.glPopMatrix();

            gl.glBindFramebufferEXT( GL.GL_FRAMEBUFFER_EXT, 0 );
            gl.glClearColor(0.0f, 1.0f, 0.0f, 0.0f);
            gl.glClear( GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT );
            gl.glPushMatrix();
                renderscene();
                renderWater();
            gl.glPopMatrix(); 

....
public void renderWater() {

        gl.glEnable( GL.GL_DEPTH_TEST);
        gl.glEnable(GL.GL_MULTISAMPLE_ARB);

        gl.glActiveTextureARB( GL.GL_TEXTURE0_ARB + 0);
        gl.glBindTexture( GL.GL_TEXTURE_2D, FBOTexture[0]);
        gl.glClientActiveTextureARB( GL.GL_TEXTURE0_ARB + 0);
        gl.glEnable( GL.GL_TEXTURE_2D);

            gl.glBegin( GL.GL_QUADS);
                gl.glMultiTexCoord2f( 0, 1, 1 );
                gl.glVertex3f( vertexes[0][0], waterLevel, vertexes[0][1] );

                gl.glMultiTexCoord2f( 0, 1 , 0 );
                gl.glVertex3f( vertexes[1][0], waterLevel, vertexes[1][1] );

                gl.glMultiTexCoord2f( 0, 0, 0 );
                gl.glVertex3f( vertexes[2][0], waterLevel, vertexes[2][1] );

                gl.glMultiTexCoord2f( 0, 0, 1 );
                gl.glVertex3f( vertexes[3][0], waterLevel, vertexes[3][1] );
            gl.glEnd();

        gl.glActiveTextureARB( GL.GL_TEXTURE0_ARB + 0);
        gl.glDisable( GL.GL_TEXTURE_2D);
        gl.glClientActiveTextureARB( GL.GL_TEXTURE0_ARB + 0);

        gl.glDisable( GL.GL_BLEND );

    }


My waterplane show the fbo texture very well, but I don't know how to compute the texture coordinates, to see the water like a mirror. Now, I just put the fbo texture to the water plane. Screenshot: http://delfin.klte.hu/~fazekaim/water.jpg I should project the texture on the waterplan, but I don't know how. Thanks.

Share this post


Link to post
Share on other sites
i use these functions to set the matrix, before and after have rendered the water:


void EnableWaterTextureMatrix()
{
glMatrixMode( GL_TEXTURE );

glScalef(0.5f, 0.5f, 1.0f);
glTranslatef(1.0f, 1.0f, 0.0f);
glMultMatrixf( g_Camera.GetProjection() );
glMultMatrixf( g_Camera.GetModelView() );

glMatrixMode(GL_MODELVIEW);
}

void DisableWaterTextureMatrix()
{
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
}




here's a screenshot from a demo i wrote:




[Edited by - b3rs3rk on July 11, 2005 8:11:51 AM]

Share this post


Link to post
Share on other sites
the texcoord you use on the quad you draw for the water plane are correct, but if you don't know how to get the modelview and the projection matrix i suggest to try with something simpler than a water reflection demo...

anyway, call glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); and glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);

Share this post


Link to post
Share on other sites
>>the texcoord you use on the quad you draw for the water plane are correct
Thanks.

>>anyway, call glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); and >>glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
Oh, i'm boob. I use it, but I thought to something else, sorry :)

It try it now...

Share this post


Link to post
Share on other sites
I tried it, with this code:


private void EnableWaterTextureMatrix(){
gl.glMatrixMode( GL.GL_TEXTURE );

gl.glScalef(0.5f, 0.5f, 1.0f);
gl.glTranslatef(1.0f, 1.0f, 0.0f);
float[] modelMatrix = new float[16];gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, modelMatrix);
float[] projectionlMatrix = new float[16];gl.glGetFloatv(GL.GL_PROJECTION_MATRIX, projectionlMatrix);
gl.glMultMatrixf( modelMatrix );
gl.glMultMatrixf( projectionlMatrix );

gl.glMatrixMode( GL.GL_MODELVIEW );
}

private void DisableWaterTextureMatrix() {
gl.glMatrixMode( GL.GL_TEXTURE );
gl.glLoadIdentity();
gl.glMatrixMode( GL.GL_MODELVIEW );
}

public void renderWater() {

EnableWaterTextureMatrix();

gl.glEnable( GL.GL_DEPTH_TEST);
gl.glEnable(GL.GL_MULTISAMPLE_ARB);

activateTexture( 0, MeadowLand.FBOTexture[0], GL.GL_TEXTURE_2D );

gl.glBegin( GL.GL_QUADS);
gl.glMultiTexCoord2f( 0, 1, 1 );
gl.glVertex3f( vertexes[0][0], waterLevel, vertexes[0][1] );

gl.glMultiTexCoord2f( 0, 1 , 0 );
gl.glVertex3f( vertexes[1][0], waterLevel, vertexes[1][1] );

gl.glMultiTexCoord2f( 0, 0, 0 );
gl.glVertex3f( vertexes[2][0], waterLevel, vertexes[2][1] );

gl.glMultiTexCoord2f( 0, 0, 1 );
gl.glVertex3f( vertexes[3][0], waterLevel, vertexes[3][1] );
gl.glEnd();

deactivateTexture( 0, GL.GL_TEXTURE_2D );

DisableWaterTextureMatrix();
}




The result: http://delfin.klte.hu/~fazekaim/water2.jpg

What did i wrong?

By the way, when I create the fbo texture I call glScale(1,-1,1);
Should i mirror the camera too?
glu.gluLookAt( eye.x, -eye.y, eye.z, focus.x, focus.y, focus.z, up.x, up.y, up.z );

Share this post


Link to post
Share on other sites
are you sure that the pbuffer texture is correctly filled? remember that when you render in the pbuffer you have to use the same modelview and projection you use in normal rendering, and then scale the scene up/down

Share this post


Link to post
Share on other sites
I'm using gl.glScalef( 1.0f, -1.0f, 1.0f ), and if i'm not mistaken, the framebuffer object don't switch gl context, so it use the same projection and model matrix.

here is my render code:


public void display(GLDrawable glDrawable) {
{
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT );
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
glu.gluLookAt( eye.x, eye.y, eye.z, focus.x, focus.y, focus.z, up.x, up.y, up.z );

gl.glBindFramebufferEXT( GL.GL_FRAMEBUFFER_EXT, FBO[0] );
gl.glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
gl.glClear( GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glPushMatrix();
gl.glScalef( 1.0f, -1.0f, 1.0f );
renderScene();
gl.glPopMatrix();

gl.glBindFramebufferEXT( GL.GL_FRAMEBUFFER_EXT, 0 );
gl.glClearColor(0.0f, 1.0f, 0.0f, 0.0f);
gl.glClear( GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT );
gl.glPushMatrix();
renderscene();
renderWater();
gl.glPopMatrix();
}

private void EnableWaterTextureMatrix(){
gl.glMatrixMode( GL.GL_TEXTURE );

gl.glScalef(0.5f, 0.5f, 1.0f);
gl.glTranslatef(1.0f, 1.0f, 0.0f);
float[] modelMatrix = new float[16];gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, modelMatrix);
float[] projectionlMatrix = new float[16];gl.glGetFloatv(GL.GL_PROJECTION_MATRIX, projectionlMatrix);
gl.glMultMatrixf( modelMatrix );
gl.glMultMatrixf( projectionlMatrix );

gl.glMatrixMode( GL.GL_MODELVIEW );
}

private void DisableWaterTextureMatrix() {
gl.glMatrixMode( GL.GL_TEXTURE );
gl.glLoadIdentity();
gl.glMatrixMode( GL.GL_MODELVIEW );
}

public void renderWater() {

EnableWaterTextureMatrix();

gl.glEnable( GL.GL_DEPTH_TEST);
gl.glEnable(GL.GL_MULTISAMPLE_ARB);

gl.glActiveTextureARB( GL.GL_TEXTURE0_ARB + 0);
gl.glBindTexture( GL.GL_TEXTURE_2D, FBOTexture[0]);
gl.glClientActiveTextureARB( GL.GL_TEXTURE0_ARB + 0);
gl.glEnable( GL.GL_TEXTURE_2D);

gl.glBegin( GL.GL_QUADS);
gl.glMultiTexCoord2f( 0, 1, 1 );
gl.glVertex3f( vertexes[0][0], waterLevel, vertexes[0][1] );

gl.glMultiTexCoord2f( 0, 1 , 0 );
gl.glVertex3f( vertexes[1][0], waterLevel, vertexes[1][1] );

gl.glMultiTexCoord2f( 0, 0, 0 );
gl.glVertex3f( vertexes[2][0], waterLevel, vertexes[2][1] );

gl.glMultiTexCoord2f( 0, 0, 1 );
gl.glVertex3f( vertexes[3][0], waterLevel, vertexes[3][1] );
gl.glEnd();

gl.glActiveTextureARB( GL.GL_TEXTURE0_ARB + 0);
gl.glDisable( GL.GL_TEXTURE_2D);
gl.glClientActiveTextureARB( GL.GL_TEXTURE0_ARB + 0);

gl.glDisable( GL.GL_BLEND );

DisableWaterTextureMatrix();

}


Share this post


Link to post
Share on other sites
it's totally wrong. you should follow these steps:
1) initialize the pbuffer
2) load the modelview and projection matrices (maybe with gluLookAt)
3) render the scene in the pbuffer
4) switch to normal rendering (clearing the buffers)
5) call gluLookAt
6) render all your stuff

Share this post


Link to post
Share on other sites
but i'm using framebuffer object (GL_EXT_framebuffer_object) to render-to-texture and not pbuffer.

i modified my code:


private static void setPerspective(int height, int width) {

height = height <= 0 ? 1 : height;

gl.glViewport(0, 0,width,height);
gl.glMatrixMode( GL.GL_PROJECTION );

gl.glLoadIdentity();
glu.gluPerspective(45.0f, (float)width/height, 1.0f, 10000.0f);

gl.glMatrixMode( GL.GL_MODELVIEW );
gl.glLoadIdentity();
}

...
setPerspective( canvasWidth, canvasHeight );
gl.glBindFramebufferEXT( GL.GL_FRAMEBUFFER_EXT, FBO[0] );
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT );
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
glu.gluLookAt( eye.x, eye.y, eye.z, focus.x, focus.y, focus.z, up.x, up.y, up.z );
gl.glPushMatrix();
gl.glScalef( 1.0f, -1.0f, 1.0f );
renderScene();
gl.glPopMatrix();


instance.addChild( water );
setPerspective( canvasWidth, canvasHeight );
gl.glBindFramebufferEXT( GL.GL_FRAMEBUFFER_EXT, 0 );
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT );
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
glu.gluLookAt( eye.x, eye.y, eye.z, focus.x, focus.y, focus.z, up.x, up.y, up.z );
gl.glPushMatrix();
renderScene();
renderWater();
gl.glPopMatrix();

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this