blob: 70c46dcf5ff9d7c3b35aa24d59f7e9c4fe4ecd38 [file] [log] [blame]
/*************************************************************************/
/* */
/* 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. */
/* */
/*************************************************************************/
/*************************************************************************
* *
* adaptive.c: Render dataset via raytracing. *
* *
*************************************************************************/
#include "incl.h"
float invjacobian[NM][NM]; /* Jacobian matrix showing object space */
/* d{x,y,z} per image space d{x,y,z} */
/* [0][0] is dx(object)/dx(image) */
/* [0][2] is dz(object)/dx(image) */
/* [2][0] is dx(object)/dz(image) */
float invinvjacobian[NM][NM]; /* [i][j] = 1.0 / invjacobian[i][j] */
/* For gathering statistics: */
int num_rays_traced; /* number of calls to Trace_Ray */
int num_traced_rays_hit_volume; /* number of traced rays that hit volume */
int num_samples_trilirped; /* number of samples trilirped */
int itest;
#define RAY_TRACED ((MAX_PIXEL+1)/2) /* Ray traced at this pixel */
#define START_RAY 1
#define INTERPOLATED ((MAX_PIXEL+1)/32) /* This pixel interpolated */
EXTERN_ENV
#include "anl.h"
Ray_Trace(int my_node)
{
int outx,outy,outz;
int i,j;
unsigned long starttime,stoptime,exectime,exectime1;
int pid;
char cmd[FILENAME_STRING_SIZE];
/* Assumptions made by ray tracer: */
/* o Frustrum clipping is performed. */
/* All viewing frustums will be handled correctly. */
/* o Contributions are obtained only from nearest 8 neighbors. */
/* If downsizing was specified, some input voxels will be */
/* unsampled, but upsizing may be specified and will be */
/* handled correctly. */
/* Compute inverse Jacobian matrix from */
/* coordinates of output map unit voxel in object space, */
/* then make a copy of object space d{x,y,z} per image space dz, */
/* which controls number of ray samples per object space voxel */
/* (i.e. Z-sampling rate), to allow recomputation per region. */
for (i=0; i<NM; i++) {
invjacobian[X][i] = uout_invvertex[0][0][1][i] -
uout_invvertex[0][0][0][i];
invjacobian[Y][i] = uout_invvertex[0][1][0][i] -
uout_invvertex[0][0][0][i];
invjacobian[Z][i] = uout_invvertex[1][0][0][i] -
uout_invvertex[0][0][0][i];
}
/* Compute multiplicative inverse of inverse Jacobian matrix. */
/* If any Jacobian is zero, compute no inverse for that element. */
/* This test must be repeated before access to any inverse element. */
for (i=0; i<NM; i++) {
for (j=0; j<NM; j++) {
if (ABS(invjacobian[i][j]) > SMALL)
invinvjacobian[i][j] = 1.0 / invjacobian[i][j];
}
}
num_rays_traced = 0;
num_traced_rays_hit_volume = 0;
num_samples_trilirped = 0;
/* Invoke adaptive or non-adaptive ray tracer */
if (adaptive) {
BARRIER(Global->TimeBarrier,num_nodes);
CLOCK(starttime);
Pre_Shade(my_node);
LOCK(Global->CountLock);
Global->Counter--;
UNLOCK(Global->CountLock);
while (Global->Counter);
Ray_Trace_Adaptively(my_node);
CLOCK(stoptime);
BARRIER(Global->TimeBarrier,num_nodes);
mclock(stoptime,starttime,&exectime);
/* If adaptively ray tracing and highest sampling size is greater */
/* than lowest size for volume data if polygon list exists or */
/* display pixel size if it does not, recursively interpolate to */
/* fill in any missing samples down to lowest size for volume data. */
if (highest_sampling_boxlen > 1) {
BARRIER(Global->TimeBarrier,num_nodes);
CLOCK(starttime);
Interpolate_Recursively(my_node);
CLOCK(stoptime);
BARRIER(Global->TimeBarrier,num_nodes);
mclock(stoptime,starttime,&exectime1);
}
}
else {
BARRIER(Global->TimeBarrier,num_nodes);
CLOCK(starttime);
Pre_Shade(my_node);
LOCK(Global->CountLock);
Global->Counter--;
UNLOCK(Global->CountLock);
while (Global->Counter);
Ray_Trace_Non_Adaptively(my_node);
CLOCK(stoptime);
BARRIER(Global->TimeBarrier,num_nodes);
mclock(stoptime,starttime,&exectime);
exectime1 = 0;
}
LOCK(Global->CountLock);
printf("%3d\t%3d\t%6u\t%6u\t%6d\t%6d\t%8d\n",my_node,frame,exectime,
exectime1,num_rays_traced,num_traced_rays_hit_volume,
num_samples_trilirped);
UNLOCK(Global->CountLock);
BARRIER(Global->TimeBarrier,num_nodes);
}
Ray_Trace_Adaptively(int my_node)
{
int i,outx,outy,yindex,xindex;
int num_xqueue,num_yqueue,num_queue,lnum_xblocks,lnum_yblocks,lnum_blocks;
int xstart,xstop,ystart,ystop,local_node,work;
itest = 0;
num_xqueue = ROUNDUP((float)image_len[X]/(float)image_section[X]);
num_yqueue = ROUNDUP((float)image_len[Y]/(float)image_section[Y]);
num_queue = num_xqueue * num_yqueue;
lnum_xblocks = ROUNDUP((float)num_xqueue/(float)block_xlen);
lnum_yblocks = ROUNDUP((float)num_yqueue/(float)block_ylen);
lnum_blocks = lnum_xblocks * lnum_yblocks;
local_node = my_node;
Global->Queue[local_node][0] = 0;
while (Global->Queue[num_nodes][0] > 0) {
xstart = (local_node % image_section[X]) * num_xqueue;
xstart = ROUNDUP((float)xstart/(float)highest_sampling_boxlen);
xstart = xstart * highest_sampling_boxlen;
xstop = MIN(xstart+num_xqueue,image_len[X]);
ystart = (local_node / image_section[X]) * num_yqueue;
ystart = ROUNDUP((float)ystart/(float)highest_sampling_boxlen);
ystart = ystart * highest_sampling_boxlen;
ystop = MIN(ystart+num_yqueue,image_len[Y]);
ALOCK(Global->QLock,local_node);
work = Global->Queue[local_node][0];
Global->Queue[local_node][0] += 1;
AULOCK(Global->QLock,local_node);
while (work < lnum_blocks) {
xindex = xstart + (work%lnum_xblocks)*block_xlen;
yindex = ystart + (work/lnum_xblocks)*block_ylen;
for (outy=yindex; outy<yindex+block_ylen && outy<ystop;
outy+=highest_sampling_boxlen) {
for (outx=xindex; outx<xindex+block_xlen && outx<xstop;
outx+=highest_sampling_boxlen) {
/* Trace rays within square box of highest sampling size */
/* whose lower-left corner is current image space location. */
Ray_Trace_Adaptive_Box(outx,outy,highest_sampling_boxlen);
}
}
ALOCK(Global->QLock,local_node);
work = Global->Queue[local_node][0];
Global->Queue[local_node][0] += 1;
AULOCK(Global->QLock,local_node);
}
if (my_node == local_node) {
ALOCK(Global->QLock,num_nodes);
Global->Queue[num_nodes][0]--;
AULOCK(Global->QLock,num_nodes);
}
local_node = (local_node+1)%num_nodes;
while (Global->Queue[local_node][0] >= lnum_blocks &&
Global->Queue[num_nodes][0] > 0)
local_node = (local_node+1)%num_nodes;
}
}
Ray_Trace_Adaptive_Box(outx, outy, boxlen)
int outx, outy, boxlen;
{
int i,j;
int half_boxlen;
int min_volume_color,max_volume_color;
float foutx,fouty;
volatile int imask;
PIXEL *pixel_address;
/* Trace rays from all four corners of the box into the map, */
/* being careful not to exceed the boundaries of the output image, */
/* and using a flag array to avoid retracing any rays. */
/* For diagnostic display, flag is set to a light gray. */
/* If mipmapping, flag is light gray minus current mipmap level. */
/* If mipmapping and ray has already been traced, */
/* retrace it if current mipmap level is lower than */
/* mipmap level in effect when ray was last traced, */
/* thus replacing crude approximation with better one. */
/* Meanwhile, compute minimum and maximum geometry/volume colors. */
/* If polygon list exists, compute geometry-only colors */
/* and volume-attenuated geometry-only colors as well. */
/* If stochastic sampling and box is smaller than a display pixel, */
/* distribute the rays uniformly across a square centered on the */
/* nominal ray location and of size equal to the image array spacing.*/
/* This scheme interpolates the jitter size / sample spacing ratio */
/* from zero at one sample per display pixel, avoiding jitter noise, */
/* to one at the maximum sampling rate, insuring complete coverage, */
/* all the while building on previously traced rays where possible. */
/* The constant radius also prevents overlap of jitter squares from */
/* successive subdivision levels, preventing sample clumping noise. */
min_volume_color = MAX_PIXEL;
max_volume_color = MIN_PIXEL;
for (i=0; i<=boxlen && outy+i<image_len[Y]; i+=boxlen) {
for (j=0; j<=boxlen && outx+j<image_len[X]; j+=boxlen) {
/*reschedule processes here if rescheduling only at synch points on simulator*/
if (MASK_IMAGE(outy+i,outx+j) == 0) {
/*reschedule processes here if rescheduling only at synch points on simulator*/
MASK_IMAGE(outy+i,outx+j) = START_RAY;
/*reschedule processes here if rescheduling only at synch points on simulator*/
foutx = (float)(outx+j);
fouty = (float)(outy+i);
pixel_address = IMAGE_ADDRESS(outy+i,outx+j);
/*reschedule processes here if rescheduling only at synch points on simulator*/
Trace_Ray(outx+j,outy+i,foutx,fouty,pixel_address);
/*reschedule processes here if rescheduling only at synch points on simulator*/
MASK_IMAGE(outy+i,outx+j) = RAY_TRACED;
}
}
}
for (i=0; i<=boxlen && outy+i<image_len[Y]; i+=boxlen) {
for (j=0; j<=boxlen && outx+j<image_len[X]; j+=boxlen) {
imask = MASK_IMAGE(outy+i,outx+j);
/*reschedule processes here if rescheduling only at synch points on simulator*/
while (imask == START_RAY) {
/*reschedule processes here if rescheduling only at synch points on simulator*/
imask = MASK_IMAGE(outy+i,outx+j);
/*reschedule processes here if rescheduling only at synch points on simulator*/
}
min_volume_color = MIN(IMAGE(outy+i,outx+j),min_volume_color);
max_volume_color = MAX(IMAGE(outy+i,outx+j),max_volume_color);
}
}
/* If size of current box is above lowest size for volume data and */
/* magnitude of geometry/volume color difference is significant, or */
/* size of current box is above lowest size for geometric data and */
/* magnitudes of geometry-only and volume-attenuated geometry-only */
/* are both significant, thus detecting only visible geometry events,*/
/* invoke this function recursively to trace rays within the */
/* four equal-sized square sub-boxes enclosed by the current box, */
/* being careful not to exceed the boundaries of the output image. */
/* Use of geometry-only color difference suppressed in accordance */
/* with hybrid.trf as published in IEEE CG&A, March, 1990. */
if (boxlen > lowest_volume_boxlen &&
max_volume_color - min_volume_color >=
volume_color_difference) {
half_boxlen = boxlen >> 1;
for (i=0; i<boxlen && outy+i<image_len[Y]; i+=half_boxlen) {
for (j=0; j<boxlen && outx+j<image_len[X]; j+=half_boxlen) {
Ray_Trace_Adaptive_Box(outx+j,outy+i,half_boxlen);
}
}
}
}
Ray_Trace_Non_Adaptively(int my_node)
{
int i,outx,outy,xindex,yindex;
float foutx,fouty;
PIXEL *pixel_address;
int num_xqueue,num_yqueue,num_queue,lnum_xblocks,lnum_yblocks,lnum_blocks;
int xstart,xstop,ystart,ystop,local_node,work;
num_xqueue = ROUNDUP((float)image_len[X]/(float)image_section[X]);
num_yqueue = ROUNDUP((float)image_len[Y]/(float)image_section[Y]);
num_queue = num_xqueue * num_yqueue;
lnum_xblocks = ROUNDUP((float)num_xqueue/(float)block_xlen);
lnum_yblocks = ROUNDUP((float)num_yqueue/(float)block_ylen);
lnum_blocks = lnum_xblocks * lnum_yblocks;
local_node = my_node;
Global->Queue[local_node][0] = 0;
while (Global->Queue[num_nodes][0] > 0) {
xstart = (local_node % image_section[X]) * num_xqueue;
xstop = MIN(xstart+num_xqueue,image_len[X]);
ystart = (local_node / image_section[X]) * num_yqueue;
ystop = MIN(ystart+num_yqueue,image_len[Y]);
ALOCK(Global->QLock,local_node);
work = Global->Queue[local_node][0]++;
AULOCK(Global->QLock,local_node);
while (work < lnum_blocks) {
xindex = xstart + (work%lnum_xblocks)*block_xlen;
yindex = ystart + (work/lnum_xblocks)*block_ylen;
for (outy=yindex; outy<yindex+block_ylen && outy<ystop; outy++) {
for (outx=xindex; outx<xindex+block_xlen && outx<xstop; outx++) {
/* Trace ray from specified image space location into map. */
/* Stochastic sampling is as described in adaptive code. */
foutx = (float)(outx);
fouty = (float)(outy);
pixel_address = IMAGE_ADDRESS(outy,outx);
Trace_Ray(outx,outy,foutx,fouty,pixel_address);
}
}
ALOCK(Global->QLock,local_node);
work = Global->Queue[local_node][0]++;
AULOCK(Global->QLock,local_node);
}
if (my_node == local_node) {
ALOCK(Global->QLock,num_nodes);
Global->Queue[num_nodes][0]--;
AULOCK(Global->QLock,num_nodes);
}
local_node = (local_node+1)%num_nodes;
while (Global->Queue[local_node][0] >= lnum_blocks &&
Global->Queue[num_nodes][0] > 0)
local_node = (local_node+1)%num_nodes;
}
}
Ray_Trace_Fast_Non_Adaptively(int my_node)
{
int i,outx,outy,xindex,yindex;
float foutx,fouty;
PIXEL *pixel_address;
for (i=0; i<num_blocks; i+=num_nodes) {
yindex = ((my_node+i)/num_xblocks)*block_ylen;
xindex = ((my_node+i)%num_xblocks)*block_xlen;
for (outy=yindex; outy<yindex+block_ylen &&
outy<image_len[Y]; outy+=lowest_volume_boxlen) {
for (outx=xindex; outx<xindex+block_xlen &&
outx<image_len[X]; outx+=lowest_volume_boxlen) {
/* Trace ray from specified image space location into map. */
/* Stochastic sampling is as described in adaptive code. */
MASK_IMAGE(outy,outx) += RAY_TRACED;
foutx = (float)(outx);
fouty = (float)(outy);
pixel_address = IMAGE_ADDRESS(outy,outx);
Trace_Ray(outx,outy,foutx,fouty,pixel_address);
num_rays_traced++;
}
}
}
}
Interpolate_Recursively(int my_node)
{
int i,outx,outy,xindex,yindex;
for (i=0; i<num_blocks; i+=num_nodes) {
yindex = ((my_node+i)/num_xblocks)*block_ylen;
xindex = ((my_node+i)%num_xblocks)*block_xlen;
for (outy=yindex; outy<yindex+block_ylen &&
outy<image_len[Y]; outy+=highest_sampling_boxlen) {
for (outx=xindex; outx<xindex+block_xlen &&
outx<image_len[X]; outx+=highest_sampling_boxlen) {
/* Fill in image within square box of highest sampling size */
/* whose lower-left corner is current image space location. */
Interpolate_Recursive_Box(outx,outy,highest_sampling_boxlen);
}
}
}
}
Interpolate_Recursive_Box(outx, outy, boxlen)
int outx, outy, boxlen;
{
int i,j;
int half_boxlen;
int corner_color[2][2],color;
int outx_plus_boxlen,outy_plus_boxlen;
float one_over_boxlen;
float xalpha,yalpha;
float one_minus_xalpha,one_minus_yalpha;
/* Fill in the four pixels at the midpoints of the sides and at */
/* the center of the box by bilirping between the four corners, */
/* being careful not to exceed the boundaries of the output image, */
/* and using a flag array to avoid recomputing any pixels. */
/* For diagnostic display, flag is set to a dark gray. */
/* By making interpolation follow ray tracing, no pixels along the */
/* perimeter are filled in using interpolation, just to be replaced */
/* by a more accurate color when adjacent boxes are ray traced. */
/* By making the interpolation recursive, it is able to fill in */
/* large boxes using all pixels available along their perimeters, */
/* rather than just at their four corners. This prevents "creases", */
/* or, stated another way, insures zero-order continuity everywhere. */
half_boxlen = boxlen >> 1;
one_over_boxlen = 1.0 / (float)boxlen;
outx_plus_boxlen = outx+boxlen < image_len[X] ? outx+boxlen : outx;
outy_plus_boxlen = outy+boxlen < image_len[Y] ? outy+boxlen : outy;
corner_color[0][0] = IMAGE(outy,outx);
corner_color[0][1] = IMAGE(outy,outx_plus_boxlen);
corner_color[1][0] = IMAGE(outy_plus_boxlen,outx);
corner_color[1][1] = IMAGE(outy_plus_boxlen,outx_plus_boxlen);
for (i=0; i<=boxlen && outy+i<image_len[Y]; i+=half_boxlen) {
yalpha = (float)i * one_over_boxlen;
one_minus_yalpha = 1.0 - yalpha;
for (j=0; j<=boxlen && outx+j<image_len[X]; j+=half_boxlen) {
xalpha = (float)j * one_over_boxlen;
one_minus_xalpha = 1.0 - xalpha;
if (MASK_IMAGE(outy+i,outx+j) == 0) {
color = corner_color[0][0]*one_minus_xalpha*one_minus_yalpha+
corner_color[0][1]*xalpha*one_minus_yalpha+
corner_color[1][0]*one_minus_xalpha*yalpha+
corner_color[1][1]*xalpha*yalpha;
IMAGE(outy+i,outx+j) = color;
MASK_IMAGE(outy+i,outx+j) += INTERPOLATED;
}
}
}
/* If size of sub-boxes is above lowest size for volume data */
/* if polygon list exists or display pixel size if it does not, */
/* invoke this function recursively to fill in image within the */
/* four equal-sized square sub-boxes enclosed by the current box, */
/* being careful not to exceed the boundaries of the output image. */
if (half_boxlen > 1) {
for (i=0; i<boxlen && outy+i<image_len[Y]; i+=half_boxlen) {
for (j=0; j<boxlen && outx+j<image_len[X]; j+=half_boxlen) {
Interpolate_Recursive_Box(outx+j,outy+i,half_boxlen);
}
}
}
}