home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
GRAPHICS
/
rayshade.lzh
/
grid.c
< prev
next >
Wrap
Text File
|
1990-05-08
|
10KB
|
361 lines
/*
* grid.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: grid.c,v 3.0.1.1 90/02/12 13:16:36 craig Exp $
*
* $Log: grid.c,v $
* Revision 3.0.1.1 90/02/12 13:16:36 craig
* patch4: Changed obj->counter to pointer when SHAREDMEM is defined.
*
* Revision 3.0 89/10/27 02:05:50 craig
* Baseline for first official release.
*
*/
#include <stdio.h>
#include "constants.h"
#include "typedefs.h"
#include "funcdefs.h"
extern double CheckVoxel(), intersect();
unsigned long raynumber = 1; /* Current "ray number". */
/* (should be "grid number") */
/*
* Intersect ray with grid, returning distance from "pos" to
* nearest intersection with an object in the grid. Returns 0.
* if no intersection.
*/
double
int_grid(grid, source, ray, hitinfo)
Grid *grid;
Primitive *source;
Ray *ray;
HitInfo *hitinfo;
{
ObjList *list;
Object *tmpobj;
double dist, mindist, offset, tMaxX, tMaxY, tMaxZ;
double tDeltaX, tDeltaY, tDeltaZ, *raybounds[2][3];
int stepX, stepY, stepZ, outX, outY, outZ, x, y, z;
HitInfo infotmp;
Vector curpos, nXp, nYp, nZp, np, pDeltaX, pDeltaY, pDeltaZ;
unsigned long counter;
mindist = FAR_AWAY;
/*
* The "raynumber" scheme prevents us from performing unnecessary
* ray/object intersection tests. Since an object may span more than
* one voxel, it is possible that such an object will be tested more
* than once as we move from voxel-to-voxel. The idea here is to
* increment "raynumber" once when we begin a ray/grid intersection
* test. Whenever we check for intersection with an object in
* the grid, we assign that object's "counter" field the current value
* of "raynumber". On subsequent calls to CheckVoxel, if the object's
* "counter" is greater than or equal to the value "raynumber" had
* when we started tracing the current grid, we know that we've already
* checked that object. This isn't as straight-forward as one
* might think due to instantiation -- one may have several
* instances of the same object in a grid. By incrementing raynumber
* whenever we being a new ray/grid int. test, we guarantee that
* we will check for intersection with the objects in the grid
* at most once.
*/
infotmp.totaltrans = hitinfo->totaltrans;
/*
* Check unbounded objects.
*/
for (list = grid->unbounded ; list; list = list->next) {
tmpobj = list->data;
dist = intersect(tmpobj, source, ray, &infotmp);
if (dist > 0. && dist < mindist) {
*hitinfo = infotmp;
mindist = dist;
}
}
/*
* If outside of the bounding box, check to see if we
* hit it.
*/
if (OutOfBounds(&ray->pos, grid->bounds)) {
offset = IntBounds(ray, grid->bounds);
if (offset <= 0.)
/*
* Ray never hit grid space.
*/
return (mindist == FAR_AWAY ? 0. : mindist);
else if (mindist < offset)
/*
* Hit an unbounded object closer than grid.
*/
return mindist;
/*
* else
* The ray enters voxels space before it hits
* an unbounded object.
*/
addscaledvec(ray->pos, offset, ray->dir, &curpos);
} else {
offset = 0.;
curpos = ray->pos;
}
counter = raynumber++;
/*
* Kludge: Voxel space is mapped as [start, end),
* and we want it to be [start, end].
*/
x = x2voxel(grid, curpos.x);
if (x == grid->xsize)
x = grid->xsize -1;
y = y2voxel(grid, curpos.y);
if (y == grid->ysize)
y = grid->ysize -1;
z = z2voxel(grid, curpos.z);
if (z == grid->zsize)
z = grid->zsize -1;
/*
* tMaxX is the absolute distance from the ray origin we must move
* to get to the next voxel in the X
* direction. It is incrementally updated
* by DDA as we move from voxel-to-voxel.
* tDeltaX is the relative amount along the ray we move to
* get to the next voxel in the X direction. Thus,
* when we decide to move in the X direction,
* we increment tMaxX by tDeltaX.
*/
if (ray->dir.x < 0.) {
stepX = outX = -1;
tMaxX = (voxel2x(grid, x) - curpos.x) / ray->dir.x;
tDeltaX = grid->voxsize[X] / - ray->dir.x;
raybounds[LOW][X] = &np.x;
raybounds[HIGH][X] = &curpos.x;
} else if (ray->dir.x > 0.) {
stepX = 1;
outX = grid->xsize;
tMaxX = (voxel2x(grid, x+1) - curpos.x) / ray->dir.x;
tDeltaX = grid->voxsize[X] / ray->dir.x;
raybounds[LOW][X] = &curpos.x;
raybounds[HIGH][X] = &np.x;
} else {
tMaxX = FAR_AWAY;
raybounds[LOW][X] = &curpos.x;
raybounds[HIGH][X] = &np.x;
tDeltaX = 0.;
}
if (ray->dir.y < 0.) {
stepY = outY = -1;
tMaxY = (voxel2y(grid, y) - curpos.y) / ray->dir.y;
tDeltaY = grid->voxsize[Y] / - ray->dir.y;
raybounds[LOW][Y] = &np.y;
raybounds[HIGH][Y] = &curpos.y;
} else if (ray->dir.y > 0.) {
stepY = 1;
outY = grid->ysize;
tMaxY = (voxel2y(grid, y+1) - curpos.y) / ray->dir.y;
tDeltaY = grid->voxsize[Y] / ray->dir.y;
raybounds[LOW][Y] = &curpos.y;
raybounds[HIGH][Y] = &np.y;
} else {
tMaxY = FAR_AWAY;
raybounds[LOW][Y] = &curpos.y;
raybounds[HIGH][Y] = &np.y;
tDeltaY = 0.;
}
if (ray->dir.z < 0.) {
stepZ = outZ = -1;
tMaxZ = (voxel2z(grid, z) - curpos.z) / ray->dir.z;
tDeltaZ = grid->voxsize[Z] / - ray->dir.z;
raybounds[LOW][Z] = &np.z;
raybounds[HIGH][Z] = &curpos.z;
} else if (ray->dir.z > 0.) {
stepZ = 1;
outZ = grid->zsize;
tMaxZ = (voxel2z(grid, z+1) - curpos.z) / ray->dir.z;
tDeltaZ = grid->voxsize[Z] / ray->dir.z;
raybounds[LOW][Z] = &curpos.z;
raybounds[HIGH][Z] = &np.z;
} else {
tMaxZ = FAR_AWAY;
raybounds[LOW][Z] = &curpos.z;
raybounds[HIGH][Z] = &np.z;
tDeltaZ = 0.;
}
/*
* We've already moved from the ray origin along the ray to "hitpoint"
* by "offset" units in order to reach the grid.
*/
tMaxX += offset;
tMaxY += offset;
tMaxZ += offset;
pDeltaX.x = tDeltaX * ray->dir.x;
pDeltaX.y = tDeltaX * ray->dir.y;
pDeltaX.z = tDeltaX * ray->dir.z;
pDeltaY.x = tDeltaY * ray->dir.x;
pDeltaY.y = tDeltaY * ray->dir.y;
pDeltaY.z = tDeltaY * ray->dir.z;
pDeltaZ.x = tDeltaZ * ray->dir.x;
pDeltaZ.y = tDeltaZ * ray->dir.y;
pDeltaZ.z = tDeltaZ * ray->dir.z;
nXp.x = ray->pos.x + tMaxX * ray->dir.x;
nXp.y = ray->pos.y + tMaxX * ray->dir.y;
nXp.z = ray->pos.z + tMaxX * ray->dir.z;
nYp.x = ray->pos.x + tMaxY * ray->dir.x;
nYp.y = ray->pos.y + tMaxY * ray->dir.y;
nYp.z = ray->pos.z + tMaxY * ray->dir.z;
nZp.x = ray->pos.x + tMaxZ * ray->dir.x;
nZp.y = ray->pos.y + tMaxZ * ray->dir.y;
nZp.z = ray->pos.z + tMaxZ * ray->dir.z;
while (1) {
if (tMaxX < tMaxY) {
if (tMaxX < tMaxZ) {
np = nXp;
if ((list = grid->cells[x][y][z]))
mindist = CheckVoxel(list,source,ray,
raybounds,hitinfo,counter,mindist);
x += stepX;
if (mindist < tMaxX || x == outX)
break;
tMaxX += tDeltaX;
curpos = nXp;
nXp.x += pDeltaX.x;
nXp.y += pDeltaX.y;
nXp.z += pDeltaX.z;
} else {
np = nZp;
if ((list = grid->cells[x][y][z]))
mindist = CheckVoxel(list,source,ray,
raybounds, hitinfo,counter,mindist);
z += stepZ;
if (mindist < tMaxZ || z == outZ)
break;
tMaxZ += tDeltaZ;
curpos = nZp;
nZp.x += pDeltaZ.x;
nZp.y += pDeltaZ.y;
nZp.z += pDeltaZ.z;
}
} else {
if (tMaxY < tMaxZ) {
np = nYp;
if ((list = grid->cells[x][y][z]))
mindist = CheckVoxel(list,source,ray,
raybounds,hitinfo,counter,mindist);
y += stepY;
if (mindist < tMaxY || y == outY)
break;
tMaxY += tDeltaY;
curpos = nYp;
nYp.x += pDeltaY.x;
nYp.y += pDeltaY.y;
nYp.z += pDeltaY.z;
} else {
np = nZp;
if ((list = grid->cells[x][y][z]))
mindist = CheckVoxel(list,source,ray,
raybounds, hitinfo,counter,mindist);
z += stepZ;
if (mindist < tMaxZ || z == outZ)
break;
tMaxZ += tDeltaZ;
curpos = nZp;
nZp.x += pDeltaZ.x;
nZp.y += pDeltaZ.y;
nZp.z += pDeltaZ.z;
}
}
}
if (mindist == FAR_AWAY)
return 0.;
return mindist;
}
/*
* Intersect ray with objects in grid cell. Note that there are a many ways
* to speed up this routine, all of which uglify the code to a large extent.
*/
double
CheckVoxel(list,source,ray,raybounds,hitinfo,counter,mindist)
ObjList *list;
Primitive *source;
Ray *ray;
double *raybounds[2][3];
HitInfo *hitinfo;
unsigned long counter;
double mindist;
{
Object *obj;
HitInfo tmpinfo;
double dist, lx, hx, ly, hy, lz, hz;
tmpinfo.totaltrans = hitinfo->totaltrans;
lx = *raybounds[LOW][X];
hx = *raybounds[HIGH][X];
ly = *raybounds[LOW][Y];
hy = *raybounds[HIGH][Y];
lz = *raybounds[LOW][Z];
hz = *raybounds[HIGH][Z];
for (; list; list = list->next) {
obj = list->data;
/*
* If object's counter is greater than or equal to the
* number associated with the current grid,
* don't bother checking again. In addition, if the
* bounding box of the ray's extent in the voxel does
* not intersect the bounding box of the object, don't bother.
*/
#ifdef SHAREDMEM
if (*obj->counter >= counter ||
#else
if (obj->counter >= counter ||
#endif
obj->bounds[LOW][X] > hx ||
obj->bounds[HIGH][X] < lx ||
obj->bounds[LOW][Y] > hy ||
obj->bounds[HIGH][Y] < ly ||
obj->bounds[LOW][Z] > hz ||
obj->bounds[HIGH][Z] < lz)
continue;
#ifdef SHAREDMEM
*obj->counter = counter;
#else
obj->counter = counter;
#endif
dist = intersect(obj, source, ray, &tmpinfo);
if (dist > 0. && dist < mindist) {
*hitinfo = tmpinfo;
mindist = dist;
}
}
return mindist;
}