diff options
author | Eric Anholt <eric@anholt.net> | 2009-07-31 17:19:28 -0700 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2009-07-31 17:19:54 -0700 |
commit | afac7d4b1b156636e99676a2632a2a3e32442f79 (patch) | |
tree | 0e7aeda24716a757d30ad25e1ef07c8568e0ad4a | |
parent | 9edec97711106d69b2030a20d4528c2726741eed (diff) |
Bound the shadow frustum more closely.
-rw-r--r-- | glass.h | 3 | ||||
-rw-r--r-- | matrix.c | 48 | ||||
-rw-r--r-- | shadow_map.c | 11 |
3 files changed, 53 insertions, 9 deletions
@@ -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); @@ -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); } |