import java.util.Vector; /** * Uniform spatial subdivision grid * Uses Jevans/Cleary traversal method * Refs: "Object Space Temporal Coherence for Ray Tracing" * by David A. Jevans, Graphics Interface, 1992 * "Adaptive Voxel Subdivision for Ray Tracing" * by David A. Jevans and Brian Wyvill, Graphics Interface, 1989 * "Analysis of an Algorithm for Fast Ray Tracing Using * Uniform Space Subdivision" by John Cleary and Geoff Wyvill, 1988 * @author: Phil Gage */ class Grid { /** Grid cells,left null until used to save memory */ Voxel voxel[][][]; /** Number of grid divisions for each axis */ VoxelIndex size; /** Minimum and maximum values of whole grid */ private Extent extent; // Temp locals private VoxelIndex min = new VoxelIndex (); private VoxelIndex max = new VoxelIndex (); private VoxelIndex index = new VoxelIndex (); double origin[] = new double[3]; double width[] = new double[3]; // Grid traversal temp locals private VoxelIndex tempIndex = new VoxelIndex (); Box boundBox; Point tempPoint = new Point(); Intersection tempIntersection = new Intersection(); double delta[] = new double[3]; double d[] = new double[3]; double dir[] = new double[3]; double orig[] = new double[3]; int p[] = new int[3]; /** Create grid with specified spatial extent and size */ Grid (Extent extent, VoxelIndex size) { //System.out.println("Grid extent="+extent); //System.out.println("Grid size="+size); this.size = new VoxelIndex(size); this.extent = new Extent(extent); // Ugh, I regret mixing xyz and array notations... // (tbd fix messy point to array conversion:) origin[0] = extent.min.x; origin[1] = extent.min.y; origin[2] = extent.min.z; width[0] = (extent.max.x - extent.min.x) / size.xyz[0]; width[1] = (extent.max.y - extent.min.y) / size.xyz[1]; width[2] = (extent.max.z - extent.min.z) / size.xyz[2]; // Allocate 3D array of references to all grid cells // Only creates pointers left null until used to save memory voxel = new Voxel[size.xyz[0]][size.xyz[1]][size.xyz[2]]; // Create bounding box object for traverse camera off-grid test boundBox = new Box (extent, Color.BLACK); } /** Return grid indices of world point */ void getVoxel (Point p, VoxelIndex index) { index.xyz[0] = (int)((double)size.xyz[0] * (p.x - extent.min.x) / (extent.max.x - extent.min.x)); index.xyz[1] = (int)((double)size.xyz[1] * (p.y - extent.min.y) / (extent.max.y - extent.min.y)); index.xyz[2] = (int)((double)size.xyz[2] * (p.z - extent.min.z) / (extent.max.z - extent.min.z)); } /** Convert object extent to voxels and clip to grid extent */ void getVoxelRange (Extent extent, VoxelIndex min, VoxelIndex max) { getVoxel (extent.min, min); getVoxel (extent.max, max); for (int i=0; i<3; i++) { if (min.xyz[i] < 0) min.xyz[i] = 0; if (max.xyz[i] > size.xyz[i]-1) max.xyz[i] = size.xyz[i]-1; } } /** Add object to all voxels that its extent overlaps */ void addObject (AbstractObject object, Extent extent) { //System.out.println("addObject extent="+extent); getVoxelRange (extent, min, max); for (int x=min.xyz[0]; x<=max.xyz[0]; x++) { for (int y=min.xyz[1]; y<=max.xyz[1]; y++) { for (int z=min.xyz[2]; z<=max.xyz[2]; z++) { if (voxel[x][y][z] == null) voxel[x][y][z] = new Voxel(); //TBD if (object.intersect(voxel))? here later...? voxel[x][y][z].objects.addElement(object); voxel[x][y][z].changed = true; } } } } /** Delete object from all voxels that its extent overlaps */ void deleteObject (AbstractObject object, Extent extent) { //System.out.println("deleteObject extent="+extent); getVoxelRange (extent, min, max); for (int x=min.xyz[0]; x<=max.xyz[0]; x++) { for (int y=min.xyz[1]; y<=max.xyz[1]; y++) { for (int z=min.xyz[2]; z<=max.xyz[2]; z++) { voxel[x][y][z].objects.removeElement(object); voxel[x][y][z].changed = true; } } } } //could combine both for efficiency? // void updateObject (AbstractObject object, Extent oldExtent, // Extent newExtent) { // } /** Clear all voxel changed flags in all voxels */ void clearChanged () { for (int x=0; x