#include "OgreOctreeHierarchyInterface.h" #include #include #include namespace Ogre { //----------------------------------------------------------------------- OctreeHierarchyInterface::OctreeHierarchyInterface(OctreeSceneManager *sm, RenderSystem *rsys): SceneNodeHierarchyInterface(sm, rsys) {} //----------------------------------------------------------------------- void OctreeHierarchyInterface::TraverseNode(GtpVisibility::HierarchyNode *node) { ++ mNumTraversedNodes; Octree *octree = static_cast(node); // if we come across some renderable geometry => render it if (!octree->mNodes.empty()) { RenderNode(node); } // if not all subtrees are empty if (!IsLeaf(node)) { Octree *nextChild; if ((nextChild = octree->mChildren[0][0][0]) != NULL) mDistanceQueue->push(nextChild); if ((nextChild = octree->mChildren[0][0][1]) != NULL) mDistanceQueue->push(nextChild); if ((nextChild = octree->mChildren[0][1][0]) != NULL) mDistanceQueue->push(nextChild); if ((nextChild = octree->mChildren[0][1][1]) != NULL) mDistanceQueue->push(nextChild); if ((nextChild = octree->mChildren[1][0][0]) != NULL) mDistanceQueue->push(nextChild); if ((nextChild = octree->mChildren[1][0][1]) != NULL) mDistanceQueue->push(nextChild); if ((nextChild = octree->mChildren[1][1][0]) != NULL) mDistanceQueue->push(nextChild); if ((nextChild = octree->mChildren[1][1][1]) != NULL) mDistanceQueue->push(nextChild); } } //----------------------------------------------------------------------- GtpVisibility::HierarchyNode *OctreeHierarchyInterface::GetRandomLeaf(GtpVisibility::HierarchyNode *root) { if (IsLeaf(root)) return root; Octree *octree = static_cast(root); // random decision Octree *child = NULL; std::vector nodes; nodes.reserve(8); for (int i = 0; i < 8; ++ i) { int x = (i & 4) / 4; int y = (i & 2) / 2; int z = i & 1; if ((child = octree->mChildren[x][y][z]) != NULL) { nodes.push_back(child); } } if (nodes.empty()) return NULL; int r = (int)(((float)rand() / RAND_MAX) * ((float)nodes.size() - 0.5f)); return GetRandomLeaf(nodes[r]); } //----------------------------------------------------------------------- bool OctreeHierarchyInterface::IsLeaf(GtpVisibility::HierarchyNode *node) const { Octree *octree = static_cast(node); // HACK: if there are subtrees, they are empty => we are not interested in them return octree->numNodes() == (int)octree->mNodes.size(); } //----------------------------------------------------------------------- bool OctreeHierarchyInterface::HasGeometry(GtpVisibility::HierarchyNode *node) const { return !(static_cast(node))->mNodes.empty(); } //----------------------------------------------------------------------- float OctreeHierarchyInterface::GetSquaredDistance(GtpVisibility::HierarchyNode *node) const { const Vector3 bmin = static_cast(node)->mBox.getMinimum(); const Vector3 bmax = static_cast(node)->mBox.getMaximum(); const Vector3 pos = (bmax - bmin) * 0.5f + bmin; return (mCameraPosition - pos).squaredLength(); } //----------------------------------------------------------------------- void OctreeHierarchyInterface::SetNodeVisible(GtpVisibility::HierarchyNode *node, const bool visible) const { #ifdef GTP_VISIBILITY_MODIFIED_OGRE static_cast(node)->setOctreeVisible(visible); #endif } //----------------------------------------------------------------------- void OctreeHierarchyInterface::SetLastVisited(GtpVisibility::HierarchyNode *node, const unsigned int frameId) const { #ifdef GTP_VISIBILITY_MODIFIED_OGRE static_cast(node)->setLastVisited(frameId); #endif } //----------------------------------------------------------------------- void OctreeHierarchyInterface::PullUpVisibility(GtpVisibility::HierarchyNode *node) const { #ifdef GTP_VISIBILITY_MODIFIED_OGRE Octree *octant = static_cast(node); while (octant && !octant->isOctreeVisible()) { octant->setOctreeVisible(true); octant = octant->getParent(); } #endif } //----------------------------------------------------------------------- /*void OctreeHierarchyInterface::PullUpFullVisibility(GtpVisibility::HierarchyNode *node) const { #ifdef GTP_VISIBILITY_MODIFIED_OGRE Octree *octant = static_cast(node); for (int i = 0; i < 8; ++ i) { int x = (i & 4) / 4; int y = (i & 2) / 2; int z = i & 1; if ((nextChild = octant->mChildren[x][y][z]) != NULL) { DetermineFullVisibility(nextChild); // this leaf is not fully visible => break if (!nextChild->isOctreeFullyVisible()) octant->setOctreeFullyVisible(false); } } while (octant && !octant->isOctreeVisible()) { octant->setOctreeVisible(true); octant = octant->getParent(); } #endif }*/ //----------------------------------------------------------------------- void OctreeHierarchyInterface::DetermineFullVisibility(GtpVisibility::HierarchyNode *node) const { Octree *octant = static_cast(node); // leaf node: terminate recursion if (IsLeaf(node)) { octant->setOctreeFullyVisible(octant->isOctreeVisible()); return; } octant->setOctreeFullyVisible(true); Octree *nextChild; for (int i = 0; i < 8; ++ i) { int x = (i & 4) / 4; int y = (i & 2) / 2; int z = i & 1; if ((nextChild = octant->mChildren[x][y][z]) != NULL) { DetermineFullVisibility(nextChild); // this leaf is not fully visible => break if (!nextChild->isOctreeFullyVisible()) octant->setOctreeFullyVisible(false); } } } //----------------------------------------------------------------------- void OctreeHierarchyInterface::RenderNode(GtpVisibility::HierarchyNode *node) { #ifdef GTP_VISIBILITY_MODIFIED_OGRE Octree *octant = static_cast(node); if (octant->lastRendered() != mFrameId) { octant->setLastRendered(mFrameId); OctreeSceneManager *ocm = static_cast(mSceneManager); ocm->_renderOctant(mCamera, octant, mOnlyShadowCasters, mLeavePassesInQueue); mVisibleNodes.push_back(node); } #endif } //----------------------------------------------------------------------- void OctreeHierarchyInterface::RenderNodeRecursive(GtpVisibility::HierarchyNode *node) { #ifdef GTP_VISIBILITY_MODIFIED_OGRE Octree *octant = static_cast(node); if (octant->lastRendered() != mFrameId) { octant->setLastRendered(mFrameId); OctreeSceneManager *ocm = static_cast(mSceneManager); ocm->_renderOctantRecursive(mCamera, octant, mOnlyShadowCasters, mLeavePassesInQueue); mVisibleNodes.push_back(node); } #endif } //----------------------------------------------------------------------- bool OctreeHierarchyInterface::IsNodeVisible(GtpVisibility::HierarchyNode *node) const { #ifdef GTP_VISIBILITY_MODIFIED_OGRE return static_cast(node)->isOctreeVisible(); #else return true; #endif } //----------------------------------------------------------------------- bool OctreeHierarchyInterface::IsNodeFullyVisible(GtpVisibility::HierarchyNode *node) const { #ifdef GTP_VISIBILITY_MODIFIED_OGRE return static_cast(node)->isOctreeFullyVisible(); #else return true; #endif } //----------------------------------------------------------------------- unsigned int OctreeHierarchyInterface::LastVisited(GtpVisibility::HierarchyNode *node) const { #ifdef GTP_VISIBILITY_MODIFIED_OGRE return static_cast(node)->lastVisited(); #else return 0; #endif } //----------------------------------------------------------------------- AxisAlignedBox *OctreeHierarchyInterface::GetBoundingBox(GtpVisibility::HierarchyNode *node) { // reuse box if node is the same // only create renderable bounding box for new node if (node != mSavedNode) { mSavedNode = node; //static_cast(node)->_getCullBounds(&mBox); mBox = static_cast(node)->_getWorldAABB(); } return &mBox; } //----------------------------------------------------------------------- void OctreeHierarchyInterface::VisualizeCulledNode(GtpVisibility::HierarchyNode *node, GtpVisibility::CullingType type) const { WireBoundingBox *box = static_cast(node)->getWireBoundingBox(); if (type == GtpVisibility::FRUSTUM_CULLED) { box->setMaterial("FrustumCulledNodesMaterial"); } else // type == GtpVisibility::QUERY_CULLED { box->setMaterial("QueryCulledNodesMaterial"); } static_cast(mSceneManager)->getBoxes()->push_back(box); } //----------------------------------------------------------------------- void OctreeHierarchyInterface::GetNodeGeometryList(GtpVisibility::HierarchyNode *node, GeometryVector *geometryList, bool includeChildren) { NodeList::const_iterator nodeIt, nodeIt_end; nodeIt_end = static_cast(node)->mNodes.end(); for (nodeIt = static_cast(node)->mNodes.begin(); nodeIt != nodeIt_end; ++nodeIt) { SceneNodeHierarchyInterface::GetNodeGeometryList(*nodeIt, geometryList, includeChildren); } } //----------------------------------------------------------------------- void OctreeHierarchyInterface::CollectLeaves(GtpVisibility::HierarchyNode *root, GtpVisibility::HierarchyNodeContainer &nodes) { std::stack tStack; tStack.push(root); Octree *child; while (!tStack.empty()) { GtpVisibility::HierarchyNode *node = tStack.top(); tStack.pop(); if (IsLeaf(node)) { nodes.push_back(node); } else { Octree *octree = static_cast(node); for (int i = 0; i < 8; ++ i) { int x = (i & 4) / 4; int y = (i & 2) / 2; int z = i & 1; if ((child = octree->mChildren[x][y][z]) != NULL) { tStack.push(child); } } } } } } // namespace Ogre