28. OpenGL Basic Reflection

This OpenGL tutorial will show you how to create basic reflections using the stencil buffer to clip the reflection to a specific plane. It is almost the same as the shadow tutorial prior. But it changes a few little variables to change the shadow to a reflection.

This tutorial is basically just like the basic shadow
tutorial, only here we are not changing our square
to look like a shadow. We are leaving it exactly
as it is. You will notice that this tutorial is
almost identical to the shadow one, so you can
skip it if you like.

To achieve the effect of reflections that remain on a plane
the best method is to use the stencil buffer. With this
we can set the plane that the reflections is to be drawn on
and any part that is not drawn within the selected plane
is then clipped from the view.

Now the stencil buffer basically just draws the shape
again and changes is accordingly, setting it to the
selected part of the scene.

To do this we have to set up the stencil buffer by changing the
code in the main function to:
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_STENCIL);
notice that we are adding GLUT_STENCIL.

That then leads to another call in the display function
so that just like clearing the depth and color buffers,
we clear the stencil buffer with:
glClearStencil(0);
And change the clear line to:
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

After that we need to set the plane for the stencil buffer
to draw to.
So we clear the color and depth masks, then we enable the stencil
test with:
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
glEnable(GL_STENCIL_TEST);

Then we set the stencil function to replace the data in our
selected plane with whatever we choose to. We set it to
replace with:
glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);

Next we set the plane that we want the stencil buffer to
draw to. I have used my bench function for this with:
bench();
So it will take the coordinates for my bench and use
that as the plane to draw to.

Then we turn on the color mask, the depth mask and
set the stencil function to keep whatever we say next.
So it is replacing what we had before, with what we are
about to add. We do this with:
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

Now it is time to draw the shadow.
First of all I disable the depth testing so that the reflection will
appear behind our bench.
I then draw the square flipped upside down, and translated
into the drawing plane.
I then set the rotation as the squares rotation.
Then I re-enable the depth testing.
This is all done with:
glDisable(GL_DEPTH_TEST);
glPushMatrix();
glScalef(1.0f, -1.0f, 1.0f);
glTranslatef(0,2,0);
glRotatef(angle,0,1,0);
square();
glPopMatrix();
glEnable(GL_DEPTH_TEST);

Next I simply disable the stencil test with:
glDisable(GL_STENCIL_TEST);

After that I just draw the scene as usual with
the bench set to an alpha blend so that the
reflection appears transparent.

Now that should give you an idea of how to use the stencil
buffer to create basic reflections.

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
    #include <GL/gl.h>
#include <GL/glut.h>
#include <windows.h>
#include <stdio.h>
#include <iostream.h>

float angle = 0;

GLint stencilBits;

GLuint texture[40];

void freetexture (GLuint texture) {
    glDeleteTextures( 1, &texture );
}

loadtextures (const char *filename, float width, float 
height) {
  GLuint texture;

  unsigned char *data;
  FILE *file;

  file = fopen( filename, “rb” );
  if ( file == NULL ) return 0;

  data = (unsigned char *)malloc( width * height * 3 );
  fread( data, width * height * 3, 1, file );

  fclose( file );

  glGenTextures( 1, &texture );
  glBindTexture( GL_TEXTURE_2D, texture );
  glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 
GL_MODULATE );
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
 GL_LINEAR_MIPMAP_NEAREST );
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
 GL_LINEAR );
  gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height, 
GL_RGB, GL_UNSIGNED_BYTE, data );
    
  data = NULL;

  return texture;
}

void square (void) {
    glPushMatrix();
    glBindTexture(GL_TEXTURE_2D,texture[0]);
    glTranslatef(0,2.5,0);
    glScalef(2,2,2);
    glBegin(GL_QUADS);
        glTexCoord2f(1,0);
    glVertex3f(-1,-1,0);
        glTexCoord2f(1,1);
    glVertex3f(-1,1,0);
        glTexCoord2f(0,1);
    glVertex3f(1,1,0);
        glTexCoord2f(0,0);
    glVertex3f(1,-1,0);
    glEnd();
    glPopMatrix();
}

void bench (void) {
    glPushMatrix();
    glColor4f(1,1,1,0.7);
    glBindTexture(GL_TEXTURE_2D,texture[1]);
    glTranslatef(0,-2.5,0);
    glScalef(4,2,4);
    glBegin(GL_QUADS);
        glTexCoord2f(1,0);
    glVertex3f(-1,-1,1);
        glTexCoord2f(1,1);
    glVertex3f(-1,1,-0.5);
        glTexCoord2f(0,1);
    glVertex3f(1,1,-0.5);
        glTexCoord2f(0,0);
    glVertex3f(1,-1,1);
    glEnd();
    glPopMatrix();
}

void display (void) {
    glClearStencil(0); //clear the stencil buffer
    glClearDepth(1.0f);
    glClearColor (0.0,0.0,0.0,1);
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT); //clear the buffers
    glLoadIdentity();

    glTranslatef(0, 0, -10);

//start
    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); /
/disable the color mask

    glDepthMask(GL_FALSE); //disable the depth mask

    glEnable(GL_STENCIL_TEST); //enable the stencil testing

    glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
    glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); //set
 the stencil buffer to replace our next lot of data

    bench(); //set the data plane to be replaced

    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); //enable
 the color mask

    glDepthMask(GL_TRUE); //enable the depth mask

    glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); //set the stencil
 buffer to keep our next lot of data

    glDisable(GL_DEPTH_TEST); //disable depth testing of the
 reflection

    glPushMatrix();
    glScalef(1.0f, -1.0f, 1.0f); //flip the reflection vertically

    glTranslatef(0,2,0); //translate the reflection onto the
 drawing plane

    glRotatef(angle,0,1,0); //rotate the reflection
    square(); //draw the square as our reflection
    glPopMatrix();
    glEnable(GL_DEPTH_TEST); //enable the depth testing

    glDisable(GL_STENCIL_TEST); //disable the stencil testing

//end

    glEnable(GL_BLEND); //enable alpha blending
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); /
/set the blending function

    
    bench(); //draw our bench

    glDisable(GL_BLEND); //disable alpha blending

    glRotatef(angle,0,1,0); //rotate our square
    square(); //draw our square

    glutSwapBuffers();
    angle++;
}

void init (void) {
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);    
    glShadeModel (GL_SMOOTH);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    glEnable(GL_TEXTURE_2D);

    texture[0] = loadtextures(“texture.raw”, 256,256);
    texture[1] = loadtextures(“water.raw”, 256,256);
}

void reshape (int w, int h) {
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 0.1, 1000.0
);
    glMatrixMode (GL_MODELVIEW);
}

int main (int argc, char **argv) {
    glutInit (&argc, argv);
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_STENCIL
); //add a stencil buffer to the window
    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow (“A basic OpenGL Window);
    init();
    glutDisplayFunc (display);
    glutIdleFunc (display);
    glutReshapeFunc (reshape);
    glutMainLoop ();
    return 0;
}

Share and Enjoy

  • Facebook
  • Twitter
  • Delicious
  • LinkedIn
  • StumbleUpon
  • Add to favorites
  • Email
  • RSS

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>