#ifndef _PlatFormBoundingBoxConverter_H__ #define _PlatFormBoundingBoxConverter_H__ #include "OgreAxisAlignedBox.h" #include "AxisAlignedBox3.h" #include "Vector3.h" #include "BoundingBoxConverter.h" #include "Containers.h" #include "IntersectableWrapper.h" //#include "KdTree.h" namespace Ogre { #define USE_KD_PVS 1 class Entity; class OctreeSceneManager; class KdTreeSceneManager; class BvHierarchySceneManager; typedef vector EntityContainer; class ObjectsIntersectable: public GtpVisibilityPreprocessor::IntersectableWrapper { public: ObjectsIntersectable(EntityContainer *item): GtpVisibilityPreprocessor::IntersectableWrapper(item) {} // hack ObjectsIntersectable::~ObjectsIntersectable() { //CLEAR_CONTAINER(*mItem); delete mItem; } int Type() const { return Intersectable::OBJECTS_INTERSECTABLE; } }; /** Class which converts preprocessor types to OGRE types */ template class __declspec(dllexport) PlatFormBoundingBoxConverter: public GtpVisibilityPreprocessor::BoundingBoxConverter { public: PlatFormBoundingBoxConverter(T *sm); bool IdentifyObjects(const GtpVisibilityPreprocessor::IndexedBoundingBoxContainer &iboxes, GtpVisibilityPreprocessor::ObjectContainer &objects) const; protected: //------------------------------------------------------------------------- inline static AxisAlignedBox EnlargeBox(const AxisAlignedBox &box) { const float eps = 1e-3f; const Vector3 veps(eps, eps, eps); Vector3 max = box.getMaximum(); Vector3 min = box.getMinimum(); return AxisAlignedBox(min - veps, max + veps); } //------------------------------------------------------------------------- inline static AxisAlignedBox ScaleBox(const AxisAlignedBox &box) { const float scale = 1.5f; Vector3 max = box.getMaximum(); Vector3 min = box.getMinimum(); Vector3 size = max - min; Vector3 newSize = size*(scale*0.5f); Vector3 center = 0.5f * (min + max); Vector3 min = center - newSize; Vector3 max = center + newSize; return AxisAlignedBox(min, max); } /** find object which fits best to this bounding box */ Entity *FindBestFittingObject(const AxisAlignedBox &box) const; /** find objects which are intersected by this box */ void FindIntersectingObjects(const AxisAlignedBox &box, vector &objects) const; T *mSceneMgr; }; //------------------------------------------------------------------------- template PlatFormBoundingBoxConverter::PlatFormBoundingBoxConverter(T *sm): mSceneMgr(sm) { } //----------------------------------------------------------------------- template Entity *PlatFormBoundingBoxConverter::FindBestFittingObject(const AxisAlignedBox &box) const { list sceneNodeList; AxisAlignedBox3 enlargedBox = AxisAlignedBox mybox = EnlargeBox(box); // get intersecting scene nodes mSceneMgr->findNodesIn(mybox, sceneNodeList, NULL); // minimal overlap float overlap = 0;//1e-6; Entity *bestFittingObj = NULL; float bestFit = overlap; // perfect fit threshold const float thresh = 1.0 - GtpVisibilityPreprocessor::Limits::Small; list::const_iterator sit, sit_end = sceneNodeList.end(); // find the bbox which is closest to the current bbox for (sit = sceneNodeList.begin(); sit != sceneNodeList.end(); ++ sit) { SceneNode *sn = *sit; SceneNode::ObjectIterator oit = sn->getAttachedObjectIterator(); while (oit.hasMoreElements()) { MovableObject *mo = oit.getNext(); // we are only interested in scene entities if (mo->getMovableType() != "Entity") { continue; } const AxisAlignedBox bbox = EnlargeBox(mo->getWorldBoundingBox()); // compute measure how much aabbs overlap overlap = RatioOfOverlap(OgreTypeConverter::ConvertFromOgre(mybox), OgreTypeConverter::ConvertFromOgre(bbox)); if (overlap > bestFit) { bestFit = overlap; bestFittingObj = static_cast(mo); // perfect fit => object found, early exit if (overlap >= thresh) { return bestFittingObj; } } } } if (0) { std::stringstream d; if (bestFittingObj) d << "best fit: " << bestFit; else d << "warning, no best fitting object\n" << box; Ogre::LogManager::getSingleton().logMessage(d.str()); } return bestFittingObj; } //----------------------------------------------------------------------- /*template void PlatFormBoundingBoxConverter::FindIntersectingObjects(const AxisAlignedBox &box, EntityContainer &objects) const {//return; list sceneNodeList; // get intersecting scene nodes (= candidates) AxisAlignedBox mybox = EnlargeBox(box); mSceneMgr->findNodesIn(mybox, sceneNodeList, NULL); //mSceneMgr->findNodesIn(box, sceneNodeList, NULL); list::const_iterator sit, sit_end = sceneNodeList.end(); GtpVisibilityPreprocessor::AxisAlignedBox3 nodeBox = OgreTypeConverter::ConvertFromOgre(mybox); //GtpVisibilityPreprocessor::AxisAlignedBox3 nodeBox = OgreTypeConverter::ConvertFromOgre(box); // find really intersecting objects for (sit = sceneNodeList.begin(); sit != sceneNodeList.end(); ++ sit) { SceneNode *sn = *sit; SceneNode::ObjectIterator oit = sn->getAttachedObjectIterator(); while (oit.hasMoreElements()) { MovableObject *mo = oit.getNext(); // we are only interested in scene entities if (mo->getMovableType() != "Entity") { continue; } //const AxisAlignedBox bbox = EnlargeBox(mo->getWorldBoundingBox()); const AxisAlignedBox bbox = mo->getWorldBoundingBox(); const bool overlaps = Overlap(nodeBox, OgreTypeConverter::ConvertFromOgre(bbox) ); //,0.00001); if (overlaps) { objects.push_back(static_cast(mo)); } } } } */ template void PlatFormBoundingBoxConverter::FindIntersectingObjects(const AxisAlignedBox &box, EntityContainer &objects) const {//return; list sceneNodeList; // get intersecting scene nodes (= candidates) //AxisAlignedBox mybox = EnlargeBox(box); //mSceneMgr->findNodesIn(mybox, sceneNodeList, NULL); mSceneMgr->findNodesIn(box, sceneNodeList, NULL); list::const_iterator sit, sit_end = sceneNodeList.end(); //GtpVisibilityPreprocessor::AxisAlignedBox3 nodeBox = OgreTypeConverter::ConvertFromOgre(mybox); GtpVisibilityPreprocessor::AxisAlignedBox3 nodeBox = OgreTypeConverter::ConvertFromOgre(box); // find really intersecting objects for (sit = sceneNodeList.begin(); sit != sceneNodeList.end(); ++ sit) { SceneNode *sn = *sit; SceneNode::ObjectIterator oit = sn->getAttachedObjectIterator(); while (oit.hasMoreElements()) { MovableObject *mo = oit.getNext(); // we are only interested in scene entities if (mo->getMovableType() != "Entity") { continue; } //const AxisAlignedBox bbox = EnlargeBox(mo->getWorldBoundingBox()); const AxisAlignedBox bbox = mo->getWorldBoundingBox(); const bool overlaps = Overlap(nodeBox, OgreTypeConverter::ConvertFromOgre(bbox)); if (overlaps) { objects.push_back(static_cast(mo)); } } } } #if USE_KD_PVS //------------------------------------------------------------------------- template bool PlatFormBoundingBoxConverter::IdentifyObjects( const GtpVisibilityPreprocessor::IndexedBoundingBoxContainer &iboxes, GtpVisibilityPreprocessor::ObjectContainer &objects) const { //Ogre::LogManager().logMessage("pvs: intersecting objects"); const long startTime = GtpVisibilityPreprocessor::GetTime(); GtpVisibilityPreprocessor::IndexedBoundingBoxContainer:: const_iterator iit, iit_end = iboxes.end(); int i = 0; for (iit = iboxes.begin(); iit != iit_end; ++ iit, ++ i) { if (0 && ((i % 1000) == 0)) { std::stringstream d; d << "found " << i << " objects"; Ogre::LogManager().getSingleton().logMessage(d.str()); } const AxisAlignedBox box = OgreTypeConverter::ConvertToOgre((*iit).second); //GtpVisibilityPreprocessor::ObjectContainer *entryObjects = new EntityContainer(); EntityContainer *entryObjects = new EntityContainer(); // find all objects that intersect the bounding box FindIntersectingObjects(box, *entryObjects); /*vector::const_iterator mit, mit_end = sceneObjects.end(); for (mit = sceneObjects.begin(); mit != mit_end; ++ mit) { Entity *ent = *mit; // create new mesh instance OgreMeshInstance *omi = new OgreGetOrCreateOgreMeshInstance(ent); //omi->SetId((*iit).first); entryObjects->push_back(omi); }*/ ObjectsIntersectable *entry = new ObjectsIntersectable(entryObjects); entry->SetId((*iit).first); //kdObj->mBbox = (*iit).second; objects.push_back(entry); } //std::stringstream d; d << "finished object intersection in " << GtpVisibilityPreprocessor::TimeDiff(startTime, GtpVisibilityPreprocessor::GetTime()) * 1e-3 << "secs"; //Ogre::LogManager().logMessage(d.str()); return true; } #else //------------------------------------------------------------------------- template bool PlatFormBoundingBoxConverter::IdentifyObjects( const GtpVisibilityPreprocessor::IndexedBoundingBoxContainer &iboxes, GtpVisibilityPreprocessor::ObjectContainer &objects) const { GtpVisibilityPreprocessor::IndexedBoundingBoxContainer:: const_iterator iit, iit_end = iboxes.end(); for (iit = iboxes.begin(); iit != iit_end; ++ iit) { const GtpVisibilityPreprocessor::AxisAlignedBox3 box = (*iit).second; const AxisAlignedBox currentBox = OgreTypeConverter::ConvertToOgre(box); Entity *ent = FindBestFittingObject(currentBox); if (ent) { // create new mesh instance OgreMeshInstance *omi = new OgreMeshInstance(ent); omi->SetId((*iit).first); objects.push_back(omi); } } return true; } #endif typedef PlatFormBoundingBoxConverter OctreeBoundingBoxConverter; typedef PlatFormBoundingBoxConverter BvhBoundingBoxConverter; typedef PlatFormBoundingBoxConverter KdTreeBoundingBoxConverter; } // namespace Ogre #endif // PlatFormBoundingBoxConverter