1 /* $Id: shadowtex.c,v 1.4 2001/02/28 18:41:50 brianp Exp $ */
4 * Shadow demo using the GL_SGIX_depth_texture, GL_SGIX_shadow and
5 * GL_SGIX_shadow_ambient extensions.
10 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
26 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 #include "../util/showbuffer.c"
39 #define DEG_TO_RAD (3.14159 / 180.0)
41 static GLint WindowWidth
= 450, WindowHeight
= 300;
42 static GLfloat Xrot
= 15, Yrot
= 0, Zrot
= 0;
44 static GLfloat Red
[4] = {1, 0, 0, 1};
45 static GLfloat Green
[4] = {0, 1, 0, 1};
46 static GLfloat Blue
[4] = {0, 0, 1, 1};
47 static GLfloat Yellow
[4] = {1, 1, 0, 1};
49 static GLfloat LightDist
= 10;
50 static GLfloat LightLatitude
= 45.0;
51 static GLfloat LightLongitude
= 45.0;
52 static GLfloat LightPos
[4];
53 static GLfloat SpotDir
[3];
54 static GLfloat SpotAngle
= 40.0 * DEG_TO_RAD
;
55 static GLfloat ShadowNear
= 4.0, ShadowFar
= 24.0;
56 static GLint ShadowTexWidth
= 256, ShadowTexHeight
= 256;
58 static GLboolean LinearFilter
= GL_FALSE
;
60 static GLfloat Bias
= -0.06;
62 static GLboolean Anim
= GL_TRUE
;
64 static GLuint DisplayMode
;
66 #define SHOW_DEPTH_IMAGE 1
67 #define SHOW_DEPTH_MAPPING 2
68 #define SHOW_DISTANCE 3
78 glTranslatef(1.6, 2.2, 2.7);
79 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, Green
);
81 glutSolidSphere(1.5, 15, 15);
85 glTranslatef(-2.0, 1.2, 2.1);
86 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, Red
);
88 glutSolidDodecahedron();
92 glTranslatef(-0.6, 1.3, -0.5);
93 glScalef(1.5, 1.5, 1.5);
94 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, Yellow
);
96 glutSolidIcosahedron();
100 glTranslatef(0, -1.1, 0);
101 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, Blue
);
105 glVertex3f(-k
, 0, -k
);
106 glVertex3f( k
, 0, -k
);
107 glVertex3f( k
, 0, k
);
108 glVertex3f(-k
, 0, k
);
115 * Load the GL_TEXTURE matrix with the projection from the light
116 * source's point of view.
119 MakeShadowMatrix(const GLfloat lightPos
[4], const GLfloat spotDir
[3],
120 GLfloat spotAngle
, GLfloat shadowNear
, GLfloat shadowFar
)
124 glMatrixMode(GL_TEXTURE
);
126 glTranslatef(0.5, 0.5, 0.5 + Bias
);
127 glScalef(0.5, 0.5, 0.5);
128 d
= shadowNear
* tan(spotAngle
);
129 glFrustum(-d
, d
, -d
, d
, shadowNear
, shadowFar
);
130 gluLookAt(lightPos
[0], lightPos
[1], lightPos
[2],
131 lightPos
[0] + spotDir
[0],
132 lightPos
[1] + spotDir
[1],
133 lightPos
[2] + spotDir
[2],
135 glMatrixMode(GL_MODELVIEW
);
140 EnableIdentityTexgen(void)
142 /* texgen so that texcoord = vertex coord */
143 static GLfloat sPlane
[4] = { 1, 0, 0, 0 };
144 static GLfloat tPlane
[4] = { 0, 1, 0, 0 };
145 static GLfloat rPlane
[4] = { 0, 0, 1, 0 };
146 static GLfloat qPlane
[4] = { 0, 0, 0, 1 };
148 glTexGenfv(GL_S
, GL_EYE_PLANE
, sPlane
);
149 glTexGenfv(GL_T
, GL_EYE_PLANE
, tPlane
);
150 glTexGenfv(GL_R
, GL_EYE_PLANE
, rPlane
);
151 glTexGenfv(GL_Q
, GL_EYE_PLANE
, qPlane
);
152 glTexGeni(GL_S
, GL_TEXTURE_GEN_MODE
, GL_EYE_LINEAR
);
153 glTexGeni(GL_T
, GL_TEXTURE_GEN_MODE
, GL_EYE_LINEAR
);
154 glTexGeni(GL_R
, GL_TEXTURE_GEN_MODE
, GL_EYE_LINEAR
);
155 glTexGeni(GL_Q
, GL_TEXTURE_GEN_MODE
, GL_EYE_LINEAR
);
157 glEnable(GL_TEXTURE_GEN_S
);
158 glEnable(GL_TEXTURE_GEN_T
);
159 glEnable(GL_TEXTURE_GEN_R
);
160 glEnable(GL_TEXTURE_GEN_Q
);
165 * Setup 1-D texgen so that the distance from the light source, between
166 * the near and far planes maps to s=0 and s=1. When we draw the scene,
167 * the grayness will indicate the fragment's distance from the light
171 EnableDistanceTexgen(const GLfloat lightPos
[4], const GLfloat lightDir
[3],
172 GLfloat lightNear
, GLfloat lightFar
)
176 GLfloat nearPoint
[3];
178 m
= sqrt(lightDir
[0] * lightDir
[0] +
179 lightDir
[1] * lightDir
[1] +
180 lightDir
[2] * lightDir
[2]);
182 d
= lightFar
- lightNear
;
184 /* nearPoint = point on light direction vector which intersects the
185 * near plane of the light frustum.
187 nearPoint
[0] = LightPos
[0] + lightDir
[0] / m
* lightNear
;
188 nearPoint
[1] = LightPos
[1] + lightDir
[1] / m
* lightNear
;
189 nearPoint
[2] = LightPos
[2] + lightDir
[2] / m
* lightNear
;
191 sPlane
[0] = lightDir
[0] / d
/ m
;
192 sPlane
[1] = lightDir
[1] / d
/ m
;
193 sPlane
[2] = lightDir
[2] / d
/ m
;
194 sPlane
[3] = -(sPlane
[0] * nearPoint
[0]
195 + sPlane
[1] * nearPoint
[1]
196 + sPlane
[2] * nearPoint
[2]);
198 glTexGenfv(GL_S
, GL_EYE_PLANE
, sPlane
);
199 glTexGeni(GL_S
, GL_TEXTURE_GEN_MODE
, GL_EYE_LINEAR
);
200 glEnable(GL_TEXTURE_GEN_S
);
207 glDisable(GL_TEXTURE_GEN_S
);
208 glDisable(GL_TEXTURE_GEN_T
);
209 glDisable(GL_TEXTURE_GEN_R
);
210 glDisable(GL_TEXTURE_GEN_Q
);
215 ComputeLightPos(GLfloat dist
, GLfloat latitude
, GLfloat longitude
,
216 GLfloat pos
[4], GLfloat dir
[3])
219 pos
[0] = dist
* sin(longitude
* DEG_TO_RAD
);
220 pos
[1] = dist
* sin(latitude
* DEG_TO_RAD
);
221 pos
[2] = dist
* cos(latitude
* DEG_TO_RAD
) * cos(longitude
* DEG_TO_RAD
);
232 GLfloat ar
= (GLfloat
) WindowWidth
/ (GLfloat
) WindowHeight
;
235 ComputeLightPos(LightDist
, LightLatitude
, LightLongitude
,
238 * Step 1: render scene from point of view of the light source
240 /* compute frustum to enclose spot light cone */
241 d
= ShadowNear
* tan(SpotAngle
);
242 glMatrixMode(GL_PROJECTION
);
244 glFrustum(-d
, d
, -d
, d
, ShadowNear
, ShadowFar
);
245 glMatrixMode(GL_MODELVIEW
);
247 gluLookAt(LightPos
[0], LightPos
[1], LightPos
[2], /* from */
248 0, 0, 0, /* target */
251 glViewport(0, 0, ShadowTexWidth
, ShadowTexHeight
);
252 glClear(GL_DEPTH_BUFFER_BIT
);
256 * Step 2: copy depth buffer into texture map
258 if (DisplayMode
== SHOW_DEPTH_MAPPING
) {
259 /* load depth image as gray-scale luminance texture */
260 GLfloat
*depth
= malloc(ShadowTexWidth
* ShadowTexHeight
263 glReadPixels(0, 0, ShadowTexWidth
, ShadowTexHeight
,
264 GL_DEPTH_COMPONENT
, GL_FLOAT
, depth
);
265 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
,
266 ShadowTexWidth
, ShadowTexHeight
, 0,
267 GL_LUMINANCE
, GL_FLOAT
, depth
);
272 /* The normal shadow case */
273 glCopyTexImage2D(GL_TEXTURE_2D
, 0, GL_DEPTH_COMPONENT
,
274 0, 0, ShadowTexWidth
, ShadowTexHeight
, 0);
278 * Step 3: render scene from point of view of the camera
280 glViewport(0, 0, WindowWidth
, WindowHeight
);
281 if (DisplayMode
== SHOW_DEPTH_IMAGE
) {
282 ShowDepthBuffer(WindowWidth
, WindowHeight
, 0, 1);
285 glMatrixMode(GL_PROJECTION
);
287 glFrustum(-ar
, ar
, -1.0, 1.0, 4.0, 50.0);
288 glMatrixMode(GL_MODELVIEW
);
290 glTranslatef(0.0, 0.0, -22.0);
291 glRotatef(Xrot
, 1, 0, 0);
292 glRotatef(Yrot
, 0, 1, 0);
293 glRotatef(Zrot
, 0, 0, 1);
294 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
295 glLightfv(GL_LIGHT0
, GL_POSITION
, LightPos
);
297 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
298 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
301 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
302 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
304 if (DisplayMode
== SHOW_DEPTH_MAPPING
) {
305 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_SGIX
, GL_FALSE
);
306 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
307 glEnable(GL_TEXTURE_2D
);
308 MakeShadowMatrix(LightPos
, SpotDir
, SpotAngle
, ShadowNear
, ShadowFar
);
309 EnableIdentityTexgen();
311 else if (DisplayMode
== SHOW_DISTANCE
) {
312 glMatrixMode(GL_TEXTURE
);
314 glMatrixMode(GL_MODELVIEW
);
315 EnableDistanceTexgen(LightPos
, SpotDir
, ShadowNear
+Bias
, ShadowFar
);
316 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
317 glEnable(GL_TEXTURE_1D
);
320 assert(DisplayMode
== SHOW_NORMAL
);
321 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_SGIX
, GL_TRUE
);
322 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
323 glEnable(GL_TEXTURE_2D
);
324 MakeShadowMatrix(LightPos
, SpotDir
, SpotAngle
, ShadowNear
, ShadowFar
);
325 EnableIdentityTexgen();
329 glDisable(GL_TEXTURE_1D
);
330 glDisable(GL_TEXTURE_2D
);
338 Reshape(int width
, int height
)
341 WindowHeight
= height
;
342 if (width
>= 512 && height
>= 512) {
343 ShadowTexWidth
= ShadowTexHeight
= 512;
345 else if (width
>= 256 && height
>= 256) {
346 ShadowTexWidth
= ShadowTexHeight
= 256;
349 ShadowTexWidth
= ShadowTexHeight
= 128;
351 printf("Using %d x %d depth texture\n", ShadowTexWidth
, ShadowTexHeight
);
359 /*LightLongitude -= 5.0;*/
365 Key(unsigned char key
, int x
, int y
)
367 const GLfloat step
= 3.0;
380 printf("Bias %g\n", Bias
);
384 printf("Bias %g\n", Bias
);
387 DisplayMode
= SHOW_DISTANCE
;
390 LinearFilter
= !LinearFilter
;
391 printf("%s filtering\n", LinearFilter
? "Bilinear" : "Nearest");
394 DisplayMode
= SHOW_DEPTH_IMAGE
;
397 DisplayMode
= SHOW_DEPTH_MAPPING
;
401 DisplayMode
= SHOW_NORMAL
;
418 SpecialKey(int key
, int x
, int y
)
420 const GLfloat step
= 3.0;
421 const int mod
= glutGetModifiers();
427 LightLatitude
+= step
;
433 LightLatitude
-= step
;
439 LightLongitude
+= step
;
445 LightLongitude
-= step
;
457 if (!glutExtensionSupported("GL_SGIX_depth_texture") ||
458 !glutExtensionSupported("GL_SGIX_shadow")) {
459 printf("Sorry, this demo requires the GL_SGIX_depth_texture and GL_SGIX_shadow extensions\n");
463 glTexParameteri(GL_TEXTURE_1D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
464 glTexParameteri(GL_TEXTURE_1D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
465 glTexParameteri(GL_TEXTURE_1D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
466 glTexParameteri(GL_TEXTURE_1D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
467 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
468 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
469 #ifdef GL_SGIX_shadow
470 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_OPERATOR_SGIX
,
471 GL_TEXTURE_LEQUAL_R_SGIX
);
473 #ifdef GL_SGIX_shadow_ambient
474 if (glutExtensionSupported("GL_SGIX_shadow_ambient"))
475 glTexParameterf(GL_TEXTURE_2D
, GL_SHADOW_AMBIENT_SGIX
, 0.3);
478 /* setup 1-D grayscale texture image for SHOW_DISTANCE mode */
482 for (i
= 0; i
< 256; i
++)
484 glTexImage1D(GL_TEXTURE_1D
, 0, GL_LUMINANCE
,
485 256, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, image
);
488 glEnable(GL_DEPTH_TEST
);
489 glEnable(GL_LIGHTING
);
498 printf(" a = toggle animation\n");
499 printf(" i = show depth texture image\n");
500 printf(" m = show depth texture mapping\n");
501 printf(" d = show fragment distance from light source\n");
502 printf(" n = show normal, shadowed image\n");
503 printf(" f = toggle nearest/bilinear texture filtering\n");
504 printf(" b/B = decrease/increase shadow map Z bias\n");
505 printf(" cursor keys = rotate scene\n");
506 printf(" <shift> + cursor keys = rotate light source\n");
511 main(int argc
, char *argv
[])
513 glutInit(&argc
, argv
);
514 glutInitWindowPosition(0, 0);
515 glutInitWindowSize(WindowWidth
, WindowHeight
);
516 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
517 glutCreateWindow(argv
[0]);
518 glutReshapeFunc(Reshape
);
519 glutKeyboardFunc(Key
);
520 glutSpecialFunc(SpecialKey
);
521 glutDisplayFunc(Display
);