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.