This is trace.c in view mode; [Download] [Up]
/*
* (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);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.