Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Some more example programs.

Demonstrating the use of the stencil buffer and shadow mapping.
  • Loading branch information...
commit fc93db984107af67d5fa6988cdd1961dd882570d 1 parent b0a5f7e
Vilya Harvey authored
2  CMakeLists.txt
View
@@ -91,6 +91,8 @@ example(basic)
example(example)
example(imageview)
example(raymarch)
+example(shadowmap)
+example(stencil)
example(styled)
#example(picking)
10 TODO.txt
View
@@ -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.
340 example/shadowmap.cpp
View
@@ -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;
+}
118 example/stencil.cpp
View
@@ -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;
+}
2  src/vgl_viewer.cpp
View
@@ -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");
Please sign in to comment.
Something went wrong with that request. Please try again.