home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
zip
/
graphics
/
utility
/
raymovi2.lzh
/
RAYMOVI2
/
SHADE.C
(
.txt
)
< prev
next >
Wrap
C/C++ Source or Header
|
1988-12-21
|
8KB
|
268 lines
/*
From harvard!husc6!caip!nike!ucbcad!ucbvax!sdcsvax!net1!fritzz 25 Jul 86 21:35:59 GMT
Article 2915 of net.sources:
Relay-Version: version B 2.10.2 9/18/84; site bbnccv.UUCP
Path: bbnccv!harvard!husc6!caip!nike!ucbcad!ucbvax!sdcsvax!net1!fritzz
>From: fritzz@net1.UCSD.EDU (Friedrich Knauss)
Newsgroups: net.sources
Subject: basic ray tracing: part 1 (tracer.c)
Message-ID: <190@net1.UCSD.EDU>
Date: 25 Jul 86 21:35:59 GMT
Date-Received: 27 Jul 86 01:07:29 GMT
Reply-To: fritzz@net1.UUCP (Friedrich Knauss)
Organization: University of California, San Diego
*/
/*
* this subroutine does all the gritty work- it calculates
* what shade each pixel should be. I like recursion.
*/
#include <math.h>
#include "rtd.h"
#include "extern.h"
#define time(x) 0
/* LEVEL defines number of levels of recursion */
#define LEVEL 5
int debug;
#define dprintf if (debug) printf
shade (r, red, green, blue)
struct ray *r;
double *red, *green, *blue;
{ int i, c,
refract ();
struct ray refr;
double rd, gn, blu, tmp;
double lght_red, lght_green, lght_blue,
x, y, z,
l, k,
dot (), find (), findo ();
struct vector new, norm;
struct mat trans;
struct sphere ss;
if (++level <= LEVEL)
{ c = -1;
l = HUGE;
dprintf("LEVEL %d: ", level);
/* get vector length and xz component for mt() */
vecl (&r->dir);
vexzl (&r->dir);
/* make a transform matrix that rotates something in space so
that the ray will be aligned with the x axis */
mt (&r->dir, &trans);
/* for starters we find out whether we hit anything. */
for (i = 0; i < nob; i++)
{ ss.rad = bl[i].s.rad;
sv (&ss.cent, &bl[i].s.cent, &r->org);
if ((k = find (&trans, &ss)) > 0.0 && k < l)
{ c = i;
l = k;
}
}
if (c >= 0.0) /* WE HIT SOMETHING */
{ x = l * trans.x.x;
y = l * trans.x.y;
z = l * trans.x.z;
mv (x, y, z, &new);
/* move the new orgin of the ray to the intersection */
av (&refr.org, &new, &r->org);
av (&r->org, &new, &r->org);
mv (r->dir.x, r->dir.y, r->dir.z, &refr.dir);
/* get a normal vector for the intersection point */
sv (&norm, &r->org, &bl[c].s.cent);
vecl (&norm);
/* ambient lighting */
tmp = 255.0 * bl[c].amb;
lght_red = tmp * bl[c].red;
lght_green = tmp * bl[c].green;
lght_blue = tmp * bl[c].blue;
dprintf(" ball[%d]", c);
dprintf(", ambient=%d,%d,%d\n",
(int)lght_red, (int)lght_green, (int)lght_blue);
/* shaded lighting (diffuse). subroutine shadow is in find.c */
if (bl[c].dif != 0.0)
{ sv (&new, &ls.cent, &r->org);
vecl (&new);
if ((k = dot (&new, &norm)) > 0.0)
{ shadow (&r->org, &rd, &gn, &blu);
dprintf("diffuse = %d, %d, %d\n",(int)rd,(int)gn,(int)blu);
tmp = bl[c].dif * k / (new.l * norm.l);
lght_red += tmp * rd * bl[c].red;
lght_green += tmp * rd * bl[c].green;
lght_blue += tmp * rd * bl[c].blue;
} }
/*reflection... easy */
if (bl[c].rfl != 0.0)
{ vecl (&norm);
/* make the normal unit length */
scamult ((1.0 / norm.l), &norm);
/* get the length of the ray's component in the normal direction */
x = 2.0 * dot (&norm, &r->dir);
scamult (x, &norm);
/* subtract double the normal component- !reflection! */
sv (&r->dir, &r->dir, &norm);
shade (r, &rd, &gn, &blu);
dprintf("reflection = %d, %d, %d, tmp=%d\n",
(int)rd, (int)gn, (int)blu, (int)tmp);
tmp = bl[c].rfl;
lght_red += tmp * rd;
lght_green += tmp * gn;
lght_blue += tmp * blu;
}
/* refraction. this is ugly, which is why I choose to deal with
it in it's own subroutine which comes after this one */
if (bl[c].rfr != 0.0)
{ dprintf(" refraction\n");
refract (&refr, &bl[c], &rd, &gn, &blu);
tmp = bl[c].rfr;
dprintf("refraction = %d, %d, %d\n",(int)rd,(int)gn,(int)blu);
lght_red += tmp * rd;
lght_green += tmp * gn;
lght_blue += tmp * blu;
} }
else /* hit no objects... */
{ if ((r->dir.y) < 0.0) /* crosses floor */
{ z = -(r->org.y) / (r->dir.y);
(r->org.x) += z * (r->dir.x);
(r->org.z) += z * (r->dir.z);
(r->org.y) = 0.0;
dprintf("floor (%d, %d): ", (int)r->org.x, (int)r->org.z);
if ( ((int) ((r->org.x) / 9.0) % 8 == 0)
|| ((int) ((r->org.z) / 9.0) % 8 == 0))
{ lght_red = lght_green = lght_blue = 0.0;
dprintf("black. 0,0,0\n");
} /* this is for texture, grid on the ground */
else /* get shading for the squares... */
{ sv (&new, &ls.cent, &r->org);
vecl (&new);
shadow (&r->org, &rd, &gn, &blu);
tmp = 0.6 * new.y / new.l;
lght_blue = tmp * blu + 100.0; /* tile pattern: */
if ((int)r->org.x/72 & (int)r->org.z/72 & 0x15)
{ lght_red = lght_green = 0.0; /* blue */
dprintf("blue. %d, %d, %d\n",
(int)lght_red, (int)lght_green, (int)lght_blue);
}
else
{ lght_red = tmp * rd + 100.0; /* white */
lght_green = tmp * gn + 100.0;
dprintf("white. %d,%d,%d\n",
(int)lght_red, (int)lght_green, (int)lght_blue);
} } }
else /* didn't hit ground... sky */
{ lght_red = lght_green = lght_blue = 0.0;
dprintf("sky. %d,%d,%d\n",
(int)lght_red, (int)lght_green, (int)lght_blue);
}
dprintf("lght_= %d,%d,%d\n",
(int)lght_red, (int)lght_green, (int)lght_blue);
} }
/* to many levels return 0 cause it shouldn't matter */
else
{ lght_red = lght_green = lght_blue = 0.0;
dprintf(">5 levels. 0, 0, 0\n");
}
level--;
if (lght_red < 0.0) lght_red = 0.0;
if (lght_red > 255.0) lght_red = 255.0;
if (lght_green < 0.0) lght_green = 0.0;
if (lght_green > 255.0) lght_green = 255.0;
if (lght_blue < 0.0) lght_blue = 0.0;
if (lght_blue > 255.0) lght_blue = 255.0;
*red = lght_red;
*green = lght_green;
*blue = lght_blue;
dprintf("returned: %d, %d, %d\n", (int)*red, (int)*green, (int)*blue);
}
int refract (r, bll, red, green, blue)
struct ray *r;
struct ball *bll;
double *red, *green, *blue;
{
struct vector new, norm;
struct mat trans;
double l,
refk ();
struct sphere ss;
sv (&norm, &r->org, &bll->s.cent);
vecl (&norm);
vecl (&r->dir);
/* get the addition factor for the normal */
scamult (refk (&norm, &r->dir, bll->ior), &norm);
av (&r->dir, &r->dir, &norm);
/* find the point where the ray leaves the sphere. just like shade. */
vexzl (&r->dir);
vecl (&r->dir);
mt (&r->dir, &trans);
ss.rad = bll->s.rad;
sv (&ss.cent, &bll->s.cent, &r->org);
l = findo (&trans, &ss);
mv (l * trans.x.x, l * trans.x.y, l * trans.x.z, &new);
av (&r->org, &r->org, &new);
/* redirect the ray and continue tracing */
sv (&norm, &r->org, &bll->s.cent);
vecl (&norm);
vecl (&r->dir);
scamult (refk (&norm, &r->dir, 1.0 / bll->ior), &norm);
av (&r->dir, &r->dir, &norm);
shade (r, red, green, blue);
}
double refk (nrm, in, ior)
struct vector *nrm, *in;
double ior;
{ double dt, ln, li, ret;
dt = dot (nrm, in);
ln = nrm->x * nrm->x + nrm->y * nrm->y + nrm->z * nrm->z;
li = in->x * in->x + in->y * in->y + in->z * in->z;
ret = dt * dt - ln * li * (1 - ior);
if (ret < 0.0)
ret = 0.0;
if (dt < 0)
ret = (-dt - sqrt (ret)) / ln;
else
ret = (-dt + sqrt (ret)) / ln;
return (ret);
}
printv(s, v)
char *s;
struct vector *v;
{ printf("%s.x = %f, .y = %f, .z = %f\n", s, v->x, v->y, v->z);
}