From 762c3618f52ef5033844092074c63eee545500fa Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 6 Apr 2006 04:11:28 +0000 Subject: [PATCH] Added render to depth texture support with GL_EXT_framebuffer_object. Only render the shadow/depth texture when really needed, not every frame. Remove support for old SGIX shadow extensions. --- progs/demos/shadowtex.c | 326 ++++++++++++++++++++++++++++------------ 1 file changed, 227 insertions(+), 99 deletions(-) diff --git a/progs/demos/shadowtex.c b/progs/demos/shadowtex.c index 3e4bd43abdc..49dd8cbcc9c 100644 --- a/progs/demos/shadowtex.c +++ b/progs/demos/shadowtex.c @@ -1,13 +1,16 @@ /* * Shadow demo using the GL_ARB_depth_texture, GL_ARB_shadow and - * GL_ARB_shadow_ambient extensions (or the old SGIX extensions). + * GL_ARB_shadow_ambient extensions. * * Brian Paul * 19 Feb 2001 * * Added GL_EXT_shadow_funcs support on 23 March 2002 + * Added GL_EXT_packed_depth_stencil support on 15 March 2006. + * Added GL_EXT_framebuffer_object support on 27 March 2006. + * Removed old SGIX extension support on 5 April 2006. * - * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -27,7 +30,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - +#define GL_GLEXT_PROTOTYPES #include #include #include @@ -35,12 +38,6 @@ #include #include "showbuffer.h" -#if 0 /* change to 1 if you want to use the old SGIX extensions */ -#undef GL_ARB_depth_texture -#undef GL_ARB_shadow -#undef GL_ARB_shadow_ambient -#endif - #define DEG_TO_RAD (3.14159 / 180.0) static GLint WindowWidth = 450, WindowHeight = 300; @@ -64,10 +61,19 @@ static GLboolean LinearFilter = GL_FALSE; static GLfloat Bias = -0.06; -static GLboolean Anim = GL_TRUE; +static GLboolean Anim = GL_FALSE; +static GLboolean NeedNewShadowMap = GL_FALSE; +static GLuint ShadowTexture, GrayTexture; +static GLuint ShadowFBO; + +static GLboolean HaveFBO = GL_FALSE; +static GLboolean UseFBO = GL_FALSE; +static GLboolean HavePackedDepthStencil = GL_FALSE; static GLboolean UsePackedDepthStencil = GL_FALSE; static GLboolean HaveEXTshadowFuncs = GL_FALSE; +static GLboolean HaveShadowAmbient = GL_FALSE; + static GLint Operator = 0; static const GLenum OperatorFunc[8] = { GL_LEQUAL, GL_LESS, GL_GEQUAL, GL_GREATER, @@ -78,7 +84,7 @@ static const char *OperatorName[8] = { static GLuint DisplayMode; -#define SHOW_NORMAL 0 +#define SHOW_SHADOWS 0 #define SHOW_DEPTH_IMAGE 1 #define SHOW_DEPTH_MAPPING 2 #define SHOW_DISTANCE 3 @@ -89,6 +95,7 @@ static void DrawScene(void) { GLfloat k = 6; + /* sphere */ glPushMatrix(); glTranslatef(1.6, 2.2, 2.7); @@ -200,9 +207,9 @@ EnableDistanceTexgen(const GLfloat lightPos[4], const GLfloat lightDir[3], /* nearPoint = point on light direction vector which intersects the * near plane of the light frustum. */ - nearPoint[0] = LightPos[0] + lightDir[0] / m * lightNear; - nearPoint[1] = LightPos[1] + lightDir[1] / m * lightNear; - nearPoint[2] = LightPos[2] + lightDir[2] / m * lightNear; + nearPoint[0] = lightPos[0] + lightDir[0] / m * lightNear; + nearPoint[1] = lightPos[1] + lightDir[1] / m * lightNear; + nearPoint[2] = lightPos[2] + lightDir[2] / m * lightNear; sPlane[0] = lightDir[0] / d / m; sPlane[1] = lightDir[1] / d / m; @@ -242,20 +249,43 @@ ComputeLightPos(GLfloat dist, GLfloat latitude, GLfloat longitude, } +/** + * Render the shadow map / depth texture. + * The result will be in the texture object named ShadowTexture. + */ static void -Display(void) +RenderShadowMap(void) { - GLfloat ar = (GLfloat) WindowWidth / (GLfloat) WindowHeight; - GLfloat d; - GLenum error; + GLenum depthFormat; /* GL_DEPTH_COMPONENT or GL_DEPTH_STENCIL_EXT */ + GLenum depthType; /* GL_UNSIGNED_INT_24_8_EXT or GL_UNSIGNED_INT */ + float d; + + if (WindowWidth >= 1024 && WindowHeight >= 1024) { + ShadowTexWidth = ShadowTexHeight = 1024; + } + else if (WindowWidth >= 512 && WindowHeight >= 512) { + ShadowTexWidth = ShadowTexHeight = 512; + } + else if (WindowWidth >= 256 && WindowHeight >= 256) { + ShadowTexWidth = ShadowTexHeight = 256; + } + else { + ShadowTexWidth = ShadowTexHeight = 128; + } + printf("Rendering %d x %d depth texture\n", ShadowTexWidth, ShadowTexHeight); + + if (UsePackedDepthStencil) { + depthFormat = GL_DEPTH_STENCIL_EXT; + depthType = GL_UNSIGNED_INT_24_8_EXT; + } + else { + depthFormat = GL_DEPTH_COMPONENT; + depthType = GL_UNSIGNED_INT; + } - ComputeLightPos(LightDist, LightLatitude, LightLongitude, - LightPos, SpotDir); - /* - * Step 1: render scene from point of view of the light source - */ /* compute frustum to enclose spot light cone */ d = ShadowNear * tan(SpotAngle); + glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-d, d, -d, d, ShadowNear, ShadowFar); @@ -265,73 +295,145 @@ Display(void) 0, 0, 0, /* target */ 0, 1, 0); /* up */ + if (UseFBO) { + glTexImage2D(GL_TEXTURE_2D, 0, depthFormat, + ShadowTexWidth, ShadowTexHeight, 0, + depthFormat, depthType, NULL); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowFBO); + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + assert(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) + == GL_FRAMEBUFFER_COMPLETE_EXT); + } + + assert(!glIsEnabled(GL_TEXTURE_1D)); + assert(!glIsEnabled(GL_TEXTURE_2D)); + glViewport(0, 0, ShadowTexWidth, ShadowTexHeight); - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glClear(GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); DrawScene(); - /* - * Step 2: copy depth buffer into texture map - */ - if (DisplayMode == SHOW_DEPTH_MAPPING) { - /* load depth image as gray-scale luminance texture */ - if (UsePackedDepthStencil) { - GLuint *depth = (GLuint *) malloc(ShadowTexWidth * ShadowTexHeight - * sizeof(GLuint)); + if (UseFBO) { + /* all done! */ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } + else { + /* + * copy depth buffer into the texture map + */ + if (DisplayMode == SHOW_DEPTH_MAPPING) { + /* load depth image as gray-scale luminance texture */ + GLuint *depth = (GLuint *) + malloc(ShadowTexWidth * ShadowTexHeight * sizeof(GLuint)); assert(depth); glReadPixels(0, 0, ShadowTexWidth, ShadowTexHeight, - GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, depth); + depthFormat, depthType, depth); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, ShadowTexWidth, ShadowTexHeight, 0, GL_LUMINANCE, GL_UNSIGNED_INT, depth); free(depth); } else { - GLfloat *depth = (GLfloat *) malloc(ShadowTexWidth * ShadowTexHeight - * sizeof(GLfloat)); - assert(depth); - glReadPixels(0, 0, ShadowTexWidth, ShadowTexHeight, - GL_DEPTH_COMPONENT, GL_FLOAT, depth); - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, - ShadowTexWidth, ShadowTexHeight, 0, - GL_LUMINANCE, GL_FLOAT, depth); - free(depth); + /* The normal shadow case - a real depth texture */ + glCopyTexImage2D(GL_TEXTURE_2D, 0, depthFormat, + 0, 0, ShadowTexWidth, ShadowTexHeight, 0); + if (UsePackedDepthStencil) { + /* debug check */ + GLint intFormat; + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, + GL_TEXTURE_INTERNAL_FORMAT, &intFormat); + assert(intFormat == GL_DEPTH_STENCIL_EXT); + } } } - else { - /* The normal shadow case */ - if (UsePackedDepthStencil) { - GLint intFormat; - glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_STENCIL_EXT, - 0, 0, ShadowTexWidth, ShadowTexHeight, 0); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, - GL_TEXTURE_INTERNAL_FORMAT, &intFormat); - assert(intFormat == GL_DEPTH_STENCIL_EXT); - } - else { - glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, - 0, 0, ShadowTexWidth, ShadowTexHeight, 0); - } +} + + +/** + * Show the shadow map as a grayscale image. + */ +static void +ShowShadowMap(void) +{ + glClear(GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, WindowWidth, 0, WindowHeight, -1, 1); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + + glEnable(GL_TEXTURE_2D); + + DisableTexgen(); + + /* interpret texture's depth values as luminance values */ +#if defined(GL_ARB_shadow) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); + glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE); +#endif + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + glBegin(GL_POLYGON); + glTexCoord2f(0, 0); glVertex2f(0, 0); + glTexCoord2f(1, 0); glVertex2f(ShadowTexWidth, 0); + glTexCoord2f(1, 1); glVertex2f(ShadowTexWidth, ShadowTexHeight); + glTexCoord2f(0, 1); glVertex2f(0, ShadowTexHeight); + glEnd(); + + glDisable(GL_TEXTURE_2D); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); +} + + +/** + * Redraw window image + */ +static void +Display(void) +{ + GLenum error; + + ComputeLightPos(LightDist, LightLatitude, LightLongitude, + LightPos, SpotDir); + + if (NeedNewShadowMap) { + RenderShadowMap(); + NeedNewShadowMap = GL_FALSE; } - /* - * Step 3: render scene from point of view of the camera - */ glViewport(0, 0, WindowWidth, WindowHeight); if (DisplayMode == SHOW_DEPTH_IMAGE) { - ShowDepthBuffer(WindowWidth, WindowHeight, 0, 1); + ShowShadowMap(); } else { + /* prepare to draw scene from camera's view */ + const GLfloat ar = (GLfloat) WindowWidth / (GLfloat) WindowHeight; + glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-ar, ar, -1.0, 1.0, 4.0, 50.0); + glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -22.0); glRotatef(Xrot, 1, 0, 0); glRotatef(Yrot, 0, 1, 0); glRotatef(Zrot, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glLightfv(GL_LIGHT0, GL_POSITION, LightPos); + if (LinearFilter) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -340,11 +442,10 @@ Display(void) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } + if (DisplayMode == SHOW_DEPTH_MAPPING) { #if defined(GL_ARB_shadow) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); -#elif defined(GL_SGIX_shadow) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_SGIX, GL_FALSE); #endif glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glEnable(GL_TEXTURE_2D); @@ -358,21 +459,22 @@ Display(void) EnableDistanceTexgen(LightPos, SpotDir, ShadowNear+Bias, ShadowFar); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glEnable(GL_TEXTURE_1D); + assert(!glIsEnabled(GL_TEXTURE_2D)); } else { - assert(DisplayMode == SHOW_NORMAL); + assert(DisplayMode == SHOW_SHADOWS); #if defined(GL_ARB_shadow) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); -#elif defined(GL_SGIX_shadow) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_SGIX, GL_TRUE); #endif glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glEnable(GL_TEXTURE_2D); MakeShadowMatrix(LightPos, SpotDir, SpotAngle, ShadowNear, ShadowFar); EnableIdentityTexgen(); } + DrawScene(); + DisableTexgen(); glDisable(GL_TEXTURE_1D); glDisable(GL_TEXTURE_2D); @@ -392,16 +494,7 @@ Reshape(int width, int height) { WindowWidth = width; WindowHeight = height; - if (width >= 512 && height >= 512) { - ShadowTexWidth = ShadowTexHeight = 512; - } - else if (width >= 256 && height >= 256) { - ShadowTexWidth = ShadowTexHeight = 256; - } - else { - ShadowTexWidth = ShadowTexHeight = 128; - } - printf("Using %d x %d depth texture\n", ShadowTexWidth, ShadowTexHeight); + NeedNewShadowMap = GL_TRUE; } @@ -456,8 +549,9 @@ Key(unsigned char key, int x, int y) DisplayMode = SHOW_DEPTH_MAPPING; break; case 'n': + case 's': case ' ': - DisplayMode = SHOW_NORMAL; + DisplayMode = SHOW_SHADOWS; break; case 'o': if (HaveEXTshadowFuncs) { @@ -465,19 +559,24 @@ Key(unsigned char key, int x, int y) if (Operator >= 8) Operator = 0; printf("Operator: %s\n", OperatorName[Operator]); +#if defined(GL_ARB_shadow) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, OperatorFunc[Operator]); +#endif } break; case 'p': UsePackedDepthStencil = !UsePackedDepthStencil; - if (UsePackedDepthStencil - && !glutExtensionSupported("GL_EXT_packed_depth_stencil")) { + if (UsePackedDepthStencil && !HavePackedDepthStencil) { printf("Sorry, GL_EXT_packed_depth_stencil not supported\n"); UsePackedDepthStencil = GL_FALSE; } else { printf("Use GL_DEPTH_STENCIL_EXT: %d\n", UsePackedDepthStencil); + /* Don't really need to regenerate shadow map texture, but do so + * to exercise more code more often. + */ + NeedNewShadowMap = GL_TRUE; } break; case 'z': @@ -527,6 +626,9 @@ SpecialKey(int key, int x, int y) Yrot -= step; break; } + if (mod) + NeedNewShadowMap = GL_TRUE; + glutPostRedisplay(); } @@ -539,25 +641,39 @@ Init(void) #if defined(GL_ARB_depth_texture) && defined(GL_ARB_shadow) if (!glutExtensionSupported("GL_ARB_depth_texture") || !glutExtensionSupported("GL_ARB_shadow")) { +#else + if (1) { +#endif printf("Sorry, this demo requires the GL_ARB_depth_texture and GL_ARB_shadow extensions\n"); exit(1); } printf("Using GL_ARB_depth_texture and GL_ARB_shadow\n"); -#elif defined(GL_SGIX_depth_texture) && defined(GL_SGIX_shadow) - if (!glutExtensionSupported("GL_SGIX_depth_texture") || - !glutExtensionSupported("GL_SGIX_shadow")) { - printf("Sorry, this demo requires the GL_SGIX_depth_texture and GL_SGIX_shadow extensions\n"); - exit(1); + +#if defined(GL_ARB_shadow_ambient) + HaveShadowAmbient = glutExtensionSupported("GL_ARB_shadow_ambient"); + if (HaveShadowAmbient) { + printf("and GL_ARB_shadow_ambient\n"); } - printf("Using GL_SGIX_depth_texture and GL_SGIX_shadow\n"); #endif + HaveEXTshadowFuncs = glutExtensionSupported("GL_EXT_shadow_funcs"); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + HavePackedDepthStencil = glutExtensionSupported("GL_EXT_packed_depth_stencil"); + UsePackedDepthStencil = HavePackedDepthStencil; +#if defined(GL_EXT_framebuffer_object) + HaveFBO = glutExtensionSupported("GL_EXT_framebuffer_object"); + UseFBO = HaveFBO; + if (UseFBO) { + printf("Using GL_EXT_framebuffer_object\n"); + } +#endif + + /* + * Set up the 2D shadow map texture + */ + glGenTextures(1, &ShadowTexture); + glBindTexture(GL_TEXTURE_2D, ShadowTexture); glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); @@ -565,24 +681,36 @@ Init(void) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); -#elif defined(GL_SGIX_shadow) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_OPERATOR_SGIX, - GL_TEXTURE_LEQUAL_R_SGIX); #endif - + if (HaveShadowAmbient) { #if defined(GL_ARB_shadow_ambient) - if (glutExtensionSupported("GL_ARB_shadow_ambient")) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.3); - printf("and GL_ARB_shadow_ambient\n"); +#endif } -#elif defined(GL_SGIX_shadow_ambient) - if (glutExtensionSupported("GL_SGIX_shadow_ambient")) { - glTexParameterf(GL_TEXTURE_2D, GL_SHADOW_AMBIENT_SGIX, 0.3); - printf("and GL_SGIX_shadow_ambient\n"); + +#if defined(GL_EXT_framebuffer_object) + if (UseFBO) { + glGenFramebuffersEXT(1, &ShadowFBO); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowFBO); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_RENDERBUFFER_EXT, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, + GL_TEXTURE_2D, ShadowTexture, 0); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } #endif - /* setup 1-D grayscale texture image for SHOW_DISTANCE mode */ + /* + * Setup 1-D grayscale texture image for SHOW_DISTANCE mode + */ + glGenTextures(1, &GrayTexture); + glBindTexture(GL_TEXTURE_1D, GrayTexture); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); { GLuint i; GLubyte image[256];