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.