bool BVHAccel::IntersectQ(const Ray &ray, Intersection *isect, float* barycentrics) const { if (!nodes) return false; PBRT_BVH_INTERSECTION_STARTED(const_cast<BVHAccel *>(this), const_cast<Ray *>(&ray)); bool hit = false; //PbrtPoint origin = ray(ray.mint); Vector invDir(1.f / ray.d.x, 1.f / ray.d.y, 1.f / ray.d.z); uint32_t dirIsNeg[3] = { invDir.x < 0, invDir.y < 0, invDir.z < 0 }; // Follow ray through BVH nodes to find primitive intersections uint32_t todoOffset = 0, nodeNum = 0; uint32_t todo[64]; while (true) { const LinearBVHNode *node = &nodes[nodeNum]; // Check ray against BVH node if (::IntersectP(node->bounds, ray, invDir, dirIsNeg)) { if (node->nPrimitives > 0) { // Intersect ray with primitives in leaf BVH node PBRT_BVH_INTERSECTION_TRAVERSED_LEAF_NODE(const_cast<LinearBVHNode *>(node)); for (uint32_t i = 0; i < node->nPrimitives; ++i) { PBRT_BVH_INTERSECTION_PRIMITIVE_TEST(const_cast<Primitive *>(primitives[node->primitivesOffset+i].GetPtr())); if (primitives[node->primitivesOffset+i]->IntersectQ(ray, isect, barycentrics)) { PBRT_BVH_INTERSECTION_PRIMITIVE_HIT(const_cast<Primitive *>(primitives[node->primitivesOffset+i].GetPtr())); hit = true; } else { PBRT_BVH_INTERSECTION_PRIMITIVE_MISSED(const_cast<Primitive *>(primitives[node->primitivesOffset+i].GetPtr())); } } if (todoOffset == 0) break; nodeNum = todo[--todoOffset]; } else { // Put far BVH node on _todo_ stack, advance to near node PBRT_BVH_INTERSECTION_TRAVERSED_INTERIOR_NODE(const_cast<LinearBVHNode *>(node)); if (dirIsNeg[node->axis]) { todo[todoOffset++] = nodeNum + 1; nodeNum = node->secondChildOffset; } else { todo[todoOffset++] = node->secondChildOffset; nodeNum = nodeNum + 1; } } } else { if (todoOffset == 0) break; nodeNum = todo[--todoOffset]; } } PBRT_BVH_INTERSECTION_FINISHED(); if (hit) { //printf("\t BVH Intersect: thit=%f\n", ray.maxt); } return hit; }
int BAH::intersect(const ponos::Ray2 &ray, float *t) { UNUSED_VARIABLE(t); if (!nodes.size()) return false; ponos::Transform2 inv = ponos::inverse(mesh->getTransform()); ponos::Ray2 r = inv(ray); int hit = 0; ponos::vec2 invDir(1.f / r.d.x, 1.f / r.d.y); uint32_t dirIsNeg[2] = {invDir.x < 0, invDir.y < 0}; uint32_t todoOffset = 0, nodeNum = 0; uint32_t todo[64]; while (true) { LinearBAHNode *node = &nodes[nodeNum]; if (intersect(node->bounds, r, invDir, dirIsNeg)) { if (node->nElements > 0) { // intersect ray with primitives for (uint32_t i = 0; i < node->nElements; i++) { ponos::point2 v0 = mesh->getMesh() ->positionElement(orderedElements[node->elementsOffset + i], 0) .xy(); ponos::point2 v1 = mesh->getMesh() ->positionElement(orderedElements[node->elementsOffset + i], 1) .xy(); if (ponos::ray_segment_intersection(r, ponos::Segment2(v0, v1))) hit++; } if (todoOffset == 0) break; nodeNum = todo[--todoOffset]; } else { if (dirIsNeg[node->axis]) { todo[todoOffset++] = nodeNum + 1; nodeNum = node->secondChildOffset; } else { todo[todoOffset++] = node->secondChildOffset; nodeNum++; } } } else { if (todoOffset == 0) break; nodeNum = todo[--todoOffset]; } } return hit; }
bool BVHAccel::IntersectP(const Ray &ray) const { if (!nodes) return false; PBRT_BVH_INTERSECTIONP_STARTED(const_cast<BVHAccel *>(this), const_cast<Ray *>(&ray)); Vector invDir(1.f / ray.d.x, 1.f / ray.d.y, 1.f / ray.d.z); uint32_t dirIsNeg[3] = { invDir.x < 0, invDir.y < 0, invDir.z < 0 }; uint32_t todo[64]; uint32_t todoOffset = 0, nodeNum = 0; while (true) { const LinearBVHNode *node = &nodes[nodeNum]; if (::IntersectP(node->bounds, ray, invDir, dirIsNeg)) { // Process BVH node _node_ for traversal if (node->nPrimitives > 0) { PBRT_BVH_INTERSECTIONP_TRAVERSED_LEAF_NODE(const_cast<LinearBVHNode *>(node)); for (uint32_t i = 0; i < node->nPrimitives; ++i) { PBRT_BVH_INTERSECTIONP_PRIMITIVE_TEST(const_cast<Primitive *>(primitives[node->primitivesOffset + i].GetPtr())); if (primitives[node->primitivesOffset+i]->IntersectP(ray)) { PBRT_BVH_INTERSECTIONP_PRIMITIVE_HIT(const_cast<Primitive *>(primitives[node->primitivesOffset+i].GetPtr())); // printf("\t BVH Intersect P: thit=%f\n", ray.maxt); return true; } else { PBRT_BVH_INTERSECTIONP_PRIMITIVE_MISSED(const_cast<Primitive *>(primitives[node->primitivesOffset + i].GetPtr())); } } if (todoOffset == 0) break; nodeNum = todo[--todoOffset]; } else { PBRT_BVH_INTERSECTIONP_TRAVERSED_INTERIOR_NODE(const_cast<LinearBVHNode *>(node)); if (dirIsNeg[node->axis]) { /// second child first todo[todoOffset++] = nodeNum + 1; nodeNum = node->secondChildOffset; } else { todo[todoOffset++] = node->secondChildOffset; nodeNum = nodeNum + 1; } } } else { if (todoOffset == 0) break; nodeNum = todo[--todoOffset]; } } PBRT_BVH_INTERSECTIONP_FINISHED(); return false; }
void BVH::hit(Ray &ray, ShadeRec &sr) const { int numNodes = 0; int hitTests = 0; Vec3 invDir(1.0f/ray.m_dir[0], 1.0f/ray.m_dir[1], 1.0f/ray.m_dir[2]); bool dirIsNegative[] = {ray.m_dir[0] < 0.0f, ray.m_dir[1] < 0.0f, ray.m_dir[2] < 0.0f}; int todo[64]; int todoOffset = 0; int nodeNum = 0; while(true){ numNodes++; const BVHLinearNode *node = &m_root[nodeNum]; if(node->m_numTris > 0){ if(node->m_axis == 0){ for(int i=0;i<node->m_numTris;i++){ m_orderedTriangles[node->m_firstTriOffset + i]->hit(ray,sr); } } else{ for(int i=0;i<node->m_numTris;i++){ m_orderedInstances[node->m_firstTriOffset + i]->hit(ray,sr); } } hitTests++; if(todoOffset == 0) break; nodeNum = todo[--todoOffset]; } else{ if(node->m_bbox.hit(ray,invDir, dirIsNegative)){ if(dirIsNegative[node->m_axis]){ todo[todoOffset++] = nodeNum+1; nodeNum = node->m_secondChildOffset; } else{ nodeNum = nodeNum+1; todo[todoOffset++] = node->m_secondChildOffset; } } else{ if(todoOffset == 0) break; nodeNum = todo[--todoOffset]; } } } }
bool BVHAccel::Intersect(const Ray &ray, SurfaceInteraction *isect) const { if (!nodes) return false; ProfilePhase p(Prof::AccelIntersect); bool hit = false; Vector3f invDir(1 / ray.d.x, 1 / ray.d.y, 1 / ray.d.z); int dirIsNeg[3] = {invDir.x < 0, invDir.y < 0, invDir.z < 0}; // Follow ray through BVH nodes to find primitive intersections int toVisitOffset = 0, currentNodeIndex = 0; int nodesToVisit[64]; while (true) { const LinearBVHNode *node = &nodes[currentNodeIndex]; // Check ray against BVH node if (node->bounds.IntersectP(ray, invDir, dirIsNeg)) { if (node->nPrimitives > 0) { // Intersect ray with primitives in leaf BVH node for (int i = 0; i < node->nPrimitives; ++i) if (primitives[node->primitivesOffset + i]->Intersect( ray, isect)) hit = true; if (toVisitOffset == 0) break; currentNodeIndex = nodesToVisit[--toVisitOffset]; } else { // Put far BVH node on _nodesToVisit_ stack, advance to near // node if (dirIsNeg[node->axis]) { nodesToVisit[toVisitOffset++] = currentNodeIndex + 1; currentNodeIndex = node->secondChildOffset; } else { nodesToVisit[toVisitOffset++] = node->secondChildOffset; currentNodeIndex = currentNodeIndex + 1; } } } else { if (toVisitOffset == 0) break; currentNodeIndex = nodesToVisit[--toVisitOffset]; } } return hit; }
bool BVHAccel::IntersectP(const Ray &ray) const { if (!nodes) return false; ProfilePhase p(Prof::AccelIntersectP); Vector3f invDir(1.f / ray.d.x, 1.f / ray.d.y, 1.f / ray.d.z); int dirIsNeg[3] = {invDir.x < 0, invDir.y < 0, invDir.z < 0}; int nodesToVisit[64]; int toVisitOffset = 0, currentNodeIndex = 0; while (true) { const LinearBVHNode *node = &nodes[currentNodeIndex]; if (node->bounds.IntersectP(ray, invDir, dirIsNeg)) { // Process BVH node _node_ for traversal if (node->nPrimitives > 0) { for (int i = 0; i < node->nPrimitives; ++i) { if (primitives[node->primitivesOffset + i]->IntersectP( ray)) { return true; } } if (toVisitOffset == 0) break; currentNodeIndex = nodesToVisit[--toVisitOffset]; } else { if (dirIsNeg[node->axis]) { /// second child first nodesToVisit[toVisitOffset++] = currentNodeIndex + 1; currentNodeIndex = node->secondChildOffset; } else { nodesToVisit[toVisitOffset++] = node->secondChildOffset; currentNodeIndex = currentNodeIndex + 1; } } } else { if (toVisitOffset == 0) break; currentNodeIndex = nodesToVisit[--toVisitOffset]; } } return false; }
void GeomTree::TraceRay(const BVHNode *currnode, const vector3f &a_origin, const vector3f &a_dir, isect_t *isect) const { BVHNode *stack[32]; int stackpos = -1; vector3f invDir(1.0f/a_dir.x, 1.0f/a_dir.y, 1.0f/a_dir.z); for (;;) { while (!currnode->IsLeaf()) { if (!SlabsRayAabbTest(currnode, a_origin, invDir, isect)) goto pop_bstack; stackpos++; stack[stackpos] = currnode->kids[1]; currnode = currnode->kids[0]; } // triangle intersection j**z for (int i=0; i<currnode->numTris; i++) { RayTriIntersect(1, a_origin, &a_dir, currnode->triIndicesStart[i], isect); } pop_bstack: if (stackpos < 0) break; currnode = stack[stackpos]; stackpos--; } }
void CollisionSpace::TraceRay(const vector3d &start, const vector3d &dir, double len, CollisionContact *c, Geom *ignore) { vector3d invDir(1.0/dir.x, 1.0/dir.y, 1.0/dir.z); c->dist = len; BvhNode *vn_stack[16]; BvhNode *node = m_staticObjectTree->m_root; int stackPos = -1; for (;node;) { // do we hit it? { isect_t isect; isect.dist = float(c->dist); isect.triIdx = -1; if (!node->CollideRay(start, invDir, &isect)) goto pop_jizz; } if (node->geomStart) { // it is a leaf node // collide with all geoms for (int i=0; i<node->numGeoms; i++) { Geom *g = node->geomStart[i]; const matrix4x4d &invTrans = g->GetInvTransform(); vector3d ms = invTrans * start; vector3d md = invTrans.ApplyRotationOnly(dir); vector3f modelStart = vector3f(ms.x, ms.y, ms.z); vector3f modelDir = vector3f(md.x, md.y, md.z); isect_t isect; isect.dist = float(c->dist); isect.triIdx = -1; g->GetGeomTree()->TraceRay(modelStart, modelDir, &isect); if (isect.triIdx != -1) { c->pos = start + dir*double(isect.dist); vector3f n = g->GetGeomTree()->GetTriNormal(isect.triIdx); c->normal = vector3d(n.x, n.y, n.z); c->normal = g->GetTransform().ApplyRotationOnly(c->normal); c->depth = len - isect.dist; c->triIdx = isect.triIdx; c->userData1 = g->GetUserData(); c->userData2 = 0; c->geomFlag = g->GetGeomTree()->GetTriFlag(isect.triIdx); c->dist = isect.dist; } } } else if (node->kids[0]) { vn_stack[++stackPos] = node->kids[0]; node = node->kids[1]; continue; } pop_jizz: if (stackPos < 0) break; node = vn_stack[stackPos--]; } for (std::list<Geom*>::iterator i = m_geoms.begin(); i != m_geoms.end(); ++i) { if ((*i) == ignore) continue; if ((*i)->IsEnabled()) { const matrix4x4d &invTrans = (*i)->GetInvTransform(); vector3d ms = invTrans * start; vector3d md = invTrans.ApplyRotationOnly(dir); vector3f modelStart = vector3f(ms.x, ms.y, ms.z); vector3f modelDir = vector3f(md.x, md.y, md.z); isect_t isect; isect.dist = float(c->dist); isect.triIdx = -1; (*i)->GetGeomTree()->TraceRay(modelStart, modelDir, &isect); if (isect.triIdx != -1) { c->pos = start + dir*double(isect.dist); vector3f n = (*i)->GetGeomTree()->GetTriNormal(isect.triIdx); c->normal = vector3d(n.x, n.y, n.z); c->normal = (*i)->GetTransform().ApplyRotationOnly(c->normal); c->depth = len - isect.dist; c->triIdx = isect.triIdx; c->userData1 = (*i)->GetUserData(); c->userData2 = 0; c->geomFlag = (*i)->GetGeomTree()->GetTriFlag(isect.triIdx); c->dist = isect.dist; } } } { isect_t isect; isect.dist = float(c->dist); isect.triIdx = -1; CollideRaySphere(start, dir, &isect); if (isect.triIdx != -1) { c->pos = start + dir*double(isect.dist); c->normal = vector3d(0.0); c->depth = len - isect.dist; c->triIdx = -1; c->userData1 = sphere.userData; c->userData2 = 0; c->geomFlag = 0; } } }
bool EBVHAccel::IntersectP(const Ray &ray) const { if (!nodes) return false; PBRT_BVH_INTERSECTIONP_STARTED(const_cast<EBVHAccel *>(this), const_cast<Ray *>(&ray)); Vector invDir(1.f / ray.d.x, 1.f / ray.d.y, 1.f / ray.d.z); uint32_t dirIsNeg[3] = { invDir.x < 0, invDir.y < 0, invDir.z < 0 }; uint32_t todo[64]; uint32_t todoOffset = 0, nodeNum = 0; std::stack<BBox> stackOfBoxes; stackOfBoxes.push(this->sceneBoundingBox); while (true) { const LinearEBVHNode *node = &nodes[nodeNum]; BBox myBBox = uncompressBBox(BBox(Point(node->bounds_x0, node->bounds_y0, node->bounds_z0), Point(node->bounds_x1, node->bounds_y1, node->bounds_z1)), stackOfBoxes.top()); if (::IntersectP(myBBox, ray, invDir, dirIsNeg)) { // Process EBVH node _node_ for traversal if (node->nPrimitives > 0) { PBRT_BVH_INTERSECTIONP_TRAVERSED_LEAF_NODE(const_cast<LinearEBVHNode *>(node)); for (uint32_t i = 0; i < node->nPrimitives; ++i) { PBRT_BVH_INTERSECTIONP_PRIMITIVE_TEST(const_cast<Primitive *>(primitives[node->primitivesOffset + i].GetPtr())); if (primitives[node->primitivesOffset+i]->IntersectP(ray)) { PBRT_BVH_INTERSECTIONP_PRIMITIVE_HIT(const_cast<Primitive *>(primitives[node->primitivesOffset+i].GetPtr())); return true; } else { PBRT_BVH_INTERSECTIONP_PRIMITIVE_MISSED(const_cast<Primitive *>(primitives[node->primitivesOffset + i].GetPtr())); } } if (todoOffset == 0) break; todoOffset--; nodeNum = todo[todoOffset]; stackOfBoxes.pop(); } else { PBRT_BVH_INTERSECTIONP_TRAVERSED_INTERIOR_NODE(const_cast<LinearEBVHNode *>(node)); if (dirIsNeg[node->axis]) { /// second child first todo[todoOffset] = nodeNum + 1; nodeNum = node->secondChildOffset; todoOffset++; stackOfBoxes.pop(); stackOfBoxes.push(myBBox); stackOfBoxes.push(myBBox); } else { todo[todoOffset] = node->secondChildOffset; nodeNum = nodeNum + 1; todoOffset++; stackOfBoxes.pop(); stackOfBoxes.push(myBBox); stackOfBoxes.push(myBBox); } } } else { if (todoOffset == 0) break; todoOffset--; nodeNum = todo[todoOffset]; stackOfBoxes.pop(); } } PBRT_BVH_INTERSECTIONP_FINISHED(); return false; }
bool EBVHAccel::Intersect(const Ray &ray, Intersection *isect) const { if (!nodes) return false; PBRT_BVH_INTERSECTION_STARTED(const_cast<EBVHAccel *>(this), const_cast<Ray *>(&ray)); bool hit = false; Vector invDir(1.f / ray.d.x, 1.f / ray.d.y, 1.f / ray.d.z); uint32_t dirIsNeg[3] = { invDir.x < 0, invDir.y < 0, invDir.z < 0 }; // Follow ray through EBVH nodes to find primitive intersections uint32_t todoOffset = 0, nodeNum = 0; uint32_t todo[64]; std::stack<BBox> stackOfBoxes; stackOfBoxes.push(this->sceneBoundingBox); while (true) { LinearEBVHNode *node = &nodes[nodeNum]; BBox myBBox = uncompressBBox(BBox(Point(node->bounds_x0, node->bounds_y0, node->bounds_z0), Point(node->bounds_x1, node->bounds_y1, node->bounds_z1)), stackOfBoxes.top()); // Check ray against EBVH node if (::IntersectP(myBBox, ray, invDir, dirIsNeg)) { if (node->nPrimitives > 0) { // Intersect ray with primitives in leaf EBVH node PBRT_BVH_INTERSECTION_TRAVERSED_LEAF_NODE(const_cast<LinearEBVHNode *>(node)); for (uint32_t i = 0; i < node->nPrimitives; ++i) { PBRT_BVH_INTERSECTION_PRIMITIVE_TEST(const_cast<Primitive *>(primitives[node->primitivesOffset+i].GetPtr())); if (primitives[node->primitivesOffset+i]->Intersect(ray, isect)) { PBRT_BVH_INTERSECTION_PRIMITIVE_HIT(const_cast<Primitive *>(primitives[node->primitivesOffset+i].GetPtr())); hit = true; } else { PBRT_BVH_INTERSECTION_PRIMITIVE_MISSED(const_cast<Primitive *>(primitives[node->primitivesOffset+i].GetPtr())); } } if (todoOffset == 0) break; todoOffset--; nodeNum = todo[todoOffset]; stackOfBoxes.pop(); } else { // Put far EBVH node on _todo_ stack, advance to near node PBRT_BVH_INTERSECTION_TRAVERSED_INTERIOR_NODE(const_cast<LinearEBVHNode *>(node)); if (dirIsNeg[node->axis]) { todo[todoOffset] = nodeNum + 1; nodeNum = node->secondChildOffset; stackOfBoxes.pop(); stackOfBoxes.push(myBBox); stackOfBoxes.push(myBBox); todoOffset++; } else { todo[todoOffset] = node->secondChildOffset; nodeNum = nodeNum + 1; stackOfBoxes.pop(); stackOfBoxes.push(myBBox); stackOfBoxes.push(myBBox); todoOffset++; } } } else { if (todoOffset == 0) break; todoOffset--; nodeNum = todo[todoOffset]; stackOfBoxes.pop(); } } PBRT_BVH_INTERSECTION_FINISHED(); return hit; }
bool KdTreeAccel::IntersectP(const Ray &ray) const { // Compute initial parametric range of ray inside kd-tree extent float tmin, tmax; if (!bounds.IntersectP(ray, &tmin, &tmax)) return false; // Prepare to traverse kd-tree for ray int rayId = curMailboxId++; Vector invDir(1.f/ray.d.x, 1.f/ray.d.y, 1.f/ray.d.z); #define MAX_TODO 64 KdToDo todo[MAX_TODO]; int todoPos = 0; const KdAccelNode *node = &nodes[0]; while (node != NULL) { // Update kd-tree shadow ray traversal statistics //static StatsCounter nodesTraversed("Kd-Tree Accelerator", // "Number of kd-tree nodes traversed by shadow rays"); //++nodesTraversed; if (node->IsLeaf()) { // Check for shadow ray intersections inside leaf node u_int nPrimitives = node->nPrimitives(); if (nPrimitives == 1) { MailboxPrim *mp = node->onePrimitive; if (mp->lastMailboxId != rayId) { mp->lastMailboxId = rayId; if (mp->primitive->IntersectP(ray)) return true; } } else { MailboxPrim **prims = node->primitives; for (u_int i = 0; i < nPrimitives; ++i) { MailboxPrim *mp = prims[i]; if (mp->lastMailboxId != rayId) { mp->lastMailboxId = rayId; if (mp->primitive->IntersectP(ray)) return true; } } } // Grab next node to process from todo list if (todoPos > 0) { --todoPos; node = todo[todoPos].node; tmin = todo[todoPos].tmin; tmax = todo[todoPos].tmax; } else break; } else { // Process kd-tree interior node // Compute parametric distance along ray to split plane int axis = node->SplitAxis(); float tplane = (node->SplitPos() - ray.o[axis]) * invDir[axis]; // Get node children pointers for ray const KdAccelNode *firstChild, *secondChild; int belowFirst = (ray.o[axis] < node->SplitPos()) || (ray.o[axis] == node->SplitPos() && ray.d[axis] >= 0); if (belowFirst) { firstChild = node + 1; secondChild = &nodes[node->aboveChild]; } else { firstChild = &nodes[node->aboveChild]; secondChild = node + 1; } // Advance to next child node, possibly enqueue other child if (tplane > tmax || tplane <= 0) node = firstChild; else if (tplane < tmin) node = secondChild; else { // Enqueue _secondChild_ in todo list todo[todoPos].node = secondChild; todo[todoPos].tmin = tplane; todo[todoPos].tmax = tmax; ++todoPos; node = firstChild; tmax = tplane; } } } return false; }
bool KdTreeAccel::intersect(const Ray &inRay, DifferentialGeometry* queryPoint, const KdAccelNode* node, Float* tHit, Float* rayEpsilon) const { //Compute initial parametric range of ray inside kd-tree extent Float tmin, tmax, rayEp;//temprary DifferentialGeometry result if (!node->bbox.intersectP(inRay, &tmin, &tmax)) { return false; } //prepare to traversal kd-tree for ray Vector3f invDir(1.0 / inRay.d.x, 1.0 / inRay.d.y, 1.0 / inRay.d.z); //Traversal kd-tree node in order of ray bool isHit = false; if (node != nullptr) { //if hit outside the box, think it's used for later use if (inRay.tmax < tmin) { return isHit; } if (node->isLeaf()) { DifferentialGeometry* tmpQuery = new DifferentialGeometry(); Float hitDist; for (int i = 0; i < node->primIndex.size(); ++i) { int idx = node->primIndex[i]; if (primitives[idx]->intersectP(inRay)) { if (primitives[idx]->intersect(inRay, tmpQuery, &hitDist, &rayEp)) { if (hitDist < *tHit && inRange(hitDist, tmin, tmax)) { *queryPoint = *tmpQuery; *tHit = hitDist; *rayEpsilon = rayEp; queryPoint->shape = primitives[idx]; isHit = true; } } } } delete tmpQuery; } else//if hit interior node { /*process interior node*/ //calculate parametric distance from ray to split plane int axis = node->flags; Float tsplit = (node->split - inRay.o[axis]) * invDir[axis]; //get children node for ray const KdAccelNode* nearChild; const KdAccelNode* farChild; bool belowFisrt = ((inRay.o[axis] < node->split) || (inRay.o[axis] == node->split && inRay.d[axis] < 0)); if (belowFisrt) { nearChild = node->belowNode; farChild = node->aboveNode; } else { nearChild = node->aboveNode; farChild = node->belowNode; } if (tsplit > tmax || tsplit <= 0) { isHit = intersect(inRay, queryPoint, nearChild, tHit, rayEpsilon); } else if (tsplit < tmin) { isHit = intersect(inRay, queryPoint, farChild, tHit, rayEpsilon); } else { isHit = intersect(inRay, queryPoint, nearChild, tHit, rayEpsilon); if (!isHit) { isHit = intersect(inRay, queryPoint, farChild, tHit, rayEpsilon); } } // nearChild = nullptr; // farChild = nullptr; } } return isHit; }
bool KdTreeAccelerator::intersect(const Ray& ray, float *t, Intersection* pIntersection, Triangle::IsectMode isectMode) const { // compute initial parametric range of ray inside kd-tree extent float t_min = std::numeric_limits<float>::max(); float t_max = std::numeric_limits<float>::min(); float t_best = std::numeric_limits<float>::max(); Intersection isect_best; if(!m_boundingBox.intersect(ray, &t_min, &t_max)) return false; // prepare to traverse kd-tree for ray glm::vec3 invDir(1.f/ray.getDirection().x, 1.f/ray.getDirection().y, 1.f/ray.getDirection().z); KdToTraverse toTraverse[MAX_TO_TRAVERSE]; int toTraversePos = 0; // traverse kd-tree nodes in order for ray bool hit = false; const KdAccelNode* node = &m_nodes[0]; while(node != NULL) { // bail out if we found a hit closer than the current node if(t_best <= t_min) break; if(!node->isLeaf()) { // process kd-tree interior node // compute parametric distance along ray to split plane const int axis = node->getSplitAxis(); // get node children pointers for ray const KdAccelNode* firstChild; const KdAccelNode* secondChild; const int belowFirst = (ray.getOrigin()[axis] < node->getSplitPosition()) || (ray.getOrigin()[axis] == node->getSplitPosition() && ray.getDirection()[axis] >= 0); if(belowFirst) { firstChild = node + 1; secondChild = &m_nodes[node->aboveChild()]; } else { firstChild = &m_nodes[node->aboveChild()]; secondChild = node + 1; } // advance to next child node, possibly enqueue other child // t for which ray.getOrigin() + t * ray.getDirection() intersects the split plane float t_plane = (node->getSplitPosition() - ray.getOrigin()[axis]) * invDir[axis]; if(t_plane > t_max || t_plane <= 0) node = firstChild; else if(t_plane < t_min) node = secondChild; else { // enqueue second child in todo list toTraverse[toTraversePos].node = secondChild; toTraverse[toTraversePos].t_min = t_plane; toTraverse[toTraversePos].t_max = t_max; toTraversePos++; node = firstChild; t_max = t_plane; } } else { // check for intersection inside leaf node const uint numPrimitives = node->getNumPrimitives(); if(numPrimitives == 1) { Triangle const& primitive = m_primitives[node->m_onePrimitive]; float t_temp = 0.f; Intersection isect_temp; if(primitive.intersect(ray, &t_temp, &isect_temp, isectMode)) { if(t_temp < t_best && t_temp > 0.f) { t_best = t_temp; isect_best = isect_temp; hit = true; } } } else { uint* primitives = node->m_primitives; for(uint i = 0; i < node->getNumPrimitives(); ++i) { Triangle const& primitive = m_primitives[node->m_primitives[i]]; float t_temp = 0.f; Intersection isect_temp; if(primitive.intersect(ray, &t_temp, &isect_temp, isectMode)) { if(t_temp < t_best && t_temp > 0.f) { t_best = t_temp; isect_best = isect_temp; hit = true; } } } } // grab next node to process from toTraverse list if(toTraversePos > 0) { --toTraversePos; node = toTraverse[toTraversePos].node; t_min = toTraverse[toTraversePos].t_min; t_max = toTraverse[toTraversePos].t_max; } else break; } } *pIntersection = isect_best; *t = t_best; return hit; }
BVHItems BVH::intersect( const Ray &i_ray ) const { BVHItems hitItems; const vec3f &direction = i_ray.getDirection(); vec3f invDir( 1 / direction.x, 1 / direction.y, 1 / direction.z ); bool dirIsNeg[ 3 ] = { invDir.x < 0, invDir.y < 0, invDir.z < 0 }; if ( m_nodes.empty() ) { return hitItems; } size_t currentIndex = 0; size_t nodeToVisitOffset = 0; size_t nodesToVisit[ 64 ]; while ( 1 ) { const BVHNode &node = m_nodes[ currentIndex ]; const Bounds3f &bounds = node.getBounds(); if ( bounds.intersect( i_ray ) ) { size_t itemCount = node.getItemCount(); // Leaf node if ( itemCount > 0 ) { size_t start = node.getItemOffset(); size_t end = start + itemCount; for ( size_t i = start; i < end; i++ ) { hitItems.push_back( m_items[ i ] ); } if ( nodeToVisitOffset == 0 ) { break; } currentIndex = nodesToVisit[ --nodeToVisitOffset ]; } else { if ( dirIsNeg[ node.getSplitAxis() ] ) { nodesToVisit[ nodeToVisitOffset++ ] = currentIndex + 1; currentIndex = node.getSecondChildOffset(); } else { nodesToVisit[ nodeToVisitOffset++ ] = node.getSecondChildOffset(); currentIndex = currentIndex + 1; } } } else { if ( nodeToVisitOffset == 0 ) { break; } currentIndex = nodesToVisit[ --nodeToVisitOffset ]; } } return hitItems; }
TIntersection KDTree::IntersectP(Ray &a_Ray) { // Compute initial parametric range of ray inside kd-tree extent float tmin; TIntersection Intersect(-1,a_Ray.maxt); if (!bounds.IntersectP(a_Ray, &tmin, &a_Ray.maxt)) { return Intersect; } // Prepare to traverse kd-tree for ray Vector invDir(1.f/a_Ray.d.x, 1.f/a_Ray.d.y, 1.f/a_Ray.d.z); int TriangleID; TIntersection test; bool result = false; #define MAX_TODO 64 KdToDo todo[MAX_TODO]; int todoPos = 0; const KdNode *node = &nodes[0]; while (node != NULL) { if (node->IsLeaf()) { // Check for shadow ray intersections inside leaf node uint32_t nPrimitives = node->nPrimitives(); if (nPrimitives == 1) { const KDTreePrimitiveInfo &prim = primitives[node->onePrimitive]; //m_Candidates++; if (prim.bounds.IntersectP(a_Ray)){ TriangleID = prim.primitiveNumber; //candidates++; if (RayTriangleTest(a_Ray.o,a_Ray.d,test,TriangleID,m_pPrimitives) && test.t<Intersect.t) { Intersect.t = test.t; Intersect.u = test.u; Intersect.v = test.v; Intersect.IDTr = TriangleID; result = true; break; } } //break; } else { uint32_t *prims = node->primitives; bool tmp = false; for (uint32_t i = 0; i < nPrimitives; ++i) { const KDTreePrimitiveInfo &prim = primitives[prims[i]]; //m_Candidates++; if (prim.bounds.IntersectP(a_Ray)){ TriangleID = prim.primitiveNumber; //candidates++; if (RayTriangleTest(a_Ray.o,a_Ray.d,test,TriangleID,m_pPrimitives) && test.t<Intersect.t) { Intersect.t = test.t; Intersect.u = test.u; Intersect.v = test.v; Intersect.IDTr = TriangleID; result = true; tmp = true; } } } if(tmp) break; } // Grab next node to process from todo list if (todoPos > 0) { --todoPos; node = todo[todoPos].node; tmin = todo[todoPos].tmin; a_Ray.maxt = todo[todoPos].maxT; } else break; } else { // Process kd-tree interior node // Compute parametric distance along ray to split plane int axis = node->SplitAxis(); float tplane = (node->SplitPos() - a_Ray.o[axis]) * invDir[axis]; // Get node children pointers for ray const KdNode *firstChild, *secondChild; int belowFirst = (a_Ray.o[axis] < node->SplitPos()) || (a_Ray.o[axis] == node->SplitPos() && a_Ray.d[axis] >= 0); if (belowFirst) { firstChild = node + 1; secondChild = &nodes[node->AboveChild()]; } else { firstChild = &nodes[node->AboveChild()]; secondChild = node + 1; } // Advance to next child node, possibly enqueue other child if (tplane > a_Ray.maxt || tplane <= 0) node = firstChild; else if (tplane < tmin) node = secondChild; else { // Enqueue _secondChild_ in todo list todo[todoPos].node = secondChild; todo[todoPos].tmin = tplane; todo[todoPos].maxT = a_Ray.maxt; ++todoPos; node = firstChild; a_Ray.maxt = tplane; } } } return Intersect; }