#include "OgreOcclusionQueriesQueryManager.h" #include #include #include namespace Ogre { //----------------------------------------------------------------------- OcclusionQueriesQueryManager::OcclusionQueriesQueryManager(PlatformHierarchyInterface *hierarchyInterface, Viewport *vp): PlatformQueryManager(hierarchyInterface, vp) { } //----------------------------------------------------------------------- bool OcclusionQueriesQueryManager::ShootRay(const Ray &ray, std::vector *visibleMeshes, bool isGlobalLine) { // run OGRE ray shooting query return false; } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::ComputeCameraVisibility(const Camera &camera, InfoContainer *visibleNodes, InfoContainer *visibleGeometry, bool relativeVisibility) { // we need access to the scene manager and the rendersystem PlatformHierarchyInterface *pfHierarchyInterface = dynamic_cast(mHierarchyInterface); //-- Render scene to get conservative visibility and fill depth buffer // const_cast allowed because camera is not changed in renderScene Camera *pCam = const_cast(&camera); // disable overlays, reset them later bool overlayEnabled = mViewport->getOverlaysEnabled(); mViewport->setOverlaysEnabled(false); //-- render the scene once to update depth buffer pfHierarchyInterface->GetSceneManager()->_renderScene(pCam, mViewport, false); /* Two query lists for projected pixels and for visibile pixels: We test queries after a rendering pass to get exact visibility with regard to the current camera. We issue all queries at once to avoid starvation & stalls. */ GtpVisibility::QueryList queryList[2]; // get rendered hierarchy nodes GtpVisibility::HierarchyNodeList *nodeList = mHierarchyInterface->GetRenderedNodes(); // vector for storing entities of meshes GtpVisibility::GeometryList geometryList; GtpVisibility::HierarchyNodeList::iterator nodeIt, nodeIt_end = nodeList->end(); // geometry list has still do be built GtpVisibility::GeometryList::iterator geometryIt, geometryIt_end; // to obtain the correct number of projected pixels, depth write must be disabled bool enableDepthWrite = false; // this option must be provided by the scene manager pfHierarchyInterface->GetSceneManager()->setOption("DepthWrite", &enableDepthWrite); /* relative visiblity: 1) get visible pixels count of objects 2) clear frame buffer 3) get projected visible pixels count: test all objects again without depth write (set as option in scene manager) 4) calculate ratio between visible vs. projected pixels */ // for relative visibility we need 2 rendering passes int n = relativeVisibility ? 2 : 1; for (int i=0; ibegin(); nodeIt != nodeIt_end; ++nodeIt) { // TODO: DELETE QUERIES FROM PREVIOUS RENDER queryList[i].push_back(mHierarchyInterface->IssueOcclusionQuery(*nodeIt, false)); // store geometry of the hierarchy node in a geometry list (only once!) if (i == 0) { mHierarchyInterface->GetNodeGeometryList(*nodeIt, &geometryList, false); } } geometryIt_end = geometryList.end(); //-- add queries for geometry for (geometryIt = geometryList.begin(); geometryIt != geometryIt_end; ++geometryIt) { queryList[i].push_back(mHierarchyInterface->IssueOcclusionQuery(*geometryIt)); } pfHierarchyInterface->GetRenderSystem()->clearFrameBuffer(FBT_DEPTH); } enableDepthWrite = true; // this option must be provided by the scene manager pfHierarchyInterface->GetSceneManager()->setOption("DepthWrite", &enableDepthWrite); // reset old overlay status mViewport->setOverlaysEnabled(overlayEnabled); // ---- collect results GtpVisibility::QueryList::iterator visQueryIt, projQueryIt; visQueryIt = queryList[0].begin(); projQueryIt = queryList[1].begin(); for (nodeIt = nodeList->begin(); nodeIt != nodeIt_end; ++nodeIt) { unsigned int visiblePixels = 0; (*visQueryIt)->GetQueryResult(visiblePixels, true); unsigned int projectedPixels = 0; if (relativeVisibility) { (*projQueryIt)->GetQueryResult(projectedPixels, true); ++projQueryIt; } ++visQueryIt; // node with visibilty 0 in queue (e.g., if node is intersected by near plane) if (visiblePixels > 0) { visibleNodes->push_back(GtpVisibility::NodeInfo(*nodeIt, visiblePixels, projectedPixels)); } } // ---- queries for geometry geometryIt_end = geometryList.end(); for (geometryIt = geometryList.begin(); geometryIt != geometryIt_end; ++geometryIt) { unsigned int visiblePixels = 0; (*visQueryIt)->GetQueryResult(visiblePixels, true); unsigned int projectedPixels = 0; if (relativeVisibility) { (*projQueryIt)->GetQueryResult(projectedPixels, true); ++projQueryIt; } ++visQueryIt; // WARNING: approximate depth ordering during rendering => // geometry maybe occluded if (visiblePixels > 0) { visibleGeometry->push_back(GtpVisibility::MeshInfo(*geometryIt, visiblePixels, projectedPixels)); } } } //----------------------------------------------------------------------- inline bool nodeinfo_eq(const GtpVisibility::NodeInfo &info1, const GtpVisibility::NodeInfo &info2) { return info1.GetNode() == info2.GetNode(); } //----------------------------------------------------------------------- inline bool meshinfo_eq(const GtpVisibility::MeshInfo &info1, const GtpVisibility::MeshInfo &info2) { return info1.GetMesh() == info2.GetMesh(); } //----------------------------------------------------------------------- inline bool nodeinfo_lower(const GtpVisibility::NodeInfo &info1, const GtpVisibility::NodeInfo &info2) { return info1.GetNode() < info2.GetNode(); } //----------------------------------------------------------------------- inline bool meshinfo_lower(const GtpVisibility::MeshInfo &info1, const GtpVisibility::MeshInfo &info2) { return info1.GetMesh() < info2.GetMesh(); } //----------------------------------------------------------------------- void OcclusionQueriesQueryManager::ComputeFromPointVisibility(const Vector3 &point, InfoContainer *visibleNodes, InfoContainer *visibleGeometry, bool relativeVisibility) { PlatformQueryManager::ComputeFromPointVisibility(point, visibleNodes, visibleGeometry, relativeVisibility); // --- remove duplicates (duplicates occur if an object is on the edge of the viewport) // before duplicates can be deleted we have to add up their visibility // --- visible nodes sort(visibleNodes->begin(), visibleNodes->end(), nodeinfo_lower); InfoContainer::iterator visibleNodesIt, visibleNodesIt_end = visibleNodes->end(); GtpVisibility::NodeInfo *nodeInfo = NULL; for (visibleNodesIt = visibleNodes->begin(); visibleNodesIt != visibleNodesIt_end; ++visibleNodesIt) { if (!nodeInfo || (nodeInfo->GetNode() != (*visibleNodesIt).GetNode())) { nodeInfo = &(*visibleNodesIt); } else // add visibility { nodeInfo->AddVisibility(*visibleNodesIt); } } // physically delete duplicates visibleNodes->erase( std::unique(visibleNodes->begin(), visibleNodes->end(), nodeinfo_eq), visibleNodes->end()); // --- visible geometry sort(visibleGeometry->begin(), visibleGeometry->end(), meshinfo_lower); InfoContainer::iterator visibleGeomIt, visibleGeomIt_end = visibleGeometry->end(); GtpVisibility::MeshInfo *geomInfo = NULL; int i=0; for (visibleGeomIt = visibleGeometry->begin(); visibleGeomIt != visibleGeomIt_end; ++visibleGeomIt) { if (!geomInfo || (geomInfo->GetMesh() != (*visibleGeomIt).GetMesh())) { geomInfo = &(*visibleGeomIt); } else // info points to same mesh, just add visibility { geomInfo->AddVisibility(*visibleGeomIt); } } // physically delete duplicates visibleGeometry->erase(std::unique(visibleGeometry->begin(), visibleGeometry->end(), meshinfo_eq), visibleGeometry->end()); } } // namespace Ogre