00001 /*
00002 File: RT_Grid.cc
00003
00004 Function: Defines a hierarchical grid class for ray-tracing
00005 optimisation
00006
00007 Author: Andrew Willmott, ajw+@cs.cmu.edu
00008 */
00009
00060 #include "RT_Grid.h"
00061 #include "RT_RayStats.h"
00062 #include "FCompare.h"
00063 #ifdef RT_VIS
00064 #include "gcl/Renderer.h"
00065 #endif
00066
00067 #define RT_SetLock(x)
00068 #define RT_UnsetLock(x)
00069 #define RT_Lock Int
00070
00071 #define DBG_COUT if (0) cerr
00072
00073
00074 // --- Globals ----------------------------------------------------------------
00075
00076
00077 Int RT_Grid::sStamp = 1;
00078 Int RT_Grid::sTag = 0x00000001;
00079 // By default, the first group is enabled.
00080 Int RT_Grid::sMem = 0;
00081 Int RT_Grid::sTriMem = 0;
00082 Int RT_Grid::sGenMem = 0;
00083 Int RT_Grid::sPointMem = 0;
00084 Int RT_Grid::sMemLimit = 0;
00085
00086 Int RT_Grid::sMaxCells = 40;
00087 // Maximum cells along one side of a side
00088 Int RT_Grid::sMaxCellPrims = RT_Grid::sMaxCells;
00089 // Need this many prims in a cell before
00090 // considering them as subgrid candidates.
00091
00092 GCLReal RT_Grid::sPushSizeLimit = 0.05;
00093 // A primitive must be smaller than this
00094 // fraction of a cell for it to be a subgrid
00095 // candidate.
00096 GCLReal RT_Grid::sMaxCellRatio = 0.20;
00097 // A subgrid's cell size must be this much
00098 // smaller than its parent's.
00099 GCLReal RT_Grid::sMinDensity = 0.05;
00100 // A grid must have at least this primitive
00101 // density to be considered worthwhile creating
00102 // it.
00103 GCLReal RT_Grid::sMaxExpand = 3.00;
00104 // The maximum amount to expand a subgrid in
00105 // order to merge it with another.
00106 GCLReal RT_Grid::sEpsilon = 1e-15;
00107 // Nearness epsilon. For intersection
00108 // tests where a casting primitive isn't
00109 // provided, this helps avoid self-shadowing /
00110 // intersection.
00111
00112
00113 // --- Internal data structures -----------------------------------------------
00114
00115
00116 struct PrimEntry
00117 {
00118 union
00119 {
00120 RT_Prim* prim;
00121 RT_Grid* grid;
00122 };
00123 PrimEntry* next;
00124 };
00125
00126 typedef PrimEntry* PrimEntryPtr;
00127
00128 // We assume no memory is malloc'd at $8.
00129
00130 const PrimEntryPtr PRIM_GRID_TAG = (PrimEntry*) 0x8;
00131
00132 struct PrimListEntry
00133 {
00134 PrimEntry** list;
00135 PrimListEntry* next;
00136 };
00137
00138
00139 // --- GridStore methods ------------------------------------------------------
00140
00141
00142 Void GridStore::Init(Int size)
00143 {
00144 Int spill;
00145 Int i;
00146
00147 spill = size & PAGE_PTR_MASK; // size of last page
00148 if (spill == 0)
00149 spill = PAGE_PTR_SIZE;
00150
00151 numPages = ((size - 1) >> PAGE_PTR_BITS) + 1;
00152 pages = RT_ArrayAlloc(PrimEntry**, numPages);
00153 mem = sizeof(PrimEntry**) * numPages;
00154
00155 for (i = 0; i < numPages - 1; i++)
00156 {
00157 pages[i] = RT_ArrayAllocClr(PrimEntry*, PAGE_PTR_SIZE);
00158 Assert(pages[i] != 0, "Out of memory");
00159 mem += sizeof(PrimEntry*) * PAGE_PTR_SIZE;
00160 }
00161
00162 pages[numPages - 1] = RT_ArrayAllocClr(PrimEntry*, spill);
00163 mem += sizeof(PrimEntry*) * spill;
00164 }
00165
00166 Void GridStore::Free()
00167 {
00168 Int i;
00169
00170 if (pages)
00171 {
00172 for (i = 0; i < numPages; i++)
00173 RT_ArrayFree(pages[i]);
00174
00175 RT_ArrayFree(pages);
00176 }
00177 }
00178
00179 // --- Useful #defines --------------------------------------------------------
00180
00181
00182 #ifdef RT_USE_FC
00183 #define FEQG(a,b) F_EQG10(a,b)
00184 #define FSGN(x) ((F_EQ10((x), 0)) ? 0 : (((x) < 0) ? -1 : 1))
00185 #else
00186 #define FEQG(a, b) (b >= a)
00187 // the epsilon is necessary here so that planes that just touch grid cells
00188 // get added to them... old old bug.
00189 #define FSGN(x) (((x) > sEpsilon ) ? 1 : (((x) < -sEpsilon) ? -1 : 0))
00190 #endif
00191
00192 // --- RT_Grid methods --------------------------------------------------------
00193
00194
00195 Void RT_Grid::MasterInit()
00196 {
00197 sMem = 0;
00198 sTriMem = 0;
00199 sGenMem = 0;
00200 sPointMem = 0;
00201 Init();
00202 }
00203
00204 Void RT_Grid::Init()
00205 {
00206 totalPrims = 0;
00207 dirty = false;
00208 level = 0;
00209
00210 max.MakeBlock(-vl_inf);
00211 min.MakeBlock(vl_inf);
00212
00213 totalCells = 0;
00214 addPrims = 0;
00215 addObjs = 0;
00216 addedObjs = 0;
00217 subGrids = 0;
00218 next = 0;
00219 hitPrim = 0;
00220 hitT = 0.0;
00221 stamp = 0;
00222 parent = 0;
00223
00224 sMem += sizeof(RT_Grid);
00225 }
00226
00227 Void RT_Grid::Free()
00228 // Delete subfields of the grid.
00229 {
00230 RT_Grid *subGrid, *nextGrid = 0;
00231 Int i;
00232 PrimEntry *entry, *nextEntry = 0;
00233 PrimListEntry *tlEntry, *tlNextEntry = 0;
00234 ObjEntry *objEntry, *objNextEntry = 0;
00235
00236 // Delete subgrids
00237
00238 for (subGrid = subGrids; subGrid; subGrid = nextGrid)
00239 {
00240 nextGrid = subGrid->next;
00241 subGrid->Free();
00242 RT_Free(subGrid);
00243 }
00244
00245 // Delete the grid storage
00246
00247 if (totalCells > 0)
00248 {
00249 for (i = 0; i < totalCells; i++)
00250 for (entry = grid[i]; entry && entry != PRIM_GRID_TAG;
00251 entry = nextEntry)
00252 {
00253 nextEntry = entry->next;
00254 RT_Free(entry);
00255 }
00256
00257 grid.Free();
00258 }
00259
00260 for (tlEntry = addPrims; tlEntry; tlEntry = tlNextEntry)
00261 {
00262 tlNextEntry = tlEntry->next;
00263 RT_Free(tlEntry);
00264 }
00265
00266 for (objEntry = addObjs; objEntry; objEntry = objNextEntry)
00267 {
00268 objNextEntry = objEntry->next;
00269 RT_Free(objEntry);
00270 }
00271
00272 for (objEntry = addedObjs; objEntry; objEntry = objNextEntry)
00273 {
00274 objNextEntry = objEntry->next;
00275 RT_Free(objEntry);
00276 }
00277 }
00278
00279 Void RT_Grid::AddObject(RT_Object *object)
00280 {
00281 ObjEntry* newEntry;
00282
00283 UpdateBounds(object);
00284
00285 newEntry = RT_Alloc(ObjEntry);
00286 sMem += sizeof(ObjEntry);
00287
00288 newEntry->object = object;
00289 newEntry->next = addObjs;
00290 addObjs = newEntry;
00291
00292 dirty = true;
00293 }
00294
00295 RT_Lock *gGridLock = 0;
00296
00297 Void RT_Grid::PrepareGrid()
00298 // Prepare grid for raytracing.
00299 {
00300 ObjEntry *entry, *nextEntry;
00301 Int j;
00302
00303 if (gGridLock)
00304 RT_SetLock(*gGridLock);
00305
00306 if (!dirty)
00307 {
00308 // Another process has Prepare()'d this grid while we were
00309 // waiting for the lock...
00310
00311 if (gGridLock)
00312 RT_UnsetLock(*gGridLock);
00313 return;
00314 }
00315
00316 if (addObjs)
00317 {
00318 RT_Tri* tri;
00319 RT_GenPtr* gen;
00320
00321 SetupGrid();
00322
00323 // Add object triangles
00324
00325 for (entry = addObjs; entry; entry = nextEntry)
00326 {
00327 nextEntry = entry->next;
00328
00329 tri = entry->object->tris;
00330 for (j = 0; j < entry->object->numTris; j++, tri++)
00331 AddTriangle(tri);
00332 totalPrims += entry->object->numTris;
00333
00334 gen = entry->object->gens;
00335 for (j = 0; j < entry->object->numGens; j++, gen++)
00336 AddGeneric(*gen);
00337 totalPrims += entry->object->numGens;
00338
00339 sTriMem += sizeof(RT_Tri) * entry->object->numTris;
00340 sGenMem += sizeof(RT_GenPtr) * entry->object->numGens;
00341 sPointMem += entry->object->numPoints * sizeof(Point);
00342
00343 if (nextEntry == 0)
00344 entry->next = addedObjs;
00345 }
00346
00347 // transfer objects to the added objects list
00348
00349 addedObjs = addObjs;
00350 addObjs = 0;
00351 }
00352
00353 // Now, create nested grids.
00354
00355 dirty = false;
00356
00357 if (sMemLimit && sMem >= sMemLimit)
00358 {
00359 cerr << "*** out of memory: aborting grid creation... >"
00360 << level << endl;
00361 cerr << "*** memory = " << sMem << " bytes." << endl;
00362 if (gGridLock)
00363 RT_UnsetLock(*gGridLock);
00364 return;
00365 }
00366
00367 CreateNestedGrids();
00368
00369 if (gGridLock)
00370 RT_UnsetLock(*gGridLock);
00371 }
00372
00373
00374 Void RT_Grid::UpdateBounds(Point& cellMin, Point& cellMax)
00375 {
00376 FindMinElts(cellMin, min, min);
00377 FindMaxElts(cellMax, max, max);
00378 }
00379
00380 Void RT_Grid::UpdateBounds(RT_Object *object)
00381 {
00382 Int i;
00383 Point* points = object->points;
00384
00385 for (i = 0; i < object->numPoints; i++)
00386 ::UpdateBounds(points[i], min, max);
00387
00388 for (i = 0; i < object->numGens; i++)
00389 object->gens[i]->UpdateBounds(min, max);
00390 }
00391
00392 Void RT_Grid::SetupGrid()
00393 {
00394 GCLReal maxSpan;
00395 Vector centre, span;
00396 Int i;
00397
00398 // Calculate the boundaries for the grid. We already know
00399 // the world-space boundaries for the object.
00400
00401 // XXX fix more elegantly
00402 // expand the box a little so we don't suffer from numerical
00403 // problems for surfaces lying along one of the sides of the grid
00404 const GCLReal kGridFudge = 1e-15;
00405 Vector fudge;
00406
00407 max += fudge.MakeBlock(kGridFudge);
00408 min -= fudge;
00409
00410 span = max - min;
00411 maxSpan = MaxElt(span);
00412 cellSize = maxSpan / sMaxCells;
00413 areaLimit = sPushSizeLimit * sqr(cellSize);
00414
00415 // Calculate how many grid cells the object will have in each
00416 // direction. We've already assigned the widest direction a
00417 // preset number of grid cells and the narrower directions fewer
00418 // cells.
00419
00420 for (i = 0; i < 3; i++)
00421 {
00422 numCells[i] = (Int) ceil(sMaxCells * span[i] / maxSpan);
00423
00424 // Ensure at least 1 cell in all directions
00425 if (numCells[i] == 0)
00426 numCells[i] = 1;
00427
00428 max[i] = min[i] + numCells[i] * cellSize;
00429 }
00430
00431 // Allocate a one-dimensional array for the grid.
00432
00433 totalCells = numCells[0] * numCells[1] * numCells[2];
00434 xSpan = numCells[1] * numCells[2];
00435 ySpan = numCells[2];
00436
00437 grid.Init(totalCells);
00438 sMem += (Int) grid.MemoryUsage();
00439 }
00440
00441
00442 Void RT_Grid::AddGeneric(RT_GenPtr gen)
00443 // Add a generic object to this grid.
00444 {
00445 Vector tMin, tMax;
00446 Vector cellMin, vertex;
00447 Int i;
00448 Int x, y, z, cellNum, cellsAdded;
00449 PrimEntry **last, *entry, *newEntry;
00450 Int start[3], end[3];
00451
00452 // We want to enter the polygon into all of the grid cells
00453 // it intersects. We first limit our test of grid cells to
00454 // those in which the polygon's bounding box resides.
00455
00456 gen->FindBounds(tMin, tMax);
00457
00458 // Find the equivalent cell bounds
00459
00460 for (i = 0; i < 3; i++)
00461 {
00462 start[i] = (Int) ((tMin[i] - min[i]) / cellSize);
00463 end[i] = (Int) ((tMax[i] - min[i]) / cellSize);
00464
00465 // Crop to the grid
00466
00467 if (end[i] >= numCells[i])
00468 end[i] = numCells[i] - 1;
00469 else if (end[i] < 0)
00470 end[i] = 0;
00471
00472 if (start[i] >= numCells[i])
00473 start[i] = numCells[i] - 1;
00474 else if (start[i] < 0)
00475 start[i] = 0;
00476 }
00477
00478 // Finally, the generic is added to every grid cell in its bounding box
00479
00480 cellsAdded = 0;
00481 for (x = start[0]; x <= end[0]; x++)
00482 for (y = start[1]; y <= end[1]; y++)
00483 for (z = start[2]; z <= end[2]; z++)
00484 {
00485 cellsAdded++;
00486 newEntry = RT_Alloc(PrimEntry);
00487 sMem += sizeof(PrimEntry);
00488 cellNum = x * xSpan + y * ySpan + z;
00489
00490 newEntry->prim = gen;
00491
00492 // Insert gen in order of (equivalent) area...
00493
00494 last = &(grid[cellNum]); // the last entry we looked at
00495
00496 for (entry = *last; entry; entry = entry->next)
00497 {
00498 // Only bother sorting prims < areaLimit
00499
00500 if (entry->prim->area <= gen->area ||
00501 entry->prim->area < areaLimit)
00502 break;
00503
00504 last = &(entry->next);
00505 }
00506
00507 *last = newEntry;
00508 newEntry->next = entry;
00509 }
00510
00511 #ifdef RT_OPAC
00512 gen->cells = cellsAdded;
00513 #endif
00514 }
00515
00516
00517 Void RT_Grid::AddTriangle(RT_Tri *tri)
00518 // Add a triangle to this grid.
00519 {
00520 Vector tMin, tMax;
00521 Vector cellMin, vertex;
00522 Point *p1, *p2, *p3;
00523 Int i;
00524 Int x, y, z, sign, cellNum, cellsAdded;
00525 PrimEntry **last, *entry, *newEntry;
00526 Point* points = tri->object->points;
00527 Int start[3], end[3];
00528 GCLReal temp;
00529
00530 // We want to enter the polygon into all of the grid cells
00531 // it intersects. We first limit our test of grid cells to
00532 // those in which the polygon's bounding box resides.
00533
00534 dirty = true;
00535 p1 = points + tri->v[0];
00536 p2 = points + tri->v[1];
00537 p3 = points + tri->v[2];
00538
00539 FindMaxElts(*p1, *p2, tMax);
00540 FindMaxElts(*p3, tMax, tMax);
00541
00542 FindMinElts(*p1, *p2, tMin);
00543 FindMinElts(*p3, tMin, tMin);
00544
00545 // Find the equivalent cell bounds
00546
00547 for (i = 0; i < 3; i++)
00548 {
00549 start[i] = (Int) ((tMin[i] - min[i]) / cellSize);
00550 end[i] = (Int) ((tMax[i] - min[i]) / cellSize);
00551
00552 // Crop to the grid
00553
00554 if (end[i] >= numCells[i])
00555 end[i] = numCells[i] - 1;
00556 else if (end[i] < 0)
00557 end[i] = 0;
00558
00559 if (start[i] >= numCells[i])
00560 start[i] = numCells[i] - 1;
00561 else if (start[i] < 0)
00562 start[i] = 0;
00563 }
00564
00565 // Finally, the triangle is added to every grid cell in the bounding box
00566 // which straddles the plane of the triangle.
00567
00568 cellsAdded = 0;
00569 for (x = start[0]; x <= end[0]; x++)
00570 for (y = start[1]; y <= end[1]; y++)
00571 for (z = start[2]; z <= end[2]; z++)
00572 {
00573 // We test each vertex of the cell by plugging it into the
00574 // triangle's plane equation. If a vertex has a different
00575 // sign from the preceeding vertices, we know the plane
00576 // straddles this cube, and we add the triangle to the
00577 // cell. A result of zero means the plane touches the vertex,
00578 // which is also grounds for adding the triangle.
00579
00580 cellMin = min + Vector(x, y, z) * cellSize;
00581 cellNum = x * xSpan + y * ySpan + z;
00582 temp = dot(tri->normal, cellMin) + tri->d;
00583 sign = FSGN(temp);
00584
00585 if (sign == 0) // The first sign is zero: we can stop.
00586 i = 1;
00587 else
00588 for (i = 1; i < 8; i++)
00589 {
00590 vertex = cellMin;
00591
00592 if (i & 1) vertex[0] += cellSize;
00593 if (i & 2) vertex[1] += cellSize;
00594 if (i & 4) vertex[2] += cellSize;
00595
00596 temp = dot(tri->normal, vertex) + tri->d;
00597
00598 if (sign != FSGN(temp))
00599 break;
00600 }
00601
00602 // Add the triangle if we have a straddle
00603
00604 if (i < 8)
00605 {
00606 cellsAdded++;
00607 newEntry = RT_Alloc(PrimEntry);
00608 sMem += sizeof(PrimEntry);
00609
00610 newEntry->prim = tri;
00611
00612 // Insert tri in order of area...
00613
00614 last = &(grid[cellNum]); // the last entry we looked at
00615
00616 for (entry = *last; entry; entry = entry->next)
00617 {
00618 // Only bother sorting tris < areaLimit
00619
00620 if (entry->prim->area <= tri->area ||
00621 entry->prim->area < areaLimit)
00622 break;
00623
00624 last = &(entry->next);
00625 }
00626
00627 *last = newEntry;
00628 newEntry->next = entry;
00629 }
00630 }
00631
00632 #ifdef RT_OPAC
00633 tri->cells = cellsAdded;
00634 #endif
00635 }
00636
00637 Void RT_Grid::RayClampEntryPoint(Int index, Bool backEntry[3],
00638 Vector& gridPoint, Int cell[3])
00639 {
00640 if (backEntry[index])
00641 {
00642 // If we're entering from the back end, we're entering the
00643 // largest numbered cell in this direction.
00644
00645 cell[index] = numCells[index] - 1;
00646 gridPoint[index] = (GCLReal) numCells[index];
00647 }
00648 else
00649 {
00650 // From the front, it's the smallest, which is conveniently zero.
00651
00652 cell[index] = 0;
00653 gridPoint[index] = 0.0;
00654 }
00655 }
00656
00657
00658 Bool RT_Grid::FindGridStart(
00659
00660 const Point& start,
00661 const Vector& direction,
00662 Int cell[3],
00663 Int increment[3],
00664 Int limit[3],
00665 GCLReal& tRay,
00666 // start of ray in grid
00667 Vector& tDelta,
00668 // delta t for a step of size cellSize in each direction
00669 Vector& tMax
00670 // delta t to the next grid wall in each direction
00671 )
00672 {
00673 Int i;
00674 Vector gridPoint;
00675 Vector in, out;
00676 Bool backEntry[3];
00677 Point point;
00678
00679 gridPoint = (start - min) / cellSize;
00680
00681 if (0.0 <= gridPoint[0] && gridPoint[0] <= numCells[0] &&
00682 0.0 <= gridPoint[1] && gridPoint[1] <= numCells[1] &&
00683 0.0 <= gridPoint[2] && gridPoint[2] <= numCells[2])
00684 {
00685 // We are starting inside the grid: find which cell
00686
00687 tRay = 0.0;
00688
00689 for (i = 0; i < 3; i++)
00690 {
00691 cell[i] = (Int) floor(gridPoint[i]);
00692
00693 if (cell[i] == numCells[i])
00694 cell[i]--;
00695 }
00696 }
00697 else
00698 {
00699 // Otherwise, we have to compute the entry point
00700 // into the grid.
00701
00702 for (i = 0; i < 3; i++)
00703 {
00704 // Avoid the divide by zero. This would occur if the ray
00705 // has no component in one or two directions.
00706
00707 if (abs(direction[i]) > (GCLReal) 0.0)
00708 {
00709 in[i] = (min[i] - start[i]) / direction[i];
00710 out[i] = (max[i] - start[i]) / direction[i];
00711 }
00712 else
00713 {
00714 in[i] = -vl_inf;
00715 out[i] = vl_inf;
00716 }
00717
00718 // We're really concerned only with the entry point of the ray
00719 // into the grid. Thus, if we've got our entry and exit points
00720 // backwards, then correct the entry point.
00721
00722 if (backEntry[i] = (in[i] > out[i]))
00723 in[i] = out[i];
00724 }
00725
00726 // The actual entry point into the grid occurs at the maximum of the
00727 // just-computed entry values (i.e., we enter the grid when we've
00728 // crossed the X _and_ the Y _and_ the Z planes of the Fujimoto
00729 // grid.
00730
00731 tRay = MaxElt(in);
00732 point = start + tRay * direction;
00733
00734 // Compute the entry point in terms of grid space. (I.e., in
00735 // what cell do we enter the grid?)
00736
00737 gridPoint = (point - min) / cellSize;
00738
00739 for (i = 0; i < 3; i++)
00740 cell[i] = (Int) floor(gridPoint[i]);
00741
00742 // the cell direction corresponding to the maximum component(s)
00743 // of 'in' will lie along the boundary of the grid. To
00744 // prevent spilling over the boundary due to round-off error, we clamp
00745 // the direction(s) back to the grid boundary.
00746
00747 if (in[0] > in[1])
00748 {
00749 if (in[0] >= in[2])
00750 {
00751 RayClampEntryPoint(0, backEntry, gridPoint, cell);
00752
00753 if (in[0] == in[2])
00754 RayClampEntryPoint(2, backEntry, gridPoint, cell);
00755 }
00756 else
00757 RayClampEntryPoint(2, backEntry, gridPoint, cell);
00758 }
00759 else if (in[0] == in[1])
00760 {
00761 if (in[2] >= in[0])
00762 {
00763 RayClampEntryPoint(2, backEntry, gridPoint, cell);
00764
00765 if (in[2] == in[0])
00766 {
00767 RayClampEntryPoint(0, backEntry, gridPoint, cell);
00768 RayClampEntryPoint(1, backEntry, gridPoint, cell);
00769 }
00770 }
00771 else
00772 {
00773 RayClampEntryPoint(0, backEntry, gridPoint, cell);
00774 RayClampEntryPoint(1, backEntry, gridPoint, cell);
00775 }
00776 }
00777 else
00778 {
00779 if (in[1] >= in[2])
00780 {
00781 RayClampEntryPoint(1, backEntry, gridPoint, cell);
00782
00783 if (in[1] == in[2])
00784 RayClampEntryPoint(2, backEntry, gridPoint, cell);
00785 }
00786 else
00787 RayClampEntryPoint(2, backEntry, gridPoint, cell);
00788 }
00789
00790 // If the ray completely misses the Fujimoto grid, then we
00791 // of course didn't hit anything.
00792
00793 for (i = 0; i < 3; i++)
00794 if (cell[i] < 0 || numCells[i] <= cell[i])
00795 return(false);
00796 }
00797
00798 // Calculate auxillary info used for traversing the grid
00799
00800 for (i = 0; i < 3; i++)
00801 {
00802 GCLReal scale = cellSize;
00803
00804 // The ray that goes through the Fujimoto grid is parameterized,
00805 // i.e., the ray is of the form start + t * direction, where t is
00806 // the parameter. For any given direction (i.e. X, Y, or Z),
00807 // the amount that t changes as the ray crosses to the next cell
00808 // in the same direction is fixed. Calculate what that change in
00809 // t is and store the information. We're going to use this
00810 // information to help us traverse the grid.
00811
00812 tDelta[i] = (abs(direction[i]) == (GCLReal) 0.0) ?
00813 0.0 : scale / abs(direction[i]);
00814
00815 // Note the sign of the direction vector of the ray.
00816
00817 increment[i] = FSGN(direction[i]);
00818 limit[i] = (increment[i] < 0) ? -1 : numCells[i];
00819
00820 // Make a note of what the value of the ray parameter t will
00821 // be when we cross over the next orthogonal plane in this
00822 // direction. (Of course, if the direction vector has no
00823 // component in this direction, then we'll _never_ reach the
00824 // next grid cell in this direction.)
00825
00826 if (increment[i] == 0)
00827 tMax[i] = vl_inf;
00828 else if (increment[i] == 1)
00829 tMax[i] = tRay + tDelta[i] * (cell[i] + 1 - gridPoint[i]);
00830 else
00831 {
00832 // The the grid point is integral, i.e. if it lies exactly on
00833 // one of the orthogonal planes, then the next movement will
00834 // cross the entire cell.
00835
00836 if (gridPoint[i] == floor(gridPoint[i]))
00837 tMax[i] = tRay + tDelta[i];
00838 else
00839 tMax[i] = tRay + tDelta[i] *
00840 (gridPoint[i] - floor(gridPoint[i]));
00841 }
00842 }
00843
00844 return(tDelta[0] != 0.0 || tDelta[1] != 0.0 || tDelta[2] != 0);
00845 }
00846
00847
00848 // --- Intersection methods ---------------------------------------------------
00849
00850
00851 Bool RT_Grid::IntersectionExists(
00852 const Point& start,
00853 const Point& end,
00854 RT_Prim* origPrim,
00855 RayStats* stats
00856 )
00857 // Finds out if any intersection occurs between start and end. Ignores
00858 // intersections with origPrim, if it is not nil.
00859 {
00860 Vector direction = end - start;
00861 Vector reflectPoint;
00862 GCLReal t, tRay;
00863 Int i, increment[3], limit[3];
00864 Vector tDelta, tMax;
00865 Int nextCellDir;
00866 Int cell[3];
00867 PrimEntry* entry;
00868
00869 if (stats) stats->rays++;
00870
00871 if (sqrlen(direction) < 1e-15)
00872 return(false);
00873
00874 if (dirty)
00875 PrepareGrid();
00876
00877 if (level == 0)
00878 {
00879 // just starting off: ignore all previously stamped subgrids.
00880 RT_Grid::IncTime();
00881 RT_Prim::IncTime();
00882 }
00883 else if (IsStamped())
00884 {
00885 // return cached result
00886 if (stats) stats->d2++;
00887 return(hitPrim != 0);
00888 }
00889 else
00890 {
00891 #ifdef RT_GRID_CACHE
00892 // ensure result is cached
00893 Stamp();
00894 #endif
00895 }
00896
00897 if (stats) stats->grids++;
00898 hitPrim = 0;
00899
00900 // Figure out grid parameters, and return if we completely miss the grid
00901 if (!FindGridStart(start, direction, cell, increment, limit, tRay,
00902 tDelta, tMax))
00903 return(false);
00904
00905 // Traverse the grid...
00906
00907 for (i = 0; i < 256; i++)
00908 {
00909 // We are only after a hit, not the closest hit, so as soon as we get
00910 // one, we can return.
00911 if (stats) stats->voxels++;
00912
00913 entry = grid[cell[0] * xSpan + cell[1] * ySpan + cell[2]];
00914
00915 for (; entry; entry = entry->next)
00916 {
00917 if (stats) stats->polysTested++;
00918
00919 if (entry->next == PRIM_GRID_TAG)
00920 {
00921 // If this is a subgrid entry, call the subgrid...
00922
00923 if (entry->grid->IntersectionExists(start, end,
00924 origPrim, stats))
00925 {
00926 hitPrim = entry->grid->hitPrim;
00927 hitT = entry->grid->hitT;
00928 return(true);
00929 }
00930
00931 break; // a grid entry is always last.
00932 }
00933
00934 if (entry->prim == origPrim)
00935 continue;
00936 if ((entry->prim->flags & TRI_INACTIVE) || !(sTag & entry->prim->object->tag))
00937 continue;
00938 #ifdef RT_SUPPORT_GENS
00939 if (entry->prim->primType == rt_gen)
00940 {
00941 RT_GenPtr gen = *(RT_GenPtr*) entry->prim;
00942
00943 if (!gen->IsStamped())
00944 gen->Intersect(start, direction, 0, 1);
00945
00946 if (gen->IsTrue(GEN_HIT))
00947 {
00948 hitPrim = gen;
00949 hitT = gen->hitT;
00950 DBG_COUT << "hit generic at " << hitT << endl;
00951 return(true);
00952 }
00953 }
00954 else if (entry->prim->primType == rt_triangle)
00955 #else
00956 if(1)
00957 #endif
00958 {
00959 RT_Tri* thisTri = (RT_Tri*) entry->prim;
00960
00961 // Find ray intersection with tri's plane. Bail if there
00962 // isn't one.
00963 GCLReal normDotDirection = dot(thisTri->normal, direction);
00964
00965 if (thisTri->flags & TRI_2SIDED_V)
00966 {
00967 if (normDotDirection == 0.0)
00968 continue;
00969 }
00970 else
00971 if (normDotDirection >= 0.0)
00972 continue;
00973
00974 t = (thisTri->d + dot(thisTri->normal, start)) /
00975 -normDotDirection;
00976
00977 // Bail if the intersection occurs before 'start' or after
00978 // 'end'. the epsilon here accounts for self-shadowing.
00979 if (t <= sEpsilon || t >= (1.0 - sEpsilon))
00980 continue;
00981
00982 // Okay, let's do the actual test. If we've hit the tri
00983 // itself, we can return.
00984
00985 if (stats) stats->intersections++;
00986
00987 reflectPoint = start + t * direction;
00988 thisTri->PointIsInside(reflectPoint);
00989
00990 if (thisTri->IsTrue(TRI_HIT))
00991 {
00992 if (stats) stats->goodHits++;
00993 hitPrim = thisTri;
00994 hitT = t;
00995 return(true);
00996 }
00997 }
00998 else
00999 DBG_COUT << "unknown primitive type: " <<
01000 entry->prim->primType << endl;
01001 }
01002
01003 nextCellDir = MinEltIndex(tMax);
01004 cell[nextCellDir] += increment[nextCellDir];
01005
01006 // If we've exited the grid, then bail -- we didn't find any
01007 // intersections.
01008 if (cell[nextCellDir] == limit[nextCellDir])
01009 return(false);
01010 else
01011 tMax[nextCellDir] += tDelta[nextCellDir];
01012 }
01013
01014 #ifdef DEBUG
01015 cerr << "*** STUCK IN GRID: tMax: " << tMax << tDelta << " for " << start << end << endl;
01016 #endif
01017 }
01018
01019 RT_Prim *RT_Grid::ClosestIntersection(
01020 const Point& start, // Start of the ray
01021 const Vector& direction, // direction of the same
01022 RT_Prim* origPrim, // originating primitive
01023 RayStats* stats // ray statistics.
01024 )
01025 // Finds the closest intersection to the start point. Ignores
01026 // intersections with origPrim, if it is not nil.
01027 {
01028 Vector reflectPoint;
01029 Int increment[3], limit[3];
01030 GCLReal tRayNext, tRayLast, t, tMin;
01031 Vector tDelta, tMax;
01032 Int nextCellDir;
01033 Int cell[3];
01034 PrimEntry* entry;
01035
01036 if (stats) stats->rays++;
01037
01038 if (dirty)
01039 PrepareGrid();
01040
01041 if (level == 0)
01042 {
01043 // just starting off: ignore all previously stamped subgrids + prims
01044 DBG_COUT << "clearing stamps" << endl;
01045 RT_Prim::IncTime();
01046 RT_Grid::IncTime();
01047 }
01048 else if (IsStamped())
01049 {
01050 // return cached result
01051 DBG_COUT << "returning cached result" << endl;
01052 if (stats) stats->d2++;
01053 return(hitPrim);
01054 }
01055 else
01056 {
01057 #ifdef RT_GRID_CACHE
01058 // ensure result is cached
01059 Stamp();
01060 #endif
01061 }
01062
01063 if (stats) stats->grids++;
01064 hitPrim = 0;
01065
01066 // Figure out grid's parameters, and return if we completely miss its
01067 // bounding box.
01068 if (!FindGridStart(start, direction, cell, increment, limit, tRayNext,
01069 tDelta, tMax))
01070 return(hitPrim);
01071
01072 // Traverse the grid & keep track of the closest intersection found so far.
01073 // tRayLast and tRayNext bracket the t values of the part of the ray that
01074 // passes through the current cell. We're only interested in hits that
01075 // occur within these values.
01076 tRayLast = Max(sEpsilon, tRayNext);
01077
01078 for (;;)
01079 {
01080 // We have to check all the triangles within this cell, since they
01081 // are in no particular order with respect to the ray.
01082 if (stats) stats->voxels++;
01083
01084 entry = grid[cell[0] * xSpan + cell[1] * ySpan + cell[2]];
01085 nextCellDir = MinEltIndex(tMax); // the next cell after this...
01086 tRayNext = tMax[nextCellDir]; // t at which we leave this cell
01087
01088 // Update record of delta t to the next cell in each direction.
01089 cell[nextCellDir] += increment[nextCellDir];
01090 tMax[nextCellDir] += tDelta[nextCellDir];
01091
01092 // we're only interested in hits before tMin
01093 if (cell[nextCellDir] == limit[nextCellDir])
01094 tMin = vl_inf;
01095 else
01096 tMin = tRayNext;
01097
01098 DBG_COUT << "searching " << tRayLast << " - " << tRayNext << endl;
01099
01100 // Iterate through the primitives in this cell...
01101 for (; entry; entry = entry->next)
01102 {
01103 DBG_COUT << "checking cell prim" << endl;
01104 if (entry->next == PRIM_GRID_TAG)
01105 {
01106 // If this is a subgrid entry
01107 if (entry->grid->ClosestIntersection(start, direction,
01108 origPrim, stats))
01109 {
01110 t = entry->grid->hitT;
01111
01112 if (FEQG(tRayLast, t) && FEQG(t, tMin))
01113 {
01114 hitPrim = entry->grid->hitPrim;
01115 hitT = t;
01116 tMin = t;
01117 DBG_COUT << "hit grid at " << t << endl;
01118 }
01119 }
01120 break; // RT_Grid is always last.
01121 }
01122
01123 if (entry->prim == origPrim)
01124 continue;
01125 if ((entry->prim->flags & TRI_INACTIVE) || !(sTag & entry->prim->object->tag))
01126 continue;
01127
01128 DBG_COUT << "intersecting" << endl;
01129 #ifdef RT_SUPPORT_GENS
01130 if (entry->prim->primType == rt_gen)
01131 {
01132 RT_GenPtr gen = *(RT_GenPtr*) entry->prim;
01133
01134 if (!gen->IsStamped())
01135 gen->Intersect(start, direction, tRayLast, tMin);
01136
01137 if (gen->IsTrue(GEN_HIT))
01138 {
01139 tMin = gen->hitT;
01140 hitT = tMin;
01141 t = hitT;
01142 hitPrim = gen;
01143 if (stats) stats->hits++;
01144 DBG_COUT << "hit gen at " << hitT << endl;
01145 }
01146
01147 }
01148 else if (entry->prim->primType == rt_triangle)
01149 #else
01150 if(1)
01151 #endif
01152 {
01153 RT_Tri* thisTri = (RT_Tri*) entry->prim;
01154
01155 if (stats) stats->polysTested++;
01156
01157 // Find ray intersection with tri's plane.
01158 // Bail if there isn't one.
01159 GCLReal normDotDirection = dot(thisTri->normal, direction);
01160
01161 if (thisTri->flags & TRI_2SIDED_R)
01162 {
01163 if (normDotDirection == 0.0)
01164 continue;
01165 }
01166 else
01167 if (normDotDirection >= 0.0)
01168 continue;
01169
01170 t = (thisTri->d + dot(thisTri->normal, start)) /
01171 -normDotDirection;
01172
01173 // Bail if it occurs before start of the cell, or after tMin
01174 if ((!FEQG(tRayLast, t) || !FEQG(t, tMin)))
01175 {
01176 DBG_COUT << "hit outside cell" << endl;
01177 continue;
01178 }
01179 // Okay, lets do the actual test. If we've hit the tri itself,
01180 // we can return a hit after we've finished this voxel.
01181 if (stats) stats->intersections++;
01182 reflectPoint = start + t * direction;
01183
01184 if (!thisTri->IsStamped())
01185 thisTri->PointIsInside(reflectPoint);
01186
01187 if (thisTri->IsTrue(TRI_HIT))
01188 {
01189 tMin = t;
01190 hitT = t;
01191 #ifdef RT_GRID_SHADE_DEBUG
01192 thisTri->id = level;
01193 #endif
01194 hitPrim = thisTri;
01195 if (stats) stats->hits++;
01196 DBG_COUT << "hit tri at " << t << endl;
01197 }
01198 }
01199 else
01200 DBG_COUT << "unknown prim type: " << entry->prim->primType
01201 << endl;
01202 }
01203
01204 if (hitPrim)
01205 {
01206 // We hit something inside this cell. Mission over, let's go home...
01207 if (stats) stats->goodHits++;
01208 return(hitPrim);
01209 }
01210
01211 // If we've exited the grid, then bail--we didn't find any
01212 // intersections.
01213
01214 if (cell[nextCellDir] == limit[nextCellDir])
01215 return(hitPrim);
01216
01217 tRayLast = tRayNext;
01218 }
01219 }
01220
01221
01222 // --- Nested grid setup ------------------------------------------------------
01223
01224
01225 Void RT_Grid::CreateNestedGrids()
01226 // Finds cells with too many primitives in them, and creates new grids to hold
01227 // them.
01228 {
01229 Int x, y, z, count;
01230 PrimEntry *entry, *startEntry, **pushStart;
01231 RT_Grid *subGrid, *bestGrid;
01232 PrimListEntry *newPrimListEntry;
01233 Vector cellMin, cellMax, bmin, bmax;
01234 GCLReal newBVol, expRatio;
01235 GCLReal minRatio;
01236 Vector cellSpan, primsMin, primsMax, primsSpan;
01237
01238 // Loop over the entire grid.
01239
01240 for (x = 0; x < numCells[0]; x++)
01241 for (y = 0; y < numCells[1]; y++)
01242 for (z = 0; z < numCells[2]; z++)
01243 {
01244 count = 0;
01245 startEntry = grid[x * xSpan + y * ySpan + z];
01246
01247 // + Don't push prims larger than areaLimit...
01248 // This limit exists for two reasons: if a primitive is very
01249 // large compared to its grid, it will create far too many
01250 // prim entries, plus there's also not much gain in pushing
01251 // a primitive that's already on the order of the size
01252 // of a voxel.
01253
01254 // find start of pushable prims (the entries are sorted
01255 // by area)
01256 pushStart = &(grid[x * xSpan + y * ySpan + z]);
01257 for (entry = startEntry; entry; entry = entry->next)
01258 if (entry->prim->area < areaLimit)
01259 break;
01260 else
01261 pushStart = &(entry->next);
01262
01263 // Count pushable prims
01264 for (entry = *pushStart; entry; entry = entry->next)
01265 count++;
01266
01267 // Add this cell's prims to a subgrid if there are too many of
01268 // them
01269 if (count > sMaxCellPrims * (level + 1))
01270 {
01271 // Find the bounds of the prims
01272
01273 cellMin = min + Vector(x, y, z) * cellSize;
01274 cellMax.MakeBlock(cellSize);
01275 cellMax += cellMin;
01276 primsMin.MakeBlock(+vl_inf);
01277 primsMax.MakeBlock(-vl_inf);
01278
01279 for (entry = *pushStart; entry; entry = entry->next)
01280 {
01281 if (entry->prim->primType == rt_triangle)
01282 ((RT_Tri*) entry->prim)->
01283 UpdateBounds(primsMin, primsMax);
01284 else if (entry->prim->primType == rt_gen)
01285 (*(RT_GenPtr*) entry->prim)->
01286 UpdateBounds(primsMin, primsMax);
01287 else
01288 DBG_COUT << "illegal prim type" << endl;
01289 }
01290
01291 // Trim the bounds to the boundaries of the cell
01292
01293 FindMaxElts(primsMin, cellMin, primsMin);
01294 FindMinElts(primsMax, cellMax, primsMax);
01295
01296 // We need a new grid. See whether we can merge with one of
01297 // the already-created subgrids.
01298
01299 minRatio = sMaxExpand;
01300 bestGrid = 0;
01301 primsSpan = primsMax - primsMin;
01302 newBVol = primsSpan[0] * primsSpan[1] * primsSpan[2];
01303
01304 for (subGrid = subGrids; subGrid; subGrid = subGrid->next)
01305 {
01306 GCLReal cellRatio;
01307
01308 // Find the bounds of the putatative new grid.
01309
01310 FindMinElts(subGrid->min, primsMin, bmin);
01311 FindMaxElts(subGrid->max, primsMax, bmax);
01312
01313 // We want to ensure the cellSize of subgrids doesn't
01314 // get too large... so we find the ratio of the cell
01315 // size of the new grid to the parent (cellRatio)
01316 // and the increase in volume over the old grid.
01317
01318 cellRatio = MaxElt(bmax - bmin) /
01319 (sMaxCells * cellSize);
01320 expRatio = BoxVol(bmin, bmax) /
01321 (BoxVol(subGrid->min, subGrid->max) + newBVol);
01322
01323 // If both are acceptable, this is our new best grid
01324
01325 if (expRatio < minRatio && cellRatio < sMaxCellRatio)
01326 {
01327 minRatio = expRatio;
01328 bestGrid = subGrid;
01329 }
01330 }
01331
01332 if (!bestGrid)
01333 {
01334 // We need a brand-spanking-new grid if we didn't
01335 // find one to merge with.
01336
01337 bestGrid = RT_Alloc(RT_Grid);
01338
01339 bestGrid->Init();
01340 bestGrid->parent = this;
01341 bestGrid->level = level + 1;
01342 bestGrid->next = subGrids;
01343 bestGrid->dirty = true;
01344 subGrids = bestGrid;
01345 }
01346
01347 // Add a pointer to the pushable prims to the prim list of
01348 // the subgrid
01349
01350 newPrimListEntry = RT_Alloc(PrimListEntry);
01351 sMem += sizeof(PrimListEntry);
01352
01353 newPrimListEntry->list = pushStart;
01354 newPrimListEntry->next = bestGrid->addPrims;
01355 bestGrid->addPrims = newPrimListEntry;
01356
01357 bestGrid->UpdateBounds(primsMin, primsMax);
01358 bestGrid->totalPrims += count;
01359 }
01360 }
01361
01362 CullSubGrids();
01363 PushPrimitives();
01364 }
01365
01366 Void RT_Grid::CullSubGrids()
01367 // Cull subgrids that aren't worth the extra space.
01368 {
01369 GCLReal r;
01370 Int estCellTotal;
01371 Vector span;
01372 RT_Grid* subGrid;
01373 RT_Grid** last;
01374
01375 last = &subGrids;
01376
01377 for (subGrid = *last; subGrid; subGrid = *last)
01378 {
01379 span = subGrid->max - subGrid->min;
01380 r = sMaxCells / MaxElt(span);
01381 estCellTotal = Int(r * r * r * GCLReal(span[0] * span[1] * span[2]));
01382
01383 if (subGrid->totalPrims / GCLReal(estCellTotal) <
01384 sMinDensity * (1 - level / 2.0))
01385 {
01386 // Delete the subgrid from the list.
01387
01388 *last = subGrid->next;
01389 subGrid->Free();
01390 RT_Free(subGrid);
01391 }
01392 else
01393 last = &(subGrid->next);
01394 }
01395 }
01396
01397 Void RT_Grid::PushPrimitives()
01398 // Shift primitives down to the grids created by CreateNestedGrids routine...
01399 {
01400 PrimEntry *entry, *nextEntry;
01401 RT_Grid *subGrid;
01402 PrimListEntry *primList;
01403
01404 for (subGrid = subGrids; subGrid; subGrid = subGrid->next)
01405 {
01406 // Create the grids!
01407 subGrid->SetupGrid();
01408 subGrid->dirty = true;
01409 RT_Prim::IncTime();
01410
01411 // Push the primitives!
01412 for (primList = subGrid->addPrims; primList; primList = primList->next)
01413 {
01414 // Each primList is a list of primitives pushed to this grid
01415 // from a particular cell.
01416
01417 for (entry = *(primList->list); entry; entry = nextEntry)
01418 {
01419 nextEntry = entry->next;
01420
01421 // Add primitives, avoiding duplicates
01422
01423 if (!entry->prim->IsStamped())
01424 {
01425 if (entry->prim->primType == rt_triangle)
01426 subGrid->AddTriangle((RT_Tri*) entry->prim);
01427 else if (entry->prim->primType == rt_gen)
01428 subGrid->AddGeneric(*(RT_GenPtr*) entry->prim);
01429 else
01430 DBG_COUT << "illegal prim type" << endl;
01431
01432 entry->prim->Stamp();
01433 }
01434 else
01435 totalPrims--;
01436
01437 RT_Free(entry);
01438 sMem -= sizeof(PrimEntry);
01439 }
01440
01441 // Remove the pushed primitives from the cell list, and replace
01442 // them with a grid entry.
01443
01444 *primList->list = RT_Alloc(PrimEntry);
01445 sMem += sizeof(PrimEntry);
01446 (*primList->list)->next = PRIM_GRID_TAG;
01447 (*primList->list)->grid = subGrid;
01448 }
01449
01450 addPrims = 0;
01451 }
01452 }
01453
01454
01455 // --- Support routines -------------------------------------------------------
01456
01457
01458 static Void Indent(ostream &s, Int n)
01459 {
01460 Int i;
01461
01462 for (i = 0; i < n; i++)
01463 s << ' ';
01464 }
01465
01466 Void RT_Grid::HierPrint(ostream &s, Int indent)
01467 {
01468 RT_Grid* subGrid;
01469
01470 Indent(s, indent);
01471 s << totalPrims << " prims, bbox: " << min << ' ' << max << endl;
01472
01473 for(subGrid = subGrids; subGrid; subGrid = subGrid->next)
01474 subGrid->HierPrint(s, indent + 2);
01475 }
01476
01477
01478 // --- Memory methods ---------------------------------------------------------
01479
01480
01481 Void RT_Grid::SetMemLimit(Int maxKbs)
01482 {
01483 sMemLimit = 1024 * maxKbs;
01484 }
01485
01486 GCLReal RT_Grid::GridMemoryUsage()
01487 {
01488 return(sMem / 1024.0);
01489 }
01490
01491 GCLReal RT_Grid::MemoryUsage()
01492 {
01493 return((sMem + sTriMem + sGenMem + sPointMem) / 1024.0);
01494 }
01495
01496 Void RT_Grid::DumpMemoryUsage()
01497 {
01498 RT_Grid *sgrid;
01499
01500 Int numGrids = 0;
01501 for (sgrid = subGrids; sgrid; sgrid = sgrid->next)
01502 numGrids++;
01503
01504 cout << "Sub grids: " << numGrids << endl;
01505 cout << "Grid pages: " << grid.NumPages() << endl;
01506 cout << "Grid memory usage: " << GridMemoryUsage() << "k" << endl;
01507 cout << "Triangle memory: " << sTriMem / 1024.0 << "k" << endl;
01508 cout << "Generic memory: " << sGenMem / 1024.0 << "k" << endl;
01509 cout << "Points memory: " << sPointMem / 1024.0 << "k" << endl;
01510 }
01511
01512 #ifdef RT_VIS
01513
01514 // --- Visualisation ----------------------------------------------------------
01515
01516 #include "gcl/Draw.h"
01517
01518 Void RT_Grid::Draw(Renderer &r, Int level)
01519 {
01520 r.C(Colour4(HSVCol(hsvYellow + 60 * level, 1, 1), 0.2));
01521 FrameBox(r, min, max);
01522 r.C(Colour4(HSVCol(hsvOrange + 60 * level, 1, 1), 0.2));
01523
01524 Vector d1, d2;
01525 Point p;
01526 Int x, y, z;
01527
01528 d1 = max - min;
01529 d2 = d1;
01530 d2[0] /= numCells[0];
01531 d2[1] /= numCells[1];
01532 d2[2] /= numCells[2];
01533
01534 for (x = 0; x < numCells[0]; x++)
01535 for (y = 0; y < numCells[1]; y++)
01536 for (z = 0; z < numCells[2]; z++)
01537 {
01538 if (grid[x * xSpan + y * ySpan + z])
01539 {
01540 p = min + Vector(x, y, z) * d2;
01541 FrameBox(r, p, p + d2);
01542 }
01543 }
01544
01545 // Draw subgrids.
01546 RT_Grid *sgrid;
01547 level++;
01548
01549 for (sgrid = subGrids; sgrid; sgrid = sgrid->next)
01550 sgrid->Draw(r, level);
01551 }
01552
01553 #endif