#ifndef _PlatformBoundingBoxConverter_H__ #define _PlatformBoundingBoxConverter_H__ #include "OgreAxisAlignedBox.h" #include "AxisAlignedBox3.h" #include "Vector3.h" #include "BoundingBoxConverter.h" #include "Containers.h" #include "IntersectableWrapper.h" namespace Ogre { #define USE_KD_PVS 1 class Entity; class OctreeSceneManager; class KdTreeSceneManager; class BvHierarchySceneManager; typedef vector EntityContainer; class EngineIntersectable: public GtpVisibilityPreprocessor::IntersectableWrapper { public: EngineIntersectable(EntityContainer *item): GtpVisibilityPreprocessor::IntersectableWrapper(item) {} // hack EngineIntersectable::~EngineIntersectable() { delete mItem; } int Type() const { return Intersectable::ENGINE_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; /// this can be any scene manager 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 // note: this function must be provided by scene manager 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 != sit_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; } #define ENLARGE_OBJECT_BBOX 0 #define ENLRAGE_NODE_BBOX 0 template void PlatFormBoundingBoxConverter::FindIntersectingObjects(const AxisAlignedBox &box, EntityContainer &objects) const { list sceneNodeList; // find intersecting scene nodes to get candidates for intersection // note: this function has to be provided by scene manager #if ENLARGE_NODE_BBOX // make search radius larger AxisAlignedBox largebox = EnlargeBox(box); mSceneMgr->findNodesIn(largebox, sceneNodeList, NULL); list::const_iterator sit, sit_end = sceneNodeList.end(); GtpVisibilityPreprocessor::AxisAlignedBox3 nodeBox = OgreTypeConverter::ConvertFromOgre(largebox); #else mSceneMgr->findNodesIn(box, sceneNodeList, NULL); list::const_iterator sit, sit_end = sceneNodeList.end(); GtpVisibilityPreprocessor::AxisAlignedBox3 nodeBox = OgreTypeConverter::ConvertFromOgre(box); #endif // loop through the intersected scene nodes for (sit = sceneNodeList.begin(); sit != sceneNodeList.end(); ++ sit) { SceneNode *sn = *sit; SceneNode::ObjectIterator oit = sn->getAttachedObjectIterator(); // find the objects that intersect the box while (oit.hasMoreElements()) { MovableObject *mo = oit.getNext(); // we are only interested in scene entities if (mo->getMovableType() != "Entity") continue; // get the bounding box of the objects #if ENLARGE_OBJECT_BBOX // compare with enlarged entitiy box const AxisAlignedBox bbox = EnlargeBox(mo->getWorldBoundingBox()); #else const AxisAlignedBox bbox = mo->getWorldBoundingBox(); #endif // test for intersection (note: function provided of preprocessor) if (Overlap(nodeBox, OgreTypeConverter::ConvertFromOgre(bbox))) { objects.push_back(static_cast(mo)); } } } } #if USE_KD_PVS //------------------------------------------------------------------------- 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 pbox = (*iit).second; const int id = (*iit).first; const AxisAlignedBox box = OgreTypeConverter::ConvertToOgre(pbox); EntityContainer entryObjects; // find all objects that intersect the bounding box FindIntersectingObjects(box, entryObjects); // TODO: can actually just put single objects into pvs with same id, // this can be sorted out later!! #if 1 EntityContainer::const_iterator eit, eit_end = entryObjects.end(); for (eit = entryObjects.begin(); eit != eit_end; ++ eit) { Entity *ent = *eit; // warning: multiple ids possible OgreMeshInstance *omi = new OgreMeshInstance(ent); omi->SetId(id); objects.push_back(omi); } #else EngineIntersectable *entry = new EngineIntersectable(entryObjects); entry->SetId(id); objects.push_back(entry); #endif } 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) continue; // 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