Permalink
Browse files

Some more example programs.

Demonstrating the use of the stencil buffer and shadow mapping.
  • Loading branch information...
1 parent b0a5f7e commit fc93db984107af67d5fa6988cdd1961dd882570d @vilya committed Oct 29, 2010
Showing with 471 additions and 1 deletion.
  1. +2 −0 CMakeLists.txt
  2. +10 −0 TODO.txt
  3. +340 −0 example/shadowmap.cpp
  4. +118 −0 example/stencil.cpp
  5. +1 −1 src/vgl_viewer.cpp
View
2 CMakeLists.txt
@@ -91,6 +91,8 @@ example(basic)
example(example)
example(imageview)
example(raymarch)
+example(shadowmap)
+example(stencil)
example(styled)
#example(picking)
View
10 TODO.txt
@@ -7,6 +7,7 @@ TODO
- Make the loadOBJ and loadPLY functions public.
- Make it possible to register additional geometry loaders without changing the VGL code.
- Add support for LWO files.
+- Add support for .3ds files, using lib3ds: http://lib3ds.sf.net/
- Comment the code properly, in a structured format that Doxygen or something can use.
- Add a build target to generate the docs.
@@ -18,3 +19,12 @@ TODO
- Get the ArcballCamera working *better* than the hacked-together camera in the
OBJViewer.
+- Scene graph classes
+- Scene graph renderer
+ - Walk the scene graph to build up a vector of render commands. Note that
+ unloading a buffer / texture / shader should be a command too.
+ - build up an adjacency matrix for dependencies between render commands.
+ - Do a topological sort of the render commands.
+ - Fuse commands where possible.
+ - Sort the render commands to minimise the number of state changes & maximise
+ reuse of buffers/textures.
View
340 example/shadowmap.cpp
@@ -0,0 +1,340 @@
+#include "vgl.h"
+
+//
+// Classes
+//
+
+class DirectionalLight
+{
+public:
+ DirectionalLight(const vgl::Vec3f& pos, const vgl::Vec3f& target,
+ const vgl::Vec3f& up);
+
+ void setupProjectionMatrix(int shadowMapWidth, int shadowMapHeight);
+ void setupModelViewMatrix();
+ void setupLight(float brightness);
+
+ vgl::Matrix4f getShadowMatrix(int shadowMapWidth, int shadowMapHeight);
+
+ const vgl::Vec3f& getPos() const;
+ const vgl::Vec3f& getTarget() const;
+ const vgl::Vec3f& getUp() const;
+
+private:
+ vgl::Vec3f _pos, _target, _up;
+ vgl::Matrix4f _projMatrix, _modelViewMatrix;
+};
+
+
+class ShadowMapRenderer : public vgl::Renderer
+{
+public:
+ ShadowMapRenderer(DirectionalLight* light, vgl::Camera* camera);
+
+ virtual void setup();
+ virtual void render();
+
+protected:
+ void saveShadowTexture();
+ void setupShadowMap();
+ void drawSceneFromLight();
+ void drawSceneFromCamera(float brightness, int viewport[]);
+ void drawScene();
+
+private:
+ int _shadowMapWidth;
+ int _shadowMapHeight;
+ GLuint _shadowTex;
+
+ DirectionalLight* _light;
+ vgl::Camera* _camera;
+};
+
+
+class ShadowMapViewer : public vgl::Viewer
+{
+public:
+ ShadowMapViewer(ShadowMapRenderer* shadowMapRenderer);
+
+ virtual void render();
+};
+
+
+//
+// DirectionalLight methods
+//
+
+DirectionalLight::DirectionalLight(const vgl::Vec3f& pos,
+ const vgl::Vec3f& target,
+ const vgl::Vec3f& up) :
+ _pos(pos),
+ _target(target),
+ _up(up)
+{
+}
+
+
+void DirectionalLight::setupProjectionMatrix(int shadowMapWidth,
+ int shadowMapHeight)
+{
+ float distance = length(_target - _pos);
+ gluPerspective(30, float(shadowMapWidth) / float(shadowMapHeight),
+ distance * 0.1, distance * 2.0);
+}
+
+
+void DirectionalLight::setupModelViewMatrix()
+{
+ gluLookAt(_pos.x, _pos.y, _pos.z, _target.x, _target.y, _target.z,
+ _up.x, _up.y, _up.z);
+}
+
+
+void DirectionalLight::setupLight(float brightness)
+{
+ const vgl::Vec3f kColor(brightness, brightness, brightness);
+ const vgl::Vec3f kBlack(0, 0, 0);
+
+ glLightfv(GL_LIGHT1, GL_POSITION, _pos.data);
+ glLightfv(GL_LIGHT1, GL_AMBIENT, kColor.data);
+ glLightfv(GL_LIGHT1, GL_DIFFUSE, kColor.data);
+ glLightfv(GL_LIGHT1, GL_SPECULAR, kBlack.data);
+ glEnable(GL_LIGHT1);
+ glEnable(GL_LIGHTING);
+}
+
+
+vgl::Matrix4f DirectionalLight::getShadowMatrix(int shadowMapWidth,
+ int shadowMapHeight)
+{
+ const float kBias[] = {
+ 0.5, 0.0, 0.0, 0.0,
+ 0.0, 0.5, 0.0, 0.0,
+ 0.0, 0.0, 0.5, 0.0,
+ 0.5, 0.5, 0.5, 1.0
+ };
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadMatrixf(kBias);
+ setupProjectionMatrix(shadowMapWidth, shadowMapHeight);
+ setupModelViewMatrix();
+
+ vgl::Matrix4f shadowMatrix;
+ glGetFloatv(GL_MODELVIEW_MATRIX, shadowMatrix.data);
+ glPopMatrix();
+
+ return shadowMatrix;
+}
+
+
+//
+// ShadowMapRenderer functions
+//
+
+ShadowMapRenderer::ShadowMapRenderer(DirectionalLight* light, vgl::Camera* camera) :
+ vgl::Renderer(),
+ _shadowMapWidth(512),
+ _shadowMapHeight(512),
+ _shadowTex(0),
+ _light(light),
+ _camera(camera)
+{
+}
+
+
+void ShadowMapRenderer::setup()
+{
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_NORMALIZE);
+ glEnable(GL_COLOR_MATERIAL);
+
+ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+
+ glCullFace(GL_BACK);
+ glShadeModel(GL_SMOOTH);
+ glDepthFunc(GL_LEQUAL);
+
+ const vgl::Vec3f kWhite(1, 1, 1);
+
+ glClearColor(0, 0, 0, 0);
+ glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
+ glMaterialfv(GL_FRONT, GL_SPECULAR, kWhite.data);
+ glMaterialf(GL_FRONT, GL_SHININESS, 16.0);
+
+ // Create the shadowmap texture.
+ glGenTextures(1, &_shadowTex);
+ glBindTexture(GL_TEXTURE_2D, _shadowTex);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
+ _shadowMapWidth, _shadowMapHeight, 0, GL_LUMINANCE, GL_FLOAT, NULL);
+}
+
+
+void ShadowMapRenderer::render()
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ // Store the current viewport settings.
+ int viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+ int width = viewport[2];
+ int height = viewport[3];
+
+ // Draw the scene from the light's point of view.
+ drawSceneFromLight();
+
+ // Save the rendered scene in the shadow map.
+ saveShadowTexture();
+
+ // Draw the scene from the cameras point of view with a dim light for the shadowed areas.
+ drawSceneFromCamera(0.2f, viewport);
+
+ // Setup the shadow map.
+ setupShadowMap();
+
+ // Draw the scene from the cameras point of view with a bright light for the unshadowed areas.
+ //drawSceneFromCamera(1.0f, viewport);
+
+ // Cleanup
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ glDisable(GL_TEXTURE_GEN_R);
+ glDisable(GL_TEXTURE_GEN_Q);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_ALPHA_TEST);
+}
+
+
+void ShadowMapRenderer::saveShadowTexture()
+{
+ glBindTexture(GL_TEXTURE_2D, _shadowTex);
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 0, 0, _shadowMapWidth, _shadowMapHeight, 0);
+ glClear(GL_DEPTH_BUFFER_BIT);
+}
+
+
+void ShadowMapRenderer::setupShadowMap()
+{
+ vgl::Matrix4f shadowMatrix = _light->getShadowMatrix(_shadowMapWidth, _shadowMapHeight);
+ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+ glTexGenfv(GL_S, GL_EYE_PLANE, shadowMatrix.rows[0]);
+ glEnable(GL_TEXTURE_GEN_S);
+ glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+ glTexGenfv(GL_T, GL_EYE_PLANE, shadowMatrix.rows[1]);
+ glEnable(GL_TEXTURE_GEN_T);
+ glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+ glTexGenfv(GL_R, GL_EYE_PLANE, shadowMatrix.rows[2]);
+ glEnable(GL_TEXTURE_GEN_R);
+ glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+ glTexGenfv(GL_Q, GL_EYE_PLANE, shadowMatrix.rows[3]);
+ glEnable(GL_TEXTURE_GEN_Q);
+ glBindTexture(GL_TEXTURE_2D, _shadowTex);
+ glEnable(GL_TEXTURE_2D);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+ glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
+ glAlphaFunc(GL_GEQUAL, 0.99f);
+ glEnable(GL_ALPHA_TEST);
+}
+
+
+void ShadowMapRenderer::drawSceneFromLight()
+{
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ _light->setupProjectionMatrix(_shadowMapWidth, _shadowMapHeight);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ _light->setupModelViewMatrix();
+ glViewport(0, 0, _shadowMapWidth, _shadowMapHeight);
+ glCullFace(GL_FRONT);
+ glShadeModel(GL_FLAT);
+ glColorMask(0, 0, 0, 0);
+ drawScene();
+}
+
+
+void ShadowMapRenderer::drawSceneFromCamera(float brightness, int viewport[])
+{
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ _camera->setupProjectionMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ _camera->setupModelViewMatrix();
+ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+ glCullFace(GL_BACK);
+ glShadeModel(GL_SMOOTH);
+ glColorMask(1, 1, 1, 1);
+ _light->setupLight(brightness);
+ drawScene();
+}
+
+
+void ShadowMapRenderer::drawScene()
+{
+ glFrontFace(GL_CW); // The triangle winding order on the teapot seems to be clockwise...
+ glColor3f(1, 0, 0);
+ glPushMatrix();
+ glTranslatef(0, 0.5, 0);
+ glutSolidTeapot(0.5);
+ glPopMatrix();
+
+ glFrontFace(GL_CCW);
+ glColor3f(0, 0, 1);
+ glPushMatrix();
+ glScalef(1, 0.1, 1);
+ glTranslatef(0, -0.5, 0);
+ glutSolidCube(1.0);
+ glPopMatrix();
+}
+
+
+//
+// ShadowMapViewer functions
+//
+
+ShadowMapViewer::ShadowMapViewer(ShadowMapRenderer* renderer) :
+ vgl::Viewer("Shadow map test", 1024, 768, renderer)
+{
+}
+
+
+void ShadowMapViewer::render()
+{
+ _renderer->render();
+ glutSwapBuffers();
+}
+
+
+//
+// Functions
+//
+
+int main(int argc, char**argv)
+{
+ const int kWidth = 1024;
+ const int kHeight = 768;
+
+ vgl::ArcballCamera camera(vgl::Vec3f(0, 0, 5),
+ vgl::Vec3f(0, 0, 0),
+ vgl::Vec3f(0, 1, 0),
+ -1, 1, -1, 1,
+ 30, kWidth, kHeight);
+
+ DirectionalLight light(vgl::Vec3f(0, 5, 0),
+ vgl::Vec3f(0, 0, 0),
+ vgl::Vec3f(1, 0, 0));
+
+ ShadowMapRenderer renderer(&light, &camera);
+ vgl::Viewer viewer("Stencil buffer test", kWidth, kHeight, &renderer, &camera);
+ viewer.run();
+ return 0;
+}
View
118 example/stencil.cpp
@@ -0,0 +1,118 @@
+#include "vgl.h"
+
+
+//
+// Classes
+//
+
+class StencilRenderer : public vgl::Renderer
+{
+public:
+ virtual void setup();
+ virtual void render();
+};
+
+
+//
+// StencilRenderer methods
+//
+
+void StencilRenderer::setup()
+{
+ int viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+ int width = viewport[0];
+ int height = viewport[1];
+
+ const unsigned char pixels[64] = {
+ 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+ 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+ 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+ 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+ 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+ 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+ 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+ 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+ };
+
+ width = 1024;
+ height = 768;
+ gluOrtho2D(0, width, 0, height);
+
+ // Fill the stencil buffer.
+ glClearStencil(0);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glColorMask(0, 0, 0, 0);
+ glEnable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glStencilFunc(GL_EQUAL, 1, 1);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+ for (int y = 0; y < height; y += 8) {
+ for (int x = 0; x < width; x += 8) {
+ glRasterPos2i(x, y);
+ glDrawPixels(8, 8, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, pixels);
+ }
+ }
+ vgl::checkGLError("fucked up the stencil buffer initialisation");
+
+ glColorMask(1, 1, 1, 1);
+ glEnable(GL_DEPTH_TEST);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+}
+
+
+void StencilRenderer::render()
+{
+ // Draw the left eye image.
+ glStencilFunc(GL_EQUAL, 1, 1);
+ glColor3f(0, 0, 1);
+ glutSolidTeapot(1.0);
+
+ // Draw the right eye image.
+ glStencilFunc(GL_NOTEQUAL, 1, 1);
+ glColor3f(0, 1, 1);
+ glutSolidTeapot(1.0);
+
+// glDisable(GL_STENCIL_TEST);
+
+// int viewport[4];
+// glGetIntegerv(GL_VIEWPORT, viewport);
+// int width = 1024;//viewport[0];
+// int height = 768;//viewport[1];
+
+// const unsigned char pixels[64] = {
+// 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+// 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+// 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+// 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+// 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+// 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+// 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+// 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
+// };
+// gluOrtho2D(0, width, 0, height);
+//// glRasterPos2i(0, 0);
+//// glDrawPixels(8, 8, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels);
+//// glRasterPos2f(0.5, 0.5);
+//// glDrawPixels(8, 8, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels);
+// for (int y = 0; y < height; y += 8) {
+// for (int x = 0; x < width; x += 8) {
+// glRasterPos2f(x, y);
+// glDrawPixels(8, 8, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels);
+// }
+// }
+// vgl::checkGLError("fucked up the stencil buffer initialisation");
+}
+
+
+//
+// Functions
+//
+
+int main(int argc, char** argv)
+{
+ StencilRenderer renderer;
+ vgl::Viewer viewer("Stencil buffer test", 1024, 768, &renderer);
+ viewer.run();
+ return 0;
+}
View
2 src/vgl_viewer.cpp
@@ -100,7 +100,7 @@ Viewer::Viewer(
// Setup GLUT
glutInit(&argc, argv);
- glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
+ glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA | GLUT_STENCIL);
glutInitWindowPosition(100, 100);
glutInitWindowSize(width, height);
glutCreateWindow((title != NULL) ? title : "Unnamed");

0 comments on commit fc93db9

Please sign in to comment.