This is shade.c in view mode; [Download] [Up]
/* * (c) 1988 by George Kyriazis */ /* * here is the shading function */ #include "ray.h" #include "vector.h" #include <math.h> struct color trace(); struct intersect intersect(); struct ray sample_ray(); /* * Shadow check. Check if the ray from the intersection point to the * light, intersection any objects inbetween. If it does, we have a * shadow. * One improvement that can be made is to check the transparencies of all * the intersecting objects and make the shadow have a different intensity * depending on the transparency of the objects */ int shadow(r) struct ray r; { struct intersect i; struct ray r2; /* to have a shadow, the light ray must intersect an object */ /* first sample the ray around the shadow ray */ r2 = sample_ray(r, r.theta); i = intersect(r2); if( i.obj == NULL ) return FALSE; else return (r.obj != i.obj); } /* * calculate the reflection vector. * D. Rogers: "Procedural elements for computer graphics". 5-12. p. 367 */ struct vector reflect(n,v1) struct vector n, v1; { struct vector v2; v2 = vsub( v1, svproduct( 2 * vdot(n, v1), n) ); return v2; } /* * calculate the refracted vector. * D. Rogers: "Procedural elements for computer graphics". 5-12. p. 367 */ struct vector refract(n, v1, index) struct vector n, v1; double index; { double p, t; struct vector v2; v2.x = 0.; v2.y = 0.; v2.z = 0.; p = vdot(n, v1); if(p < 0) { t = 1 - ( 1 - p*p ) / ( index*index ); if( t <= 0 ) return v2; t = -p/index - sqrt(t); } else { index = 1 / index; t = 1 - ( 1 - p*p ) / ( index*index ); if( t <= 0 ) return v2; t = -p/index + sqrt(t); } v2 = vadd( svproduct(1/index, v1), svproduct(t, n) ); return v2; } /* * the actual shading function. Recursively calls trace() */ struct color shade(i, r, n) struct intersect i; struct ray r; int n; /* recursion level */ { struct color col; struct vector pt; struct ray shadow_ray; struct vector ldir; int shad; double ldot; double spec; struct vector rr; /* reflected light direction */ struct ray reflected, refracted; /* refl, refr directions */ struct color c; /* if the recursion level has been exceeded, return peacefully*/ if(n > MAXLEVEL) { col.r = col.g = col.b = 0.; return col; } /* initially get the ambient color */ col = i.obj->ambient; /* first calculate the intersection point */ pt = vadd( r.pos, svproduct(i.t, r.dir) ); /* for the light source first get the vector from it to the intersection */ ldir = norm( vsub(light.org, pt) ); /* then calc the dot product between the light direction and the normal */ /* negative because the light direction is reverse (comes from the light) */ ldot = vdot(i.n, ldir); /* and find if that shadow ray is stopped by an object */ shadow_ray.pos = pt; shadow_ray.dir = ldir; shadow_ray.obj = i.obj; /* the following is the spreading angle of the ray */ shadow_ray.theta = light.angle; shad = shadow(shadow_ray); if( (ldot>0) && !shad ) { /* statistics */ shadowline++; /* add some diffuse color. */ col.r += ldot * i.obj->diffuse.r; col.g += ldot * i.obj->diffuse.g; col.b += ldot * i.obj->diffuse.b; /* now calc the specular color */ /* first calculate the reflected light vector */ rr = reflect(i.n, ldir); /* then take the dot of the reflected ray with the viewing direction */ /* that is the specular component. The minus is there for obvious reasons */ spec = vdot(rr, r.dir); spec = (spec < 0) ? 0 : spec; /* remember the specular width factor? We use it here! */ spec = pow(spec, i.obj->width); col.r += spec * i.obj->specular.r; col.g += spec * i.obj->specular.g; col.b += spec * i.obj->specular.b; } /* setup the reflected ray */ reflected.pos = pt; reflected.dir = reflect(i.n, r.dir); reflected.obj = i.obj; reflected.theta = i.obj->refl_diffuse; /* calculate the reflection */ reflectline++; c = trace(reflected, n+1); col.r += c.r * i.obj->refl_color.r * i.obj->reflection; col.g += c.g * i.obj->refl_color.g * i.obj->reflection; col.b += c.b * i.obj->refl_color.b * i.obj->reflection; /* now setup the refracted ray */ refracted.pos = pt; refracted.dir = refract(i.n, r.dir, i.obj->index); refracted.obj = i.obj; refracted.theta = i.obj->refr_diffuse; if( (refracted.dir.x == 0.) && (refracted.dir.y == 0.) && (refracted.dir.z == 0.) ) return col; /* and calculate the reflection */ refractline++; c = trace(refracted, n+1); col.r += c.r * i.obj->refr_color.r * i.obj->refraction; col.g += c.g * i.obj->refr_color.g * i.obj->refraction; col.b += c.b * i.obj->refr_color.b * i.obj->refraction; return col; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.