Featured Posts

8. Bump Mapping in GLSL8. Bump Mapping in GLSL Introduction Bump mapping is essential in todays computer games, and computer graphics in general. Would you like to know the best thing about it? It is extremely simple to implement. Bump mapping works...

Read more

Swiftless GLSL Shader DeveloperSwiftless GLSL Shader Developer Swiftless GLSL Shader Developer   Version 0.1a Currently Swiftless GLSL Shader Developer is in it's first public release, and is currently in alpha status, meaning it is not complete and may contain...

Read more

Wordpress Optimization Wordpress Website Optimizations Introduction Wordpress itself is a fairly wonderful tool. Since switching to it, I find it is a lot quicker to make changes to my website and it is also quicker to get...

Read more

36. OpenGL Framebuffers36. OpenGL Framebuffers Introduction Frame buffers are one of those mythical things that we have all heard of, but many beginner OpenGL developers avoid because there is not much information about them, and they can be confusing...

Read more

1. Terrain Class1. Terrain Class Terrain is one of those things that so far, hasn't been perfectly recreated in computer graphics. But it is almost there! Looking over a beautiful landscape can be one of the most amazing feelings in the...

Read more

  • Prev
  • Next

27. OpenGL Basic Shadows

Posted on : 25-03-2010 | By : Swiftless | In : OpenGL

Tags: , , , , , ,

3

This OpenGL tutorial will show you how to use the stencil buffer to select a plane to be drawn to, then use the stencil buffer to draw a basic shadow to that plane.

To achieve the effect of shadows that remain on a plane
the best method is to use the stencil buffer. With this
we can set the plane that the shadow 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.
I first disable texturing so our shadow appears plain.
I then disable the depth testing so that the shadow 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 and
color it black.
Then I re-enable the depth testing and the texturing.
This is all done with:
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glPushMatrix();
glScalef(1.0f, -1.0f, 1.0f);
glTranslatef(0,2,0);
glRotatef(angle,0,1,0);
glColor4f(0,0,0,1);
square();
glPopMatrix();
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);

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
shadow appears transparent.

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

Keep visiting the site as I am working on
shadows that change shape in accordance with the light
position.

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.
183.
184.
185.
  #include <GL/gl.h>
#include <GL/glut.h>
#include <windows.h>
#include <stdio.h>
#include <iostream.h>

float angle = 0;

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 (1.0,1.0,1.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_TEXTURE_2D); //disable texturing of the 
shadow

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

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

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

    glRotatef(angle,0,1,0); //rotate the shadow accordingly

    glColor4f(0,0,0,1); //color the shadow black
    square(); //draw our square as the shadow
    glPopMatrix();
    glEnable(GL_DEPTH_TEST); //enable depth testing
    glEnable(GL_TEXTURE_2D); //enable texturing

    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 teh alpha blending

    
    bench(); //draw our bench

    glDisable(GL_BLEND); //disable alpha blending

    glRotatef(angle,0,1,0); //rotate the square
    square(); //draw the 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;
}

VN:F [1.9.3_1094]
Please rate so I know where to improve the site. 1 means needs a lot of improvement, 10 means perfect. If you leave a low rating, please state why. I don't want people just coming to bash the site.
Rating: 8.2/10 (11 votes cast)
VN:F [1.9.3_1094]
Rating: +6 (from 6 votes)
27. OpenGL Basic Shadows, 8.2 out of 10 based on 11 ratings

Related posts:

  1. 28. OpenGL Basic Reflection
  2. 36. OpenGL Framebuffers
  3. 31. OpenGL Sphere Creation
  4. 35. OpenGL Tiling Engine
  5. 32. OpenGL Particle Engine

Comments (3)

Hi! I’ve been playing with your code, and for some reason, the object that is being shadowed ends up going behind the bench() (i’m using another object that the square, and i re-written the quad drawing as
glTexCoord2f (0, 0);
glVertex3f (0, 0, 0);
glTexCoord2f (1, 0);
glVertex3f (1, 0, 0);

etc.

Im drawing the object as normal at the end of the loop
Looks like this:

http://www.dobrajazz.com/behind.JPG

VA:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VA:F [1.9.3_1094]
Rating: 0 (from 0 votes)

forget it, forgot to disable the depth test :)

VA:F [1.9.3_1094]
Rating: 0.0/5 (0 votes cast)
VA:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Hey,
nice tutorial again!

It’ll be perfect, if you would upload the “water.raw”-Data :)

But thanks a lot for your engagement :)

VA:F [1.9.3_1094]
Rating: 4.5/5 (4 votes cast)
VA:F [1.9.3_1094]
Rating: +2 (from 2 votes)

Write a comment

Improve the web with Nofollow Reciprocity.