| /*************************************************************************/ |
| /* */ |
| /* Copyright (c) 1994 Stanford University */ |
| /* */ |
| /* All rights reserved. */ |
| /* */ |
| /* Permission is given to use, copy, and modify this software for any */ |
| /* non-commercial purpose as long as this copyright notice is not */ |
| /* removed. All other uses, including redistribution in whole or in */ |
| /* part, are forbidden without prior written permission. */ |
| /* */ |
| /* This software is provided with absolutely no warranty and no */ |
| /* support. */ |
| /* */ |
| /*************************************************************************/ |
| |
| |
| /* |
| * NAME |
| * trace.c |
| * |
| * DESCRIPTION |
| * This file contains the routines to process ray jobs from the work pool |
| * containing primary ray jobs. |
| */ |
| |
| |
| #include <stdio.h> |
| #include <math.h> |
| #include "rt.h" |
| |
| /* |
| * NAME |
| * frand - generate random floating point number |
| * |
| * SYNOPSIS |
| * REAL frand() |
| * Used instead of standard srand for portability to other systems than Unix. |
| * |
| * RETURNS |
| * A random floating point number in the range 0 <= x < 1. |
| */ |
| |
| REAL frand() |
| { |
| REAL r; |
| static LONG lLastRand = 0; |
| |
| lLastRand = lLastRand*214013L + 2531011L; |
| r = (REAL)((lLastRand >> 16) & 0x7FFF)/32768.0; |
| return (r); |
| } |
| |
| |
| |
| /* |
| * NAME |
| * GetRayJobFromBundle - |
| * |
| * SYNOPSIS |
| * BOOL GetRayJobFromBundle(job, x, y) |
| * RAYJOB *job; // Ray job from work pool. |
| * INT *x, *y; // Pixel address. |
| * |
| * DESCRIPTION |
| * This routine determines if there are any more primary rays left to |
| * process in the ray bundle job. |
| * |
| * The routine returns FALSE if the bundle processing is complete. If |
| * there are more jobs, the current x and y pixel position are returned |
| * through procedure parameters. Then, x and y are bundle is updated for |
| * the next inquiry and TRUE is returned. |
| * |
| * RETURNS |
| * See above. |
| */ |
| |
| BOOL GetRayJobFromBundle(job, x, y) |
| RAYJOB *job; |
| INT *x, *y; |
| { |
| *x = job->xcurr; /* Set pixel address first. */ |
| *y = job->ycurr; |
| |
| if ((job->y + job->ylen) == job->ycurr) /* All done? */ |
| return (FALSE); |
| |
| job->xcurr++; /* Update to next pixel. */ |
| if ((job->x +job->xlen) == job->xcurr ) |
| { |
| job->xcurr = job->x; /* Go to new scanline. */ |
| job->ycurr++; |
| } |
| |
| return (TRUE); |
| } |
| |
| |
| |
| /* |
| * NAME |
| * ConvertPrimRayJobToRayMsg - convert primary ray job to the ray message format |
| * |
| * SYNOPSIS |
| * VOID ConvertPrimRayJobToRayMsg(ray, x, y) |
| * RAY *ray; // Ray message. |
| * REAL x, y; // Pixel. |
| * |
| * DESCRIPTION |
| * This routine converts the primary ray job to the ray message format. |
| * The ray origin and direction are computed and the other ray message |
| * variables are initialized. |
| * |
| * Perspective Projection: |
| * |
| * Calculate ray direction thru pixel and transform it back to |
| * the world coordinate system. Origin of ray is eye position. |
| * |
| * Orthographic Projection: |
| * |
| * Calculate ray direction thru pixel and transform it back to |
| * the world coordinate system. Origin of ray must also be |
| * calculated. |
| * RETURNS |
| * Nothing. |
| */ |
| |
| VOID ConvertPrimRayJobToRayMsg(ray, x, y) |
| RAY *ray; |
| REAL x, y; |
| { |
| VEC4 dir; |
| VEC4 origin; |
| |
| if (View.projection == PT_PERSP) |
| { |
| dir[0] = -Display.scrHalfWidth + (x*Display.vWscale); |
| dir[1] = Display.scrHalfHeight - (y*Display.vHscale); |
| dir[2] = Display.scrDist; |
| dir[3] = 0.0; |
| |
| /* Transform ray back to world. */ |
| TransformViewRay(dir); |
| |
| VecNorm(dir); |
| VecCopy(ray->D, dir); |
| VecCopy(ray->P, View.eye); |
| } |
| else |
| { |
| /* Orthographic projection. */ |
| |
| dir[0] = 0.0; |
| dir[1] = 0.0; |
| dir[2] = 1.0; |
| dir[3] = 0.0; |
| |
| /* Transform ray back to world. */ |
| TransformViewRay(dir); |
| VecNorm(dir); |
| |
| VecCopy(ray->D, dir); |
| |
| /* Calculate origin. */ |
| |
| origin[0] = -Display.scrHalfWidth + (x*Display.vWscale); |
| origin[1] = Display.scrHalfHeight - (y*Display.vHscale); |
| origin[2] = 0.0; |
| origin[3] = 1.0; |
| |
| /* Transform origin back to world. */ |
| |
| TransformViewRay(origin); |
| VecCopy(ray->P, origin); |
| } |
| |
| |
| /* Initialize other fields of ray message. */ |
| |
| ray->level = 0; |
| ray->weight = 1.0/(REAL)NumSubRays; |
| |
| LOCK(gm->ridlock); |
| ray->id = gm->rid++; |
| UNLOCK(gm->ridlock); |
| |
| ray->x = (INT)x; |
| ray->y = (INT)y; |
| |
| } |
| |
| |
| |
| /* |
| * NAME |
| * RayTrace - process primary ray bundle jobs from the workpool |
| * |
| * SYNOPSIS |
| * VOID RayTrace(pid) |
| * INT pid; // Process id. |
| * |
| * DESCRIPTION |
| * Process primary ray bundle jobs from the workpool. Each ray job from |
| * the ray bundle list performs the following tasks. |
| * |
| * A ray bundle job is converted to a ray message and pushed |
| * on the raytree stack. A ray job consists of a pixel address |
| * while the ray message also contains the ray origin, direction, |
| * level in tree, ray weight, ray id, and grid parameters. |
| * Processing begins with the primary ray and secondary rays being |
| * pushed onto the stack as the raytree is built and processed. |
| * The raytree stack is used to avoid recursion. |
| * |
| * Processes all jobs on raytree stack. |
| * |
| * Calls routines for intersecting a ray with the environment and |
| * for shading the ray. |
| * |
| * RETURNS |
| * Nothing. |
| */ |
| |
| VOID RayTrace(pid) |
| INT pid; |
| { |
| INT i, j; |
| INT x, y; /* Pixel address. */ |
| REAL xx, yy; |
| VEC3 N; /* Normal at intersection. */ |
| VEC3 Ipoint; /* Intersection point. */ |
| COLOR c; /* Color for storing background. */ |
| RAY *ray; /* Ray pointer. */ |
| RAY rmsg; /* Ray message. */ |
| RAYJOB job; /* Ray job from work pool. */ |
| OBJECT *po; /* Ptr to object. */ |
| BOOL hit; /* An object hit? */ |
| IRECORD hitrecord; /* Intersection record. */ |
| |
| ray = &rmsg; |
| |
| while (GetJobs(&job, pid) != WPS_EMPTY) |
| { |
| while (GetRayJobFromBundle(&job, &x, &y)) |
| { |
| /* Convert the ray job to the ray message format. */ |
| |
| xx = (REAL)x; |
| yy = (REAL)y; |
| |
| if (AntiAlias) |
| for (j = 0; j < NumSubRays; j++) |
| { |
| ConvertPrimRayJobToRayMsg(ray, xx + frand(), yy + frand()); |
| PushRayTreeStack(ray, pid); |
| } |
| else |
| { |
| ConvertPrimRayJobToRayMsg(ray, xx, yy); |
| PushRayTreeStack(ray, pid); |
| } |
| |
| while (PopRayTreeStack(ray, pid) != RTS_EMPTY) |
| { |
| /* Find which object is closest along the ray. */ |
| |
| switch (TraversalType) |
| { |
| case TT_LIST: |
| hit = Intersect(ray, &hitrecord); |
| break; |
| |
| case TT_HUG: |
| hit = TraverseHierarchyUniform(ray, &hitrecord, pid); |
| break; |
| } |
| |
| /* Process the object ray hit. */ |
| |
| if (hit) |
| { |
| /* |
| * Get parent object to be able to access |
| * object operations. |
| */ |
| |
| po = hitrecord.pelem->parent; |
| |
| /* Calculate intersection point. */ |
| RayPoint(Ipoint, ray, hitrecord.t); |
| |
| /* Calculate normal at this point. */ |
| (*po->procs->normal)(&hitrecord, Ipoint, N); |
| |
| /* Make sure normal is pointing toward ray origin. */ |
| if ((VecDot(ray->D, N)) > 0.0) |
| VecNegate(N, N); |
| |
| /* |
| * Compute shade at this point - will process |
| * shadow rays and add secondary reflection |
| * and refraction rays to ray tree stack |
| */ |
| |
| Shade(Ipoint, N, ray, &hitrecord, pid); |
| } |
| else |
| { |
| /* Add background as pixel contribution. */ |
| |
| VecCopy(c, View.bkg); |
| VecScale(c, ray->weight, c); |
| AddPixelColor(c, ray->x, ray->y); |
| } |
| } |
| } |
| } |
| } |
| |