#include "occlusionquery.hpp" #include #include #include using namespace MWRender; using namespace Ogre; OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNode* sunNode) : mSunTotalAreaQuery(0), mSunVisibleAreaQuery(0), mActiveQuery(0), mDoQuery(0), mSunVisibility(0) { mRendering = renderer; mSunNode = sunNode; try { RenderSystem* renderSystem = Root::getSingleton().getRenderSystem(); mSunTotalAreaQuery = renderSystem->createHardwareOcclusionQuery(); mSunVisibleAreaQuery = renderSystem->createHardwareOcclusionQuery(); mSupported = (mSunTotalAreaQuery != 0) && (mSunVisibleAreaQuery != 0); } catch (Ogre::Exception e) { mSupported = false; } if (!mSupported) { std::cout << "Hardware occlusion queries not supported." << std::endl; return; } // This means that everything up to RENDER_QUEUE_MAIN can occlude the objects that are tested const int queue = RENDER_QUEUE_MAIN+1; MaterialPtr matBase = MaterialManager::getSingleton().getByName("BaseWhiteNoLighting"); MaterialPtr matQueryArea = matBase->clone("QueryTotalPixels"); matQueryArea->setDepthWriteEnabled(false); matQueryArea->setColourWriteEnabled(false); matQueryArea->setDepthCheckEnabled(false); // Not occluded by objects MaterialPtr matQueryVisible = matBase->clone("QueryVisiblePixels"); matQueryVisible->setDepthWriteEnabled(false); matQueryVisible->setColourWriteEnabled(false); matQueryVisible->setDepthCheckEnabled(true); // Occluded by objects mBBQueryTotal = mRendering->getScene()->createBillboardSet(1); mBBQueryTotal->setDefaultDimensions(150, 150); mBBQueryTotal->createBillboard(Vector3::ZERO); mBBQueryTotal->setMaterialName("QueryTotalPixels"); mBBQueryTotal->setRenderQueueGroup(queue); mSunNode->attachObject(mBBQueryTotal); mBBQueryVisible = mRendering->getScene()->createBillboardSet(1); mBBQueryVisible->setDefaultDimensions(150, 150); mBBQueryVisible->createBillboard(Vector3::ZERO); mBBQueryVisible->setMaterialName("QueryVisiblePixels"); mBBQueryVisible->setRenderQueueGroup(queue); mSunNode->attachObject(mBBQueryVisible); mRendering->getScene()->addRenderObjectListener(this); mDoQuery = true; } OcclusionQuery::~OcclusionQuery() { RenderSystem* renderSystem = Root::getSingleton().getRenderSystem(); if (mSunTotalAreaQuery) renderSystem->destroyHardwareOcclusionQuery(mSunTotalAreaQuery); if (mSunVisibleAreaQuery) renderSystem->destroyHardwareOcclusionQuery(mSunVisibleAreaQuery); } bool OcclusionQuery::supported() { return mSupported; } void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass, const AutoParamDataSource* source, const LightList* pLightList, bool suppressRenderStateChanges) { if (!mSupported) return; // The following code activates and deactivates the occlusion queries // so that the queries only include the rendering of their intended targets // Close the last occlusion query // Each occlusion query should only last a single rendering if (mActiveQuery != NULL) { mActiveQuery->endOcclusionQuery(); mActiveQuery = NULL; } // Open a new occlusion query if (mDoQuery == true) { if (rend == mBBQueryTotal) mActiveQuery = mSunTotalAreaQuery; else if (rend == mBBQueryVisible) mActiveQuery = mSunVisibleAreaQuery; if (mActiveQuery != NULL) { mActiveQuery->beginOcclusionQuery(); } } } void OcclusionQuery::update() { if (!mSupported) return; // Stop occlusion queries until we get their information // (may not happen on the same frame they are requested in) mDoQuery = false; if (!mSunTotalAreaQuery->isStillOutstanding() && !mSunVisibleAreaQuery->isStillOutstanding()) { unsigned int totalPixels; unsigned int visiblePixels; mSunTotalAreaQuery->pullOcclusionQuery(&totalPixels); mSunVisibleAreaQuery->pullOcclusionQuery(&visiblePixels); if (totalPixels == 0) { // probably outside of the view frustum mSunVisibility = 0; } else { mSunVisibility = float(visiblePixels) / float(totalPixels); if (mSunVisibility > 1) mSunVisibility = 1; } mDoQuery = true; } }