#include #include #include "ObjectPvs.h" #include "Intersectable.h" #include "IntersectableWrapper.h" #include "KdTree.h" #include "common.h" #include "BvHierarchy.h" using namespace std; namespace GtpVisibilityPreprocessor { /** the pvs is the number of different objects in the node leaves We eliminate already accounted kd nodes and objects using mailboxing. */ static int EvalKdNodeContribution(KdIntersectable *kdobj) { int pvs = 0; stack tStack; tStack.push(kdobj->GetItem()); while (!tStack.empty()) { KdNode *node = tStack.top(); tStack.pop(); // already processed node (=> objects already in pvs)? if (!node->Mailed()) { node->Mail(); if (node->IsLeaf()) { KdLeaf *leaf = static_cast(node); // add #objects exclusivly in this node pvs += (int)(leaf->mObjects.size() - leaf->mMultipleObjects.size()); // Objects already accounted for can only be found among those // which are referenced in more than one leaf ObjectContainer::const_iterator oit, oit_end = leaf->mMultipleObjects.end(); for (oit = leaf->mMultipleObjects.begin(); oit != oit_end; ++ oit) { Intersectable *object = *oit; if (!object->Mailed()) { object->Mail(); ++ pvs; } } } else // traverse tree { KdInterior *interior = static_cast(node); tStack.push(interior->mFront); tStack.push(interior->mBack); } } } return pvs; } /** Returns the the number of new (unmailed) objects in the leaves of the node. We eliminate already accounted bvh nodes and objects using mailboxing. */ static float EvalBvhNodeContribution(BvhNode *bvhObj) { BvhNode *node; // hack for choosing which node to account for if (bvhObj->IsLeaf()) node = static_cast(bvhObj)->GetActiveNode(); else node = bvhObj; // early exit if (node->IsLeaf()) { BvhLeaf *leaf = static_cast(node); // objects already accounted for if (leaf->Mailed()) return 0; leaf->Mail(); return BvHierarchy::EvalAbsCost(leaf->mObjects); } // compute leaf pvs float pvs = 0; stack tStack; tStack.push(node); while (!tStack.empty()) { node = tStack.top(); tStack.pop(); // already processed node (=> objects already in pvs)? if (!node->Mailed()) { node->Mail(); if (node->IsLeaf()) { BvhLeaf *leaf = static_cast(node); // add #objects exclusivly in this node pvs += BvHierarchy::EvalAbsCost(leaf->mObjects); } else // traverse tree { BvhInterior *interior = static_cast(node); tStack.push(interior->GetFront()); tStack.push(interior->GetBack()); } } } return pvs; } float ObjectPvs::EvalPvsCost() const { float pvs = 0; Intersectable::NewMail(); KdLeaf::NewMail(); ObjectPvsIterator pit = GetIterator(); while (pit.HasMoreEntries()) { Intersectable *obj = pit.Next(); switch (obj->Type()) { case Intersectable::KD_INTERSECTABLE: { // found kd node KdIntersectable *kdObj = static_cast(obj); pvs += EvalKdNodeContribution(kdObj); break; } case Intersectable::BVH_INTERSECTABLE: { BvhNode *bvhObj = static_cast(obj); pvs += EvalBvhNodeContribution(bvhObj); break; } default: // hack: should use assigned cost here ++ pvs; break; } } return pvs; } }