home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * (c) 1988 by George Kyriazis
- */
-
- /*
- * This is the actual ray-tracing part
- */
-
- #include "ray.h"
- #include "vector.h"
- #include <stdio.h>
- #include <math.h>
-
- struct intersect intersect();
- struct color shade();
- struct color bgcolor();
-
- double quickcos(x)
- double x;
- {
- double val;
-
- val = 1 - x*x/2.4684;
-
- return val;
- }
-
- double quickinvcos(x)
- double x;
- {
- double val;
-
- val = sqrt(2.4684*(1-x));
-
- return val;
- }
-
- /*
- * floating point random number generator
- */
- double rnd()
- {
- double t;
-
- t = (double)( random() & 0xffffff ) / 16777215;
-
- return t;
- }
-
- /*
- * Random number between -1 and 1
- */
- double rand1()
- {
- return ( rnd()*2 - .5 );
- }
-
- /*
- * approximate a gaussian random number generator between -1 and 1
- */
- double grand()
- {
- double t;
-
- /* get a random number between -1 and 1 */
- t = ( rnd() - .5 ) * 2;
-
- /* and then square it. DOn't lose the sign! */
- return (t*ABS(t));
- }
-
- /*
- * pick a random ray somewhere inside the solid angle
- */
- struct ray sample_ray(r, theta)
- struct ray r;
- double theta;
- {
- double phi1, phi2;
- struct vector c; /* directional cosines */
- struct ray r2;
-
- /*
- * adds the following 2 angles in 2 of the 3 angles specified by the
- * directional cosines
- */
- phi1 = grand() * theta;
- phi2 = grand() * theta;
-
- c = r.dir;
-
- /* choose two of them that are linearly independent */
- if( c.x > .5 ) {
- c.x = quickcos(quickinvcos(c.x) + phi1);
- c.y = quickcos(quickinvcos(c.y) + phi2);
- } else
- if( c.y < .5 ) {
- c.y = quickcos(quickinvcos(c.y) + phi1);
- c.z = quickcos(quickinvcos(c.z) + phi2);
- } else {
- c.z = quickcos(quickinvcos(c.z) + phi1);
- c.x = quickcos(quickinvcos(c.x) + phi2);
- }
-
- /* the third directional cosine is fixed when normalizing */
- r2.pos = r.pos;
- r2.dir = norm( c );
- r2.theta = 0;
- r2.obj = r.obj;
-
- return r2;
- }
-
- /*
- * trace a single strait ray
- */
- struct color trace_a_ray(r, n)
- struct ray r;
- int n; /* recursion level */
- {
- struct intersect inter;
- struct color col;
- double m;
-
- /* update stats */
- rayline++;
- /* check for intersection with the object */
- inter = intersect(r);
- /* if no intersection, return some background color */
- if( inter.obj == NULL )
- return bgcolor(r);
- /* more stats */
- intersectline++;
- /* else calculate the shading function there */
- col = shade(inter, r, n);
- /* if the color > 1, that means that the components are too big. Normalize. */
- m = col.r;
- if( col.g > m )
- m = col.g;
- if( col.b > m )
- m = col.b;
- if( m > 1 ) {
- /* overflow condition */
- /* normalize it! */
- col.r /= m;
- col.g /= m;
- col.b /= m;
- }
- return col;
- }
-
- /*
- * Trace a ray within the specified solid angle
- */
- struct color trace(r, n)
- struct ray r;
- int n;
- {
- struct ray r2;
-
- r2 = sample_ray(r, r.theta);
-
- return ( trace_a_ray(r2, n) );
- }
-
- /*
- * raytrace the whole scene
- */
- raytrace(fname)
- char *fname;
- {
- int x, y, x1, y1;
- double xr, yr, xstep, ystep;
- struct color col, color;
- struct ray ray, r2;
- int r, g, b;
- double m;
- FILE *f;
- int i;
- double p_w;
-
- p_w = fov / MIN(xres, yres); /* pixel width in radians */
-
- hor = norm( vcross(up, eye_dir) ); /* the x screen vector */
- ver = norm( vcross( eye_dir, hor) ); /* the y screen vector */
-
- f = fopen(fname, "w");
- if(f == NULL) {
- perror("fopen");
- exit(1);
- }
-
- ray.pos = eye; /* eye is the beginning of the ray */
-
- ray.obj = NULL; /* not coming from an object */
-
- fwrite(&xres, sizeof(long int), 1, f);
- fwrite(&yres, sizeof(long int), 1, f);
-
- yr = 1.;
- xstep = 2. / xres; ystep = 2. / yres;
- for(y = 0; y < yres;y++) {
- xr = -1.;
- for(x = 0; x < xres; x++) {
- /* ray direction calculations */
- ray.dir = vadd( svproduct(xr*fov, hor),
- svproduct(yr*fov, ver) );
- ray.dir = norm( vadd( ray.dir, eye_dir) );
- ray.theta = 0;
- col.r = col.g = col.b = 0;
-
- /* the time blur has to be done in linear time and not randomly */
- /* randomization is used so we won't get the strobo effect */
- for( i = tries; i--; ) {
- Time = (time2+time1)/2 +
- (time2-time1)*(i+rand1())/tries;
- r2 = sample_ray(ray, p_w);
- color = trace_a_ray(r2, 0);
- /* sum all the intensities together */
- col.r += color.r / tries;
- col.g += color.g / tries;
- col.b += color.b / tries;
- }
- /* calc the integer value to be put to the file */
- r = col.r * 255;
- g = col.g * 255;
- b = col.b * 255;
- putc(r,f);
- putc(g,f);
- putc(b,f);
-
- xr += xstep;
- }
- yr -= ystep;
- printf("Finished scanline %d. r:%.2lf/%d sh:%d rl:%d rr:%d int:%d\n",
- y, (double)rayline / yres, rayline, shadowline,
- reflectline, refractline, intersectline);
- /* update statistics */
- raycount += rayline; rayline = 0;
- shadowcount += shadowline; shadowline = 0;
- reflectcount += reflectline; reflectline = 0;
- refractcount += refractline; refractline = 0;
- intersectcount += intersectline; intersectline = 0;
- objtestcount += objtestline; objtestline = 0;
- }
- printf("\nTotal number of rays traced: %d\n", raycount);
- printf("Total number of not shadowed intersections: %d\n", shadowcount);
- printf("Total reflected rays traced: %d\n", reflectcount);
- printf("Total refracted rays traced: %d\n", refractcount);
- printf("Total object intersections: %d\n", intersectcount);
- printf("Total objects tested: %d\n", objtestcount);
- }
-