void PhotonAccelerator::build(const std::vector<Hitpoint*>& hitpoints) { hps = hitpoints; nodes.reserve(2 * hitpoints.size() - 1); BVHNode root; AABB& world_box = root.getAABB(); std::for_each(hps.begin(), hps.end(), [&] (Hitpoint* hp) { AABB aabb(hp->is.mPosition); aabb.grow(hp->radius); world_box.include(aabb); }); nodes.push_back(root); build_recursive(0, hps.size(), &nodes[0], 0); }
void PhotonAccelerator::accumulate(const Intersection& is, Color flux) { BVHNode* currentNode = &nodes[0]; AABB& box = currentNode->getAABB(); Point3D point = is.mPosition; if (!box.inside(point)) return; std::stack<BVHNode> intersect_stack; while (true) { if (currentNode->isLeaf()) { Vector3D v(point); for (unsigned int i = currentNode->getIndex(); i < currentNode->getIndex() + currentNode->getNObjs(); ++i) { Hitpoint& hp = *hps[i]; if ((v - hp.is.mPosition).length() <= hp.radius && hp.is.mNormal * is.mNormal >= 0) { hp.newPhotonCount += 1; hp.totalFlux += flux * hp.is.mMaterial->evalBRDF(hp.is, -is.mRay.dir); } } } else { BVHNode& left_node = nodes[currentNode->getIndex()]; BVHNode& right_node = nodes[currentNode->getIndex() + 1]; AABB& left_box = left_node.getAABB(); AABB& right_box = right_node.getAABB(); bool leftHit, rightHit; leftHit = left_box.inside(point); rightHit = right_box.inside(point); if (leftHit && rightHit) { currentNode = &left_node; intersect_stack.push(right_node); continue; } else if (leftHit) { currentNode = &left_node; continue; } else if (rightHit) { currentNode = &right_node; continue; } } if (intersect_stack.empty()) return; currentNode = &intersect_stack.top(); intersect_stack.pop(); } }