// return all occluders in all cells that intersect the triangle (p1,p2,p3) // these occluders do not necessarily intersect (p1,p2,p3), but all possible intersections are included in this set void Grid::triangleIntersections(Vec3r p0,Vec3r p1,Vec3r p2, set<Polygon3r*> & possibleIntersections) { Vec3r triverts[3] = {p0,p1,p2}; // find the bbox of the triangle vector<Vec3r> vertices; vertices.push_back(triverts[0]); vertices.push_back(triverts[1]); vertices.push_back(triverts[2]); Vec3r dummy; Polygon3r triangle(vertices,dummy); Vec3r min, max; triangle.getBBox(min, max); // Compute the cell coordinates for the bbox Vec3u imax, imin; getCellCoordinates(max, imax); getCellCoordinates(min, imin); // We are now going to iterate over the cells overlapping with the // polygon bbox. for (unsigned z = imin[2]; z <= imax[2]; z++) for (unsigned y = imin[1]; y <= imax[1]; y++) for (unsigned x = imin[0]; x <= imax[0]; x++) { Vec3u coord; Vec3r boxmin, boxmax; coord[0] = x; coord[1] = y; coord[2] = z; // We retrieve the box coordinates of the current cell getCellBox(coord, boxmin, boxmax); // We check whether the triangle and the box ovewrlap: Vec3r boxcenter((boxmin + boxmax) / 2.0); Vec3r boxhalfsize(_cell_size / 2.0); Cell * cell = getCell(coord); if (cell != NULL && GeomUtils::overlapTriangleBox(boxcenter, boxhalfsize, triverts)) for(OccludersSet::iterator it = cell->getOccluders().begin(); it != cell->getOccluders().end(); ++it) possibleIntersections.insert(*it); } }
/* by Tomas Akenine-Möller */ bool BoundingBox::containsTriangle( const Vec& tv0, const Vec& tv1, const Vec& tv2 ) const { Vec boxcenter(center); Vec boxhalfsize(xExtent, yExtent, zExtent); int X = 0, Y = 1, Z = 2; /* use separating axis theorem to test overlap between triangle and box */ /* need to test for overlap in these directions: */ /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */ /* we do not even need to test these) */ /* 2) normal of the triangle */ /* 3) crossproduct(edge from tri, {x,y,z}-directin) */ /* this gives 3x3=9 more tests */ Vec v0,v1,v2; double min,max,p0,p1,p2,rad,fex,fey,fez; Vec normal,e0,e1,e2; /* This is the fastest branch on Sun */ /* move everything so that the box center is in (0,0,0) */ v0=tv0-boxcenter; v1=tv1-boxcenter; v2=tv2-boxcenter; /* compute triangle edges */ e0=v1-v0; /* tri edge 0 */ e1=v2-v1; /* tri edge 1 */ e2=v0-v2; /* tri edge 2 */ /* Bullet 3: */ /* test the 9 tests first (this was faster) */ fex = fabsf(e0[X]); fey = fabsf(e0[Y]); fez = fabsf(e0[Z]); AXISTEST_X01(e0[Z], e0[Y], fez, fey); AXISTEST_Y02(e0[Z], e0[X], fez, fex); AXISTEST_Z12(e0[Y], e0[X], fey, fex); fex = fabsf(e1[X]); fey = fabsf(e1[Y]); fez = fabsf(e1[Z]); AXISTEST_X01(e1[Z], e1[Y], fez, fey); AXISTEST_Y02(e1[Z], e1[X], fez, fex); AXISTEST_Z0(e1[Y], e1[X], fey, fex); fex = fabsf(e2[X]); fey = fabsf(e2[Y]); fez = fabsf(e2[Z]); AXISTEST_X2(e2[Z], e2[Y], fez, fey); AXISTEST_Y1(e2[Z], e2[X], fez, fex); AXISTEST_Z12(e2[Y], e2[X], fey, fex); /* Bullet 1: */ /* first test overlap in the {x,y,z}-directions */ /* find min, max of the triangle each direction, and test for overlap in */ /* that direction -- this is equivalent to testing a minimal AABB around */ /* the triangle against the AABB */ /* test in X-direction */ FINDMINMAX(v0[X],v1[X],v2[X],min,max); if(min>boxhalfsize[X] || max<-boxhalfsize[X]) return 0; /* test in Y-direction */ FINDMINMAX(v0[Y],v1[Y],v2[Y],min,max); if(min>boxhalfsize[Y] || max<-boxhalfsize[Y]) return 0; /* test in Z-direction */ FINDMINMAX(v0[Z],v1[Z],v2[Z],min,max); if(min>boxhalfsize[Z] || max<-boxhalfsize[Z]) return 0; /* Bullet 2: */ /* test if the box intersects the plane of the triangle */ /* compute plane equation of triangle: normal*x+d=0 */ normal = e0 ^ e1; if(!planeBoxOverlap(normal,v0,boxhalfsize)) return 0; return 1; /* box and triangle overlaps */ }
bool isBoxIntersectingTriangle(const Box_f & box, const Triangle_f & triangle) { /* use separating axis theorem to test overlap between triangle and box */ /* need to test for overlap in these directions: */ /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */ /* we do not even need to test these) */ /* 2) normal of the triangle */ /* 3) crossproduct(edge from tri, {x,y,z}-directin) */ /* this gives 3x3=9 more tests */ Vec3 boxcenter = box.getCenter(); Vec3 boxhalfsize(0.5f * box.getExtentX(), 0.5f * box.getExtentY(), 0.5f * box.getExtentZ()); /* This is the fastest branch on Sun */ /* move everything so that the boxcenter is in (0,0,0) */ const auto v0 = triangle.getVertexA() - boxcenter; const auto v1 = triangle.getVertexB() - boxcenter; const auto v2 = triangle.getVertexC() - boxcenter; /* compute triangle edges */ const auto e0 = triangle.getEdgeAB(); const auto e1 = triangle.getEdgeBC(); const auto e2 = triangle.getEdgeCA(); /* Bullet 3: */ /* test the 9 tests first (this was faster) */ float p0, p1, p2, rad, pMin, pMax; Vec3 fe = e0.getAbs(); p0 = e0.z() * v0.y() - e0.y() * v0.z(); p2 = e0.z() * v2.y() - e0.y() * v2.z(); if (p0 < p2) { pMin = p0; pMax = p2; } else { pMin = p2; pMax = p0; } rad = fe.z() * boxhalfsize.y() + fe.y() * boxhalfsize.z(); if (pMin > rad || pMax < -rad) return 0; p0 = -e0.z() * v0.x() + e0.x() * v0.z(); p2 = -e0.z() * v2.x() + e0.x() * v2.z(); if (p0 < p2) { pMin = p0; pMax = p2; } else { pMin = p2; pMax = p0; } rad = fe.z() * boxhalfsize.x() + fe.x() * boxhalfsize.z(); if (pMin > rad || pMax < -rad) return 0; p1 = e0.y() * v1.x() - e0.x() * v1.y(); p2 = e0.y() * v2.x() - e0.x() * v2.y(); if (p2 < p1) { pMin = p2; pMax = p1; } else { pMin = p1; pMax = p2; } rad = fe.y() * boxhalfsize.x() + fe.x() * boxhalfsize.y(); if (pMin > rad || pMax < -rad) return 0; fe = e1.getAbs(); p0 = e1.z() * v0.y() - e1.y() * v0.z(); p2 = e1.z() * v2.y() - e1.y() * v2.z(); if (p0 < p2) { pMin = p0; pMax = p2; } else { pMin = p2; pMax = p0; } rad = fe.z() * boxhalfsize.y() + fe.y() * boxhalfsize.z(); if (pMin > rad || pMax < -rad) return 0; p0 = -e1.z() * v0.x() + e1.x() * v0.z(); p2 = -e1.z() * v2.x() + e1.x() * v2.z(); if (p0 < p2) { pMin = p0; pMax = p2; } else { pMin = p2; pMax = p0; } rad = fe.z() * boxhalfsize.x() + fe.x() * boxhalfsize.z(); if (pMin > rad || pMax < -rad) return 0; p0 = e1.y() * v0.x() - e1.x() * v0.y(); p1 = e1.y() * v1.x() - e1.x() * v1.y(); if (p0 < p1) { pMin = p0; pMax = p1; } else { pMin = p1; pMax = p0; } rad = fe.y() * boxhalfsize.x() + fe.x() * boxhalfsize.y(); if (pMin > rad || pMax < -rad) return 0; fe = e2.getAbs(); p0 = e2.z() * v0.y() - e2.y() * v0.z(); p1 = e2.z() * v1.y() - e2.y() * v1.z(); if (p0 < p1) { pMin = p0; pMax = p1; } else { pMin = p1; pMax = p0; } rad = fe.z() * boxhalfsize.y() + fe.y() * boxhalfsize.z(); if (pMin > rad || pMax < -rad) return 0; p0 = -e2.z() * v0.x() + e2.x() * v0.z(); p1 = -e2.z() * v1.x() + e2.x() * v1.z(); if (p0 < p1) { pMin = p0; pMax = p1; } else { pMin = p1; pMax = p0; } rad = fe.z() * boxhalfsize.x() + fe.x() * boxhalfsize.z(); if (pMin > rad || pMax < -rad) return 0; p1 = e2.y() * v1.x() - e2.x() * v1.y(); p2 = e2.y() * v2.x() - e2.x() * v2.y(); if (p2 < p1) { pMin = p2; pMax = p1; } else { pMin = p1; pMax = p2; } rad = fe.y() * boxhalfsize.x() + fe.x() * boxhalfsize.y(); if (pMin > rad || pMax < -rad) return 0; /* Bullet 1: */ /* first test overlap in the {x,y,z}-directions */ /* find min, max of the triangle each direction, and test for overlap in */ /* that direction -- this is equivalent to testing a minimal AABB around */ /* the triangle against the AABB */ /* test in X-direction */ if (std::min(std::min(v0.x(), v1.x()), v2.x()) > boxhalfsize[0] || std::max(std::max(v0.x(), v1.x()), v2.x()) < -boxhalfsize[0]) return 0; /* test in Y-direction */ if (std::min(std::min(v0.y(), v1.y()), v2.y()) > boxhalfsize[1] || std::max(std::max(v0.y(), v1.y()), v2.y()) < -boxhalfsize[1]) return 0; /* test in Z-direction */ if (std::min(std::min(v0.z(), v1.z()), v2.z()) > boxhalfsize[2] || std::max(std::max(v0.z(), v1.z()), v2.z()) < -boxhalfsize[2]) return 0; /* Bullet 2: */ /* test if the box intersects the plane of the triangle */ /* compute plane equation of triangle: normal*x+d=0 */ Vec3 normal = e0.cross(e1); float d = -normal.dot(v0); /* plane eq: normal.x+d=0 */ Vec3 vmin, vmax; for (int q = 0; q < 3; q++) { if (normal[q] > 0.0f) { vmin[q] = -boxhalfsize[q]; vmax[q] = boxhalfsize[q]; } else { vmin[q] = boxhalfsize[q]; vmax[q] = -boxhalfsize[q]; } } if (normal.dot(vmin) + d > 0.0f) return 0; if (normal.dot(vmax) + d >= 0.0f) return 1; return 0; }
void Grid::insertOccluder(Polygon3r* occluder) { const vector<Vec3r> vertices = occluder->getVertices(); if (vertices.size() == 0) return; // add this occluder to the grid's occluders list addOccluder(occluder); // find the bbox associated to this polygon Vec3r min, max; occluder->getBBox(min, max); // Retrieve the cell x, y, z cordinates associated with these min and max Vec3u imax, imin; getCellCoordinates(max, imax); getCellCoordinates(min, imin); // We are now going to fill in the cells overlapping with the // polygon bbox. // If the polygon is a triangle (most of cases), we also // check for each of these cells if it is overlapping with // the triangle in order to only fill in the ones really overlapping // the triangle. unsigned i, x, y, z; vector<Vec3r>::const_iterator it; Vec3u coord; if (vertices.size() == 3) { // Triangle case Vec3r triverts[3]; i = 0; for(it = vertices.begin(); it != vertices.end(); it++) { triverts[i] = Vec3r(*it); i++; } Vec3r boxmin, boxmax; for (z = imin[2]; z <= imax[2]; z++) for (y = imin[1]; y <= imax[1]; y++) for (x = imin[0]; x <= imax[0]; x++) { coord[0] = x; coord[1] = y; coord[2] = z; // We retrieve the box coordinates of the current cell getCellBox(coord, boxmin, boxmax); // We check whether the triangle and the box ovewrlap: Vec3r boxcenter((boxmin + boxmax) / 2.0); Vec3r boxhalfsize(_cell_size / 2.0); if (GeomUtils::overlapTriangleBox(boxcenter, boxhalfsize, triverts)) { // We must then create the Cell and add it to the cells list // if it does not exist yet. // We must then add the occluder to the occluders list of this cell. Cell* cell = getCell(coord); if (!cell) { cell = new Cell(boxmin); fillCell(coord, *cell); } cell->addOccluder(occluder); } } } else { // The polygon is not a triangle, we add all the cells overlapping the polygon bbox. for (z = imin[2]; z <= imax[2]; z++) for (y = imin[1]; y <= imax[1]; y++) for (x = imin[0]; x <= imax[0]; x++) { coord[0] = x; coord[1] = y; coord[2] = z; Cell* cell = getCell(coord); if (!cell) { Vec3r orig; getCellOrigin(coord, orig); cell = new Cell(orig); fillCell(coord, *cell); } cell->addOccluder(occluder); } } }