home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
GRAPHICS
/
rayshade.lzh
/
intersect.c
< prev
next >
Wrap
Text File
|
1990-05-08
|
7KB
|
249 lines
/*
* intersect.c
*
* Copyright (C) 1989, Craig E. Kolb
*
* This software may be freely copied, modified, and redistributed,
* provided that this copyright notice is preserved on all copies.
*
* There is no warranty or other guarantee of fitness for this software,
* it is provided solely . Bug reports or fixes may be sent
* to the author, who may or may not act on them as he desires.
*
* You may not include this software in a program or other software product
* without supplying the source, or without informing the end-user that the
* source is available for no extra charge.
*
* If you modify this software, you should include a notice giving the
* name of the person performing the modification, the date of modification,
* and the reason for such modification.
*
* $Id: intersect.c,v 3.0 89/10/27 02:05:53 craig Exp $
*
* $Log: intersect.c,v $
* Revision 3.0 89/10/27 02:05:53 craig
* Baseline for first official release.
*
*/
#include <math.h>
#include <stdio.h>
#include "typedefs.h"
#include "funcdefs.h"
#include "constants.h"
/*
* Primitive intersection routines
*/
double (*objint[])() = {intsph, intbox, inttri, intsup, intplane, intcyl,
intpoly, inttri, intcone, inthf};
/*
* Primitive normal routines
*/
int (*objnrm[])() = {nrmsph, nrmbox, nrmtri, nrmsup, nrmplane, nrmcyl,
nrmpoly, nrmtri, nrmcone, nrmhf};
/*
* object extent box routines
*/
int (*objextent[])() = {sphextent, boxextent, triextent, supextent,
planeextent, cylextent, polyextent, triextent,
coneextent, hfextent};
unsigned long int primtests[PRIMTYPES], primhits[PRIMTYPES];
char *primnames[PRIMTYPES] = { "Sphere", "Box", "Triangle", "Superq", "Plane",
"Cylinder", "Polygon", "Phongtri", "Cone",
"Heightfield"};
/*
* Flags indicating whether or not we should check for intersection
* with an object's bounding box before we check for intersection
* with the object.
*/
char CheckBounds[] = {TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE,
TRUE, FALSE, FALSE, FALSE};
/*
* Top-level raytracing routine. Increment ray number, initialize
* intersection information and trace ray through "World" object.
*/
double
TraceRay(source, ray, hitinfo)
Primitive *source;
Ray *ray;
HitInfo *hitinfo;
{
extern Object *World;
extern double intersect();
return intersect(World, source, ray, hitinfo);
}
/*
* Intersect object & ray. Return distance from "pos" along "ray" to
* intersection point. Return value <= 0 indicates no intersection.
*/
double
intersect(obj, source, ray, hitinfo)
Object *obj; /* Object to be tested. */
Primitive *source; /* Prim, if any, that pos is on. */
Ray *ray; /* Ray origin, direction. */
HitInfo *hitinfo; /* Data on intersection (pos, norm) */
{
Ray newray;
double dist, distfact, TransformRay();
extern int Cache;
/*
* Check ray/bounding volume intersection, if required.
*/
if (CheckBounds[obj->type] &&
OutOfBounds(&ray->pos, obj->bounds) &&
IntBounds(ray, obj->bounds) < EPSILON)
return 0.;
newray = *ray;
/*
* Transform the ray if necessary.
*/
if (obj->trans != (Trans *)0) {
/*
* Transforming the ray can change the distance between
* the ray origin and the point of intersection.
* We save the amount the ray is "stretched" and later
* divide the computed distance by this amount.
*/
distfact = TransformRay(&newray, &obj->trans->world2obj);
}
/*
* Call correct intersection routine.
*/
if (obj->type == GRID)
dist = int_grid((Grid *)obj->data, source, &newray, hitinfo);
else if (obj->type == LIST)
dist = int_list((List *)obj->data, source, &newray, hitinfo);
else
dist = int_primitive((Primitive *)obj->data, source, &newray,
hitinfo);
if (dist < EPSILON)
return 0.;
/*
* If this is a shadow ray, don't bother with texture mapping
* or transformation of normal.
*/
if (ray->shadow) {
if (obj->trans == (Trans *)0)
return dist;
else if (Cache)
/*
* Keep track of total transformation applied to ray
* if necessary.
*/
mmult(hitinfo->totaltrans, &obj->trans->world2obj,
hitinfo->totaltrans);
return dist / distfact;
}
/*
* Perform texture mapping.
*/
if (obj->texture)
apply_textures(hitinfo, obj->texture);
if (obj->trans) {
/*
* Transform hitinfo structure. As things stand,
* this just means transforming the normal and
* dividing "dist" by the amount the ray was
* stretched.
*/
dist /= distfact;
TransformNormal(&hitinfo->norm, &obj->trans->world2obj);
}
return dist;
}
/*
* Intersect ray & primitive object.
*/
double
int_primitive(prim, source, ray, hitinfo)
Primitive *prim, *source;
Ray *ray;
HitInfo *hitinfo;
{
double dist;
if (prim == source && prim->type != HF)
/*
* Don't check for intersection with "source", unless
* source is a height field. (Height fields may shadow
* themselves.)
*/
return 0.;
dist = (*objint[prim->type]) (&ray->pos, &ray->dir, prim);
if (dist < EPSILON)
return 0.;
primhits[prim->type]++;
hitinfo->prim = prim;
hitinfo->surf = *prim->surf;
if (ray->shadow)
return dist; /* If a shadow ray, don't bother with normal */
/*
* Calculate point of intersection in object space.
* (The point of intersection in world space is
* calculated in ShadeRay().)
*/
addscaledvec(ray->pos, dist, ray->dir, &hitinfo->pos);
/*
* Find normal to primitive.
*/
(*objnrm[prim->type]) (&hitinfo->pos, prim, &hitinfo->norm);
/*
* Make sure normal points towards ray origin. If surface is
* transparent, keep as-is, as the normal indicates whether we're
* entering or exiting. If the prim is a superquadric, don't flip,
* as this leads to strange edge effects.
*/
if (dotp(&ray->dir, &hitinfo->norm) > 0 && hitinfo->surf.transp == 0. &&
prim->type != SUPERQ) {
scalar_prod(-1., hitinfo->norm, &hitinfo->norm);
}
return dist;
}
print_prim_stats()
{
long int totaltests, totalhits;
extern FILE *fstats;
int i;
totaltests = totalhits = 0;
for (i = 0; i < PRIMTYPES; i++) {
if (primtests[i] == 0)
continue;
fprintf(fstats,"%s intersection tests:\t%ld (%ld hit, %f%%)\n",
primnames[i], primtests[i],
primhits[i],
100.*(float)primhits[i]/(float)primtests[i]);
totaltests += primtests[i];
totalhits += primhits[i];
}
fprintf(fstats,"Total intersection tests:\t%ld", totaltests);
if (totaltests == 0)
fprintf(fstats,"\n");
else
fprintf(fstats," (%ld hit, %f%%)\n", totalhits,
100.*(float)totalhits/(float)totaltests);
}