/*************************************************************************/ /* */ /* 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: */ long num_rays_traced; /* number of calls to Trace_Ray */ long num_traced_rays_hit_volume; /* number of traced rays that hit volume */ long num_samples_trilirped; /* number of samples trilirped */ long 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" void Ray_Trace(long my_node) { long i,j; long starttime,stoptime,exectime,exectime1; /* 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 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("%3ld\t%3ld\t%6ld\t%6ld\t%6ld\t%6ld\t%8ld\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); } void Ray_Trace_Adaptively(long my_node) { long outx,outy,yindex,xindex; long num_xqueue,num_yqueue,num_queue,lnum_xblocks,lnum_yblocks,lnum_blocks; long 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; outyQLock,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; } } void Ray_Trace_Adaptive_Box(long outx, long outy, long boxlen) { long i,j; long half_boxlen; long min_volume_color,max_volume_color; float foutx,fouty; volatile long 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 lowest_volume_boxlen && max_volume_color - min_volume_color >= volume_color_difference) { half_boxlen = boxlen >> 1; for (i=0; iQueue[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; outyQLock,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; } } void Ray_Trace_Fast_Non_Adaptively(long my_node) { long i,outx,outy,xindex,yindex; float foutx,fouty; PIXEL *pixel_address; for (i=0; i> 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 1) { for (i=0; i