Demos (master): cuberender: demo rendering to cube map faces for environment mapping

Brian Paul brianp at kemper.freedesktop.org
Thu May 26 13:16:24 UTC 2011


Module: Demos
Branch: master
Commit: 9319956bedd6b0fe4502b09a45be31f73532cf90
URL:    http://cgit.freedesktop.org/mesa/demos/commit/?id=9319956bedd6b0fe4502b09a45be31f73532cf90

Author: Brian Paul <brianp at vmware.com>
Date:   Thu May 26 07:15:59 2011 -0600

cuberender: demo rendering to cube map faces for environment mapping

---

 src/demos/Makefile.am  |    2 +
 src/demos/cuberender.c |  582 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 584 insertions(+), 0 deletions(-)

diff --git a/src/demos/Makefile.am b/src/demos/Makefile.am
index 8751786..41603fa 100644
--- a/src/demos/Makefile.am
+++ b/src/demos/Makefile.am
@@ -40,6 +40,7 @@ bin_PROGRAMS = \
 	clearspd \
 	copypix \
 	cubemap \
+	cuberender \
 	dinoshade \
 	dissolve \
 	drawpix \
@@ -94,6 +95,7 @@ tunnel_SOURCES = \
 
 copypix_LDADD = ../util/libutil.la
 cubemap_LDADD = ../util/libutil.la
+cuberender_LDADD = ../util/libutil.la
 drawpix_LDADD = ../util/libutil.la
 dissolve_LDADD = ../util/libutil.la
 engine_LDADD = ../util/libutil.la
diff --git a/src/demos/cuberender.c b/src/demos/cuberender.c
new file mode 100644
index 0000000..17f9d47
--- /dev/null
+++ b/src/demos/cuberender.c
@@ -0,0 +1,582 @@
+/*
+ * Test rendering into a cube map texture with FBOs.
+ *
+ * Brian Paul
+ * May 2011
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <GL/glew.h>
+#include <GL/glut.h>
+#include "shaderutil.h"
+
+
+#define DEG_TO_RAD (3.14159 / 180.0)
+
+#define ELEMENTS(array) (sizeof(array) / sizeof(array[0]))
+
+static GLint WindowWidth = 750, WindowHeight = 450;
+static GLint Win;
+
+static GLfloat Xrot = 10, Yrot = 0, Zrot = 0;
+
+static GLfloat GroundColor[4] = {0.5, 0.5, 0.75, 1};
+static GLfloat GroundY = -1.0f;
+
+static GLfloat ViewDist = 30.0;
+
+static GLfloat SpherePos[4] = { 0, 2.5, 0, 1 };
+static GLfloat LightDist = 15;
+static GLfloat LightLatitude = 30.0;
+static GLfloat LightLongitude = 45.0;
+static GLfloat LightPos[4];
+
+static GLboolean Anim = GL_TRUE;
+
+static GLboolean NeedNewCubeMap = GL_FALSE;
+static GLuint CubeTexture;
+
+
+struct cylinder
+{
+   float PosX, PosY;
+   float Radius, Height;
+   float Color[4];
+};
+
+#define NUM_CYLINDERS 30
+
+static struct cylinder Cylinders[NUM_CYLINDERS];
+
+
+static float
+RandomFloat(float min, float max)
+{
+   const int k = 10000;
+   float t = (rand() % k) / (float) (k - 1);  /* t in [0,1] */
+   float r = min + t * (max - min);
+   return r;
+}
+
+
+static void
+CheckError(int line)
+{
+   GLenum err = glGetError();
+   if (err) {
+      printf("GL Error 0x%x at line %d\n", (int) err, line);
+   }
+}
+
+
+static void
+GenerateCylinders(void)
+{
+   int i;
+   for (i = 0; i < NUM_CYLINDERS; i++) {
+      float r = RandomFloat(5.0, 9.0);
+      float a = RandomFloat(0, 2 * M_PI);
+      
+      Cylinders[i].PosX = r * cos(a);
+      Cylinders[i].PosY = r * sin(a);
+      Cylinders[i].Radius = RandomFloat(0.25, 1.0);
+      Cylinders[i].Height = RandomFloat(1.0, 7.0);
+      Cylinders[i].Color[0] = RandomFloat(0.25, 1.0);
+      Cylinders[i].Color[1] = RandomFloat(0.25, 1.0);
+      Cylinders[i].Color[2] = RandomFloat(0.25, 1.0);
+      Cylinders[i].Color[3] = RandomFloat(0.25, 1.0);
+   }
+}
+
+static void
+DrawCylinder(const struct cylinder *cyl)
+{
+   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, cyl->Color);
+   glPushMatrix();
+   glTranslatef(cyl->PosX, GroundY, cyl->PosY);
+   glRotatef(-90, 1, 0, 0);
+   glutSolidCone(cyl->Radius, cyl->Height, 12, 2);
+   glPopMatrix();
+}
+
+
+static void
+DrawLightSource(void)
+{
+   glPushMatrix();
+   glTranslatef(LightPos[0], LightPos[1], LightPos[2]);
+   glColor3f(1, 1, 1);
+   glutSolidSphere(0.25, 8, 8);
+   glPopMatrix();
+}
+
+
+static void
+DrawScene(void)
+{
+   int i;
+
+   glEnable(GL_LIGHTING);
+
+   for (i = 0; i < NUM_CYLINDERS; i++) {
+      DrawCylinder(&Cylinders[i]);
+   }
+
+   glDisable(GL_LIGHTING);
+
+   if (1)
+      DrawLightSource();
+
+   /* ground plane */
+   if (1) {
+      GLfloat k = 10.0, g = GroundY;
+      CheckError(__LINE__);
+      glPushMatrix();
+      glColor3fv(GroundColor);
+      glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, GroundColor);
+      glNormal3f(0, 1, 0);
+      glBegin(GL_POLYGON);
+      glVertex3f(-k, g, -k);
+      glVertex3f( k, g, -k);
+      glVertex3f( k, g,  k);
+      glVertex3f(-k, g,  k);
+      glEnd();
+      glPopMatrix();
+   }
+
+   CheckError(__LINE__);
+}
+
+
+/*
+ * Draw sphere with cube map texture that reflects rest of the scene.
+ */
+static void
+DrawShinySphere(void)
+{
+   glEnable(GL_TEXTURE_CUBE_MAP);
+
+#if 0
+   glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
+   glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
+   glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
+#else
+   glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB);
+   glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB);
+   glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB);
+#endif
+   glEnable(GL_TEXTURE_GEN_S);
+   glEnable(GL_TEXTURE_GEN_T);
+   glEnable(GL_TEXTURE_GEN_R);
+
+   glPushMatrix();
+   glTranslatef(SpherePos[0], SpherePos[1], SpherePos[2]);
+   glColor3f(0.75, 0.75, 0.75);
+
+   if (1) {
+      glMatrixMode(GL_TEXTURE);
+      glLoadIdentity();
+      glRotatef(-Yrot, 0, 1, 0);
+      glRotatef(-Xrot, 1, 0, 0);
+   }
+
+   glutSolidSphere(2.5, 16, 16);
+
+   glMatrixMode(GL_MODELVIEW);
+
+   glPopMatrix();
+
+   glDisable(GL_TEXTURE_CUBE_MAP);
+   glDisable(GL_TEXTURE_GEN_S);
+   glDisable(GL_TEXTURE_GEN_T);
+   glDisable(GL_TEXTURE_GEN_R);
+}
+
+
+/**
+ * Setup modelview and projection for drawing a cube face.
+ */
+static void
+SetupCubeFaceView(GLenum face, const GLfloat centerPos[4])
+{
+   GLfloat near = 0.5, far = 20.0;
+
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glFrustum(-near, near, -near, near, near, far);
+
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+
+   switch (face) {
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+      glRotatef(180, 1, 0, 0);
+      glRotatef(-90, 0, 1, 0);
+      break;
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+      glRotatef(180, 1, 0, 0);
+      glRotatef(90, 0, 1, 0);
+      break;
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+      glRotatef(-90, 1, 0, 0);
+      break;
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+      glRotatef(90, 1, 0, 0);
+      break;
+   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+      glRotatef(180, 1, 0, 0);
+      break;
+   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+      glRotatef(0, 1, 0, 0);
+      glRotatef(180, 0, 0, 1);
+      break;
+   }
+
+   glTranslatef(-centerPos[0], -centerPos[1], -centerPos[2]);
+
+   glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
+}
+
+
+
+static void
+ComputeLightPos(GLfloat dist, GLfloat latitude, GLfloat longitude,
+                GLfloat pos[4])
+{
+   pos[0] = dist * sin(longitude * DEG_TO_RAD);
+   pos[1] = dist * sin(latitude * DEG_TO_RAD);
+   pos[2] = dist * cos(latitude * DEG_TO_RAD) * cos(longitude * DEG_TO_RAD);
+   pos[3] = 1;
+}
+
+
+static GLint
+ChooseCubeSize(void)
+{
+   if (WindowWidth >= 1024 && WindowHeight >= 1024) {
+      return 1024;
+   }
+   else if (WindowWidth >= 512 && WindowHeight >= 512) {
+      return 512;
+   }
+   else if (WindowWidth >= 256 && WindowHeight >= 256) {
+      return 256;
+   }
+   else {
+      return 128;
+   }
+}
+
+
+static GLuint
+CreateCubeTexture(GLint size)
+{
+   GLboolean linearFilter = GL_TRUE;
+   GLuint cube, face;
+
+   glGenTextures(1, &cube);
+   glBindTexture(GL_TEXTURE_CUBE_MAP, cube);
+
+   /* Set the filter mode so that the texture is texture-complete.
+    * Otherwise it will cause the framebuffer to fail the framebuffer
+    * completeness test.
+    */
+   if (linearFilter) {
+      glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+      glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+   }
+   else {
+      glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+      glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+   }
+
+   for (face = 0; face < 6; face++) {
+      glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA,
+		   size, size, 0,
+		   GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+   }
+
+   CheckError(__LINE__);
+
+   return cube;
+}
+
+
+/**
+ * Render the six faces of a cube map.
+ */
+static void
+RenderCubeMap(void)
+{
+   GLuint fbo, face, depthStencilRb;
+   GLint cubeSize;
+
+   CheckError(__LINE__);
+
+   cubeSize = ChooseCubeSize();
+   printf("Rendering %d x %d cube texture\n", cubeSize, cubeSize);
+
+   CubeTexture = CreateCubeTexture(cubeSize);
+
+   /*
+    * Make FBO.
+    */
+   glGenFramebuffersEXT(1, &fbo);
+   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
+
+   /*
+    * Make depth/stencil renderbuffer.
+    */
+   glGenRenderbuffersEXT(1, &depthStencilRb);
+   glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthStencilRb);
+   glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL,
+                            cubeSize, cubeSize);
+   glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+                                GL_DEPTH_ATTACHMENT_EXT,
+                                GL_RENDERBUFFER_EXT, depthStencilRb);
+   glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+                                GL_STENCIL_ATTACHMENT_EXT,
+                                GL_RENDERBUFFER_EXT, depthStencilRb);
+
+   glClearColor(0.25, 0.25, 0.25, 1.0);
+   glViewport(0, 0, cubeSize, cubeSize);
+
+   /*
+    * Render into cube faces.
+    */
+   for (face = 0; face < 6; face++) {
+      GLenum status;
+
+      /* Render color into face of cubemap */
+      glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                                GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
+				CubeTexture, 0);
+
+      status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+      CheckError(__LINE__);
+      if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+	 fprintf(stderr, "FBO not complete!  status = 0x%04x\n", status);
+	 assert(status == GL_FRAMEBUFFER_COMPLETE_EXT);
+      }
+
+      CheckError(__LINE__);
+
+      /* Render the depth image into cube face */
+      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+      SetupCubeFaceView(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, SpherePos);
+
+      DrawScene();
+   }
+
+   glDeleteRenderbuffersEXT(1, &depthStencilRb);
+   glDeleteFramebuffersEXT(1, &fbo);
+   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+   CheckError(__LINE__);
+}
+
+
+/**
+ * Redraw window image
+ */
+static void
+Display(void)
+{
+   const GLfloat ar = (GLfloat) WindowWidth / (GLfloat) WindowHeight;
+
+   ComputeLightPos(LightDist, LightLatitude, LightLongitude, LightPos);
+
+   if (NeedNewCubeMap) {
+      /* regenerate cube map faces */
+      RenderCubeMap();
+      NeedNewCubeMap = GL_FALSE;
+   }
+
+   glViewport(0, 0, WindowWidth, WindowHeight);
+
+   /* draw scene from camera's view */
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glFrustum(-ar, ar, -1.0, 1.0, 4.0, 50.0);
+
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+   glTranslatef(0.0, 0.0, -ViewDist);
+   glRotatef(Xrot, 1, 0, 0);
+   glRotatef(Yrot, 0, 1, 0);
+   glRotatef(Zrot, 0, 0, 1);
+
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+   glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
+
+   DrawScene();
+   DrawShinySphere();
+
+   glutSwapBuffers();
+}
+
+
+static void
+Reshape(int width, int height)
+{
+   WindowWidth = width;
+   WindowHeight = height;
+   NeedNewCubeMap = GL_TRUE;
+}
+
+
+static void
+Idle(void)
+{
+   static double t0 = -1.;
+   double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
+   if (t0 < 0.0)
+      t0 = t;
+   dt = t - t0;
+   t0 = t;
+   Yrot += 40.0 * dt;
+   glutPostRedisplay();
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+   const GLfloat step = 3.0;
+   (void) x;
+   (void) y;
+   switch (key) {
+   case 'a':
+      Anim = !Anim;
+      if (Anim)
+         glutIdleFunc(Idle);
+      else
+         glutIdleFunc(NULL);
+      break;
+   case 'r':
+      GenerateCylinders();
+      NeedNewCubeMap = GL_TRUE;
+      break;
+   case 'z':
+      Zrot -= step;
+         break;
+   case 'Z':
+      Zrot += step;
+      break;
+   case 27:
+      glutDestroyWindow(Win);
+      exit(0);
+      break;
+   }
+   fflush(stdout);
+   glutPostRedisplay();
+}
+
+
+static void
+SpecialKey(int key, int x, int y)
+{
+   const GLfloat step = 3.0;
+   const int mod = glutGetModifiers();
+   (void) x;
+   (void) y;
+   switch (key) {
+      case GLUT_KEY_UP:
+         if (mod)
+            //LightLatitude += step;
+            SpherePos[1] += .1*step;
+         else
+            Xrot += step;
+         break;
+      case GLUT_KEY_DOWN:
+         if (mod)
+            //LightLatitude -= step;
+            SpherePos[1] -= .1*step;
+         else
+            Xrot -= step;
+         break;
+      case GLUT_KEY_LEFT:
+         if (mod)
+            LightLongitude += step;
+         else
+            Yrot += step;
+         break;
+      case GLUT_KEY_RIGHT:
+         if (mod)
+            LightLongitude -= step;
+         else
+            Yrot -= step;
+         break;
+   }
+   if (mod)
+      NeedNewCubeMap = GL_TRUE;
+
+   glutPostRedisplay();
+}
+
+
+static void
+Init(void)
+{
+   const char *extensions[3] = {
+      "GL_ARB_depth_texture",
+      "GL_ARB_texture_cube_map",
+      "GL_EXT_framebuffer_object"
+   };
+   int i;
+
+   for (i = 0; i < ELEMENTS(extensions); i++) {
+      if (!glutExtensionSupported(extensions[i])) {
+         printf("Sorry, this demo requires %s\n", extensions[i]);
+         exit(1);
+      }
+   }
+
+   glEnable(GL_DEPTH_TEST);
+   glEnable(GL_LIGHTING);
+   glEnable(GL_LIGHT0);
+
+   GenerateCylinders();
+
+   printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+}
+
+
+static void
+PrintHelp(void)
+{
+   printf("Keys:\n");
+   printf("  a = toggle animation\n");
+   printf("  cursor keys = rotate scene\n");
+   printf("  <shift> + up/down = move sphere\n");
+   printf("  <shift> + left/right = move light\n");
+   fflush(stdout);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+   glutInitWindowSize(WindowWidth, WindowHeight);
+   glutInit(&argc, argv);
+   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
+   Win = glutCreateWindow(argv[0]);
+   glewInit();
+   glutReshapeFunc(Reshape);
+   glutKeyboardFunc(Key);
+   glutSpecialFunc(SpecialKey);
+   glutDisplayFunc(Display);
+   if (Anim)
+      glutIdleFunc(Idle);
+   Init();
+   PrintHelp();
+   glutMainLoop();
+   return 0;
+}




More information about the mesa-commit mailing list