home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
GRAPHICS
/
rayshade.lzh
/
shade.c
< prev
next >
Wrap
Text File
|
1990-05-08
|
11KB
|
396 lines
/*
* shade.c
*
* Copyright (C) 1989, Craig E. Kolb
*
* This software may be freely copied, modified, and redistributed,
* provided that this copyright notice is preserved on all copies.
*
* There is no warranty or other guarantee of fitness for this software,
* it is provided solely . Bug reports or fixes may be sent
* to the author, who may or may not act on them as he desires.
*
* You may not include this software in a program or other software product
* without supplying the source, or without informing the end-user that the
* source is available for no extra charge.
*
* If you modify this software, you should include a notice giving the
* name of the person performing the modification, the date of modification,
* and the reason for such modification.
*
* $Id: shade.c,v 3.0.1.3 90/04/04 19:04:19 craig Exp $
*
* $Log: shade.c,v $
* Revision 3.0.1.3 90/04/04 19:04:19 craig
* patch5: Corrected free()-related problems.
*
* Revision 3.0.1.2 90/03/07 21:31:21 craig
* patch4: Replaced call to LightCoordSys() with call to VectCoordSys().
*
* Revision 3.0.1.1 89/11/16 20:34:42 craig
* patch1: Atmospheric effects are now applied to background rays.
*
* Revision 3.0 89/10/27 02:06:03 craig
* Baseline for first official release.
*
*/
#include <math.h>
#include <stdio.h>
#include "constants.h"
#include "typedefs.h"
#include "funcdefs.h"
#include "atmosphere.h"
int level, maxlevel; /* Current tree depth, max depth */
double DefIndex = 1.0; /* Default index of refraction. */
double TreeCutoff = UNSET; /* Minimum contribution of any ray. */
/*
* Calculate color of ray.
*/
ShadeRay(hitinfo, ray, dist, back, color, contrib)
HitInfo *hitinfo; /* Information about point of intersection. */
Ray *ray; /* Direction and origin of ray. */
double dist; /* Distance from origin of intersection. */
Color *back; /* "Background" color */
Color *color; /* Color to assign current ray. */
double contrib; /* Contribution of this ray to final color */
{
Vector hit;
double realdist;
extern unsigned long HitRays;
extern Fog *GlobalFog;
extern Mist *GlobalMist;
if (dist <= 0.) {
/*
* No valid intersection. Set distance for atmospheric
* effects and set color of ray to background.
*/
realdist = FAR_AWAY;
*color = *back;
addscaledvec(ray->pos, realdist, ray->dir, &hit);
} else {
realdist = dist;
/*
* If we got here, then a ray hit something, so...
*/
HitRays++;
(void)normalize(&hitinfo->norm);
/*
* "hit" is the location of intersection in world space.
* hitinfo->pos is the intersection point in object space.
*/
addscaledvec(ray->pos, dist, ray->dir, &hit);
/*
* Calculate ray color.
*/
shade(&hit, ray, &hitinfo->norm, hitinfo->prim, &hitinfo->surf,
back, color, contrib);
}
/*
* If fog or mist is present, modify computed color.
*/
if (GlobalFog)
ComputeFog(GlobalFog, realdist, color);
if (GlobalMist)
ComputeMist(GlobalMist, &ray->pos, &hit, realdist, color);
}
shade(pos, ray, nrm, prim, surf, back, color, contrib)
Vector *pos, *nrm;
Ray *ray;
Primitive *prim;
Surface *surf;
Color *back, *color;
double contrib;
{
int lnum, entering;
double dist, k;
Color newcol;
Ray NewRay;
HitInfo hitinfo;
Vector refl;
Light *lp;
extern int nlight;
extern Light light[];
extern unsigned long ReflectRays, RefractRays;
extern double TraceRay();
/*
* Ambient color is always included.
*/
*color = surf->amb;
/*
* Calculate direction of reflected ray.
*/
k = -dotp(&ray->dir, nrm);
addscaledvec(ray->dir, 2.*k, *nrm, &refl);
/*
* Calculate intensity contributed by each light source.
*/
for(lnum = 0, lp = light;lnum < nlight; lnum++, lp++) {
if (lp->type == EXTENDED)
extended_lightray(pos, nrm, &refl, lp,
prim, surf, color);
else
generic_lightray(pos, nrm, &refl, lp,
prim, surf, color);
}
if (level >= maxlevel)
/*
* Don't spawn any refracted/reflected rays.
*/
return;
/*
* Specular reflection.
*/
if(surf->refl > 0. && contrib * surf->refl > TreeCutoff) {
level++;
NewRay.shadow = FALSE;
NewRay.pos = *pos; /* Origin == hit point */
NewRay.dir = refl; /* Direction == reflection */
NewRay.media = ray->media; /* Medium == old medium */
ReflectRays++;
dist = TraceRay(prim, &NewRay, &hitinfo);
ShadeRay(&hitinfo, &NewRay, dist, back, &newcol,
contrib*surf->refl);
AddScaledColor(*color, surf->refl, newcol, color);
level--;
}
/*
* Specular transmission (refraction).
*/
if(surf->transp > 0. && contrib * surf->transp > TreeCutoff) {
NewRay.shadow = FALSE;
NewRay.pos = *pos; /* Origin == hit point */
NewRay.media = ray->media; /* Media == old media */
if (k < 0.) {
/*
* Normal points "away" from incoming ray.
* Hit "inside" surface -- assume we're exiting.
* Pop medium from stack.
*/
if (NewRay.media == (SurfaceList *)0)
/*
* We had a funky intersection at some
* point -- e.g. we hit at the intersection
* of two refracting surfaces. Skip it.
*/
return;
NewRay.media = NewRay.media->next;
if (refract(&NewRay.dir, surf->kref,
NewRay.media ? NewRay.media->surf->kref :
DefIndex, ray->dir, *nrm, k))
return;
entering = FALSE;
} else {
/*
* Entering surface.
*/
if (refract(&NewRay.dir,
NewRay.media ? NewRay.media->surf->kref :
DefIndex, surf->kref, ray->dir, *nrm, k))
return;
NewRay.media = add_surface(surf, NewRay.media);
entering = TRUE;
}
level++;
RefractRays++;
dist = TraceRay((Primitive *)NULL, &NewRay, &hitinfo);
ShadeRay(&hitinfo, &NewRay, dist, back, &newcol,
contrib * surf->transp);
AddScaledColor(*color, surf->transp, newcol, color);
if (entering)
free((char *)NewRay.media);
level--;
}
}
/*
* Sample an extended (area) light source.
*/
extended_lightray(pos, norm, refl, lp, obj, surf, color)
Vector *pos, *norm, *refl;
Light *lp;
Primitive *obj;
Surface *surf;
Color *color;
{
int uSample, vSample;
double jit, vbase, ubase, vpos, upos;
Color newcol;
Vector Uaxis, Vaxis, toLight, SampleDir;
extern double lightdist, JitterWeight, SampleSpacing;
extern int JitSamples, Jittered, SampleNumber;
/*
* Determinte two orthoganal vectors which line in the plane
* whose normal is defined by the vector from the center
* of the light source to the point of intersection and
* which passes through the center of the light source.
*/
vecsub(lp->pos, *pos, &toLight);
VectCoordSys(&toLight, &Uaxis, &Vaxis);
jit = 2. * lp->radius * SampleSpacing;
if (Jittered) {
/*
* Sample a single point, determined by SampleNumber,
* on the extended source.
*/
vpos = -lp->radius + (SampleNumber % JitSamples) * jit;
upos = -lp->radius + (SampleNumber / JitSamples) * jit;
vpos += nrand() * jit;
upos += nrand() * jit;
veccomb(upos, Uaxis, vpos, Vaxis, &SampleDir);
vecadd(toLight, SampleDir, &SampleDir);
/*
* Lightdist, the distance to the light source, is
* used by inshadow(), called from Lighting().
*/
lightdist = normalize(&SampleDir);
Lighting(pos,norm,refl,lp,obj,surf,&SampleDir,color);
return;
}
newcol.r = newcol.g = newcol.b = 0.;
/*
* Sample JitSamples^2 -4 points arranged in a square lying on the
* plane calculated above. The size of the square is equal to
* the diameter of the light source. We sample the square at equal
* intervals in the U and V direction, with "jitter" thrown in to mask
* aliasing. The corners of the square are skipped to speed up
* the calculation and to more closely model a circular source.
*/
ubase = -lp->radius;
for(uSample = 1;uSample <= JitSamples;uSample++, ubase += jit) {
vbase = -lp->radius;
for(vSample=1;vSample <= JitSamples;vSample++,vbase += jit) {
/*
* Skip corners.
*/
if ((uSample == 1 || uSample == JitSamples) &&
(vSample == 1 || vSample == JitSamples))
continue;
vpos = vbase + nrand() * jit;
upos = ubase + nrand() * jit;
veccomb(upos, Uaxis, vpos, Vaxis, &SampleDir);
vecadd(toLight, SampleDir, &SampleDir);
lightdist = normalize(&SampleDir);
Lighting(pos, norm, refl, lp, obj, surf,
&SampleDir, &newcol);
}
}
AddScaledColor(*color, JitterWeight, newcol, color);
}
/*
* Lighting calculations for a point or directional light source.
*/
generic_lightray(pos, norm, reflect, lp, obj, surf, color)
Vector *pos, *norm, *reflect;
Light *lp;
Primitive *obj;
Surface *surf;
Color *color;
{
Vector Nlightray;
lightray(lp, pos, &Nlightray);
Lighting(pos, norm, reflect, lp, obj, surf, &Nlightray, color);
}
/*
* Compute shading function (diffuse reflection and specular highlight)
* given the point of intersection, incident ray, normal to the surface,
* direction of the reflected ray,
* the current light source, the object hit, the surface hit, and
* the ray to the current light source.
*
* This function *adds* the computed color to "color".
*/
Lighting(pos, norm, refl, lp, obj, surf, tolight, color)
Vector *pos, *norm, *refl, *tolight;
Light *lp;
Primitive *obj;
Surface *surf;
Color *color;
{
Color bright;
double intens;
/*
* Diffuse reflection.
* Falls off as the cosine of the angle between
* the normal and the ray to the light.
*/
intens = dotp(norm, tolight);
if(intens <= 0.) {
/*
* Object does not face light source.
* If the surface is translucent, add in
* diffuse and specular components due to
* light hitting the other side of the surface.
* (This is a "poor man's" diffuse transmission
* and specularly transmitted highlights. Note
* that we ignore index of refraction here...)
*/
if (surf->translucency == 0.)
return;
if (inshadow(&bright, obj, lp, pos, tolight))
return;
/*
* We use -translucency to counter the fact
* that intens is < 0.
*/
intens *= -surf->translucency;
color->r += surf->diff.r * intens * bright.r;
color->g += surf->diff.g * intens * bright.g;
color->b += surf->diff.b * intens * bright.b;
intens = -dotp(refl, tolight);
if (intens <= 0.)
return;
intens = surf->translucency * pow(intens, surf->stcoef);
color->r += surf->spec.r * intens * bright.r;
color->g += surf->spec.g * intens * bright.g;
color->b += surf->spec.b * intens * bright.b;
return;
}
/*
* Add diffuse reflection component.
*/
if (inshadow(&bright, obj, lp, pos, tolight))
return; /* Object in shadow. */
color->r += surf->diff.r * intens * bright.r;
color->g += surf->diff.g * intens * bright.g;
color->b += surf->diff.b * intens * bright.b;
/*
* Specularly reflected highlights.
* Fall off as the cosine of the angle
* between the reflected ray and the ray to the light source.
*/
if (surf->coef < EPSILON)
return;
intens = dotp(refl, tolight);
if(intens <= 0.)
return;
/*
* Specular highlight = cosine of the angle raised to the
* appropriate power.
*/
intens = pow(intens, surf->coef);
color->r += surf->spec.r * intens * bright.r;
color->g += surf->spec.g * intens * bright.g;
color->b += surf->spec.b * intens * bright.b;
}