home *** CD-ROM | disk | FTP | other *** search
- /*
- 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);
- }
-