summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2009-07-31 17:19:28 -0700
committerEric Anholt <eric@anholt.net>2009-07-31 17:19:54 -0700
commitafac7d4b1b156636e99676a2632a2a3e32442f79 (patch)
tree0e7aeda24716a757d30ad25e1ef07c8568e0ad4a
parent9edec97711106d69b2030a20d4528c2726741eed (diff)
Bound the shadow frustum more closely.
-rw-r--r--glass.h3
-rw-r--r--matrix.c48
-rw-r--r--shadow_map.c11
3 files changed, 53 insertions, 9 deletions
diff --git a/glass.h b/glass.h
index d122e86..f3dc795 100644
--- a/glass.h
+++ b/glass.h
@@ -84,6 +84,9 @@ void init_m4_perspective(float *mat4, float fovy, float aspect,
void print_m4(const float *mat4, const char *name);
void print_GLUvec4(char *desc, const GLUvec4 *vec);
void print_GLUmat4(char *desc, const GLUmat4 *m);
+void make_sphere_frustum(GLUmat4 *mat,
+ GLUvec4 *center,
+ float radius);
/* load_texture.c */
GLuint load_texture_rgb(const char *filename);
diff --git a/matrix.c b/matrix.c
index 8aa02e6..f81d830 100644
--- a/matrix.c
+++ b/matrix.c
@@ -30,6 +30,7 @@
#include <stdlib.h>
#include <math.h>
#include <string.h>
+#include <assert.h>
#include "glass.h"
@@ -212,3 +213,50 @@ print_GLUmat4(char *desc, const GLUmat4 *m)
i == 0 ? "" : "}");
}
}
+
+static float length_3v(GLUvec4 *vec)
+{
+ return sqrt(vec->values[0] * vec->values[0] +
+ vec->values[1] * vec->values[1] +
+ vec->values[2] * vec->values[2]);
+}
+
+void
+make_sphere_frustum(GLUmat4 *mat,
+ GLUvec4 *center,
+ float radius)
+{
+ float near_radius;
+ float center_distance = length_3v(center);
+ float near = center_distance - radius;
+ float far = center_distance + radius;
+
+ assert(near > 0);
+
+ /* We want to make a frustum that just bounds the sphere.
+ * Obviously the near/far will the length of the vector to the center
+ * plus or minus the radius. For gluFrustum6, though, the l/r/t/b values
+ * are on the near plane, so we have to figure out where a line from
+ * the eye (0,0,0) tangent to the sphere ends up intersecting the near
+ * plane.
+ *
+ * Given hideous ASCII art:
+ * ___
+ * / \/\__ a = sqrt(n*n+2rn)
+ * / r/\|t \__
+ * | /__|_____\
+ * | r | n
+ * \ /
+ * \_/
+ *
+ * then tan θ = r/a = t/n.
+ * so t = nr/a = nr/sqrt(n*n+2rn).
+ */
+
+ near_radius = near * radius / sqrt(near * near + 2.0 * near * radius);
+
+ gluFrustum6(mat,
+ -near_radius, near_radius,
+ -near_radius, near_radius,
+ near, far);
+}
diff --git a/shadow_map.c b/shadow_map.c
index 38fc0fb..073ec6a 100644
--- a/shadow_map.c
+++ b/shadow_map.c
@@ -50,7 +50,6 @@ calculate_light_projection(void)
GLUvec4 light_up;
GLUmat4 temp;
GLUvec4 light_to_rings;
- float light_distance_to_rings;
/* Wrong. So wrong. */
light_up.values[0] = 1.0;
@@ -69,9 +68,6 @@ calculate_light_projection(void)
*/
gluSub4v_4v(&light_to_rings,
&ring_bounding_sphere_center_world, &light_world);
- light_distance_to_rings = gluLength4v(&light_to_rings);
-
- assert(light_distance_to_rings > ring_bounding_sphere_radius);
/* Transform for looking from they eye's point of view at the pile of
* rings.
@@ -80,11 +76,8 @@ calculate_light_projection(void)
&light_world,
&ring_bounding_sphere_center_world,
&light_up);
- gluFrustum6(&temp,
- -ring_bounding_sphere_radius, ring_bounding_sphere_radius,
- -ring_bounding_sphere_radius, ring_bounding_sphere_radius,
- light_distance_to_rings - ring_bounding_sphere_radius,
- light_distance_to_rings + ring_bounding_sphere_radius);
+ make_sphere_frustum(&temp, &light_to_rings,
+ ring_bounding_sphere_radius);
/*print_GLUmat4("frustum", &temp);*/
gluMult4m_4m(&world_to_light_ndc, &temp, &world_to_light_eye);
}