From 006aca5b61d17f736da168ff49ff0c0ccb5c7adc Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Thu, 12 Sep 2024 01:21:00 +0200 Subject: [PATCH] Samples: Lighting - refactor occlusion query code --- Samples/Simple/include/Lighting.h | 188 +++++++++++++----------------- 1 file changed, 78 insertions(+), 110 deletions(-) diff --git a/Samples/Simple/include/Lighting.h b/Samples/Simple/include/Lighting.h index 4218bf82030..5370df707c9 100644 --- a/Samples/Simple/include/Lighting.h +++ b/Samples/Simple/include/Lighting.h @@ -7,7 +7,48 @@ using namespace Ogre; using namespace OgreBites; -class _OgreSampleClassExport Sample_Lighting : public SdkSample, public RenderObjectListener +struct OcclusionQueryActivator : public RenderObjectListener +{ + HardwareOcclusionQuery* mActiveQuery = NULL; + + std::map mQueryMap; + + // Event raised when render single object started. + void notifyRenderSingleObject(Renderable* rend, const Pass* pass, const AutoParamDataSource* source, + const LightList* pLightList, bool suppressRenderStateChanges) override + { + // + // 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) + { + mActiveQuery->end(); + mActiveQuery = NULL; + } + + // Open a new occlusion query + + // Check if a the object being rendered needs + // to be occlusion queried, and by which query instance. + auto it = mQueryMap.find(rend); + if(it == mQueryMap.end()) + return; + + // Stop occlusion query until we get the information + // (may not happen on the same frame they are requested in) + if(!it->second->resultReady()) + return; + + mActiveQuery = it->second; + mActiveQuery->begin(); + } +}; + +class _OgreSampleClassExport Sample_Lighting : public SdkSample { static const uint8 cPriorityMain = 50; static const uint8 cPriorityQuery = 51; @@ -25,11 +66,7 @@ class _OgreSampleClassExport Sample_Lighting : public SdkSample, public RenderOb mLight1QueryArea(NULL), mLight1QueryVisible(NULL), mLight2QueryArea(NULL), - mLight2QueryVisible(NULL), - mActiveQuery(NULL), - mUseOcclusionQuery(false), - mDoOcclusionQuery(false) - + mLight2QueryVisible(NULL) { mInfo["Title"] = "Lighting"; mInfo["Description"] = "Shows OGRE's lighting support. Also demonstrates " @@ -41,40 +78,24 @@ class _OgreSampleClassExport Sample_Lighting : public SdkSample, public RenderOb bool frameRenderingQueued(const FrameEvent& evt) override { - // Modulate the light flare according to performed occlusion queries - if (mUseOcclusionQuery) + if (mLight1QueryArea) { - // Stop occlusion queries until we get their information - // (may not happen on the same frame they are requested in) - mDoOcclusionQuery = false; + // Modulate the lights according to the query data + unsigned int lightAreaCount; + unsigned int lightVisibleCount; + float ratio; - // Check if all query information available - if ((mLight1QueryArea->isStillOutstanding() == false) && - (mLight1QueryVisible->isStillOutstanding() == false) && - (mLight2QueryArea->isStillOutstanding() == false) && - (mLight2QueryVisible->isStillOutstanding() == false)) - { - // Modulate the lights according to the query data - unsigned int lightAreaCount; - unsigned int lightVisibleCount; - float ratio; - - mLight1QueryArea->pullOcclusionQuery(&lightAreaCount); - mLight1QueryVisible->pullOcclusionQuery(&lightVisibleCount); - ratio = float(lightVisibleCount) / float(lightAreaCount); - mLight1BBFlare->setColour(mTrail->getInitialColour(0) * ratio); - - mLight2QueryArea->pullOcclusionQuery(&lightAreaCount); - mLight2QueryVisible->pullOcclusionQuery(&lightVisibleCount); - ratio = float(lightVisibleCount) / float(lightAreaCount); - mLight2BBFlare->setColour(mTrail->getInitialColour(1) * ratio); - - // Request new query data - mDoOcclusionQuery = true; - } + lightAreaCount = mLight1QueryArea->getLastResult(); + lightVisibleCount = mLight1QueryVisible->getLastResult(); + ratio = float(lightVisibleCount) / float(lightAreaCount); + mLight1BBFlare->setColour(mTrail->getInitialColour(0) * ratio); + + lightAreaCount = mLight2QueryArea->getLastResult(); + lightVisibleCount = mLight2QueryVisible->getLastResult(); + ratio = float(lightVisibleCount) / float(lightAreaCount); + mLight2BBFlare->setColour(mTrail->getInitialColour(1) * ratio); } - return SdkSample::frameRenderingQueued(evt); // don't forget the parent class updates! } @@ -112,26 +133,15 @@ class _OgreSampleClassExport Sample_Lighting : public SdkSample, public RenderOb mTrail->setRenderQueueGroup(cPriorityLights); // Create the occlusion queries to be used in this sample - try { - RenderSystem* renderSystem = Ogre::Root::getSingleton().getRenderSystem(); - mLight1QueryArea = renderSystem->createHardwareOcclusionQuery(); - mLight1QueryVisible = renderSystem->createHardwareOcclusionQuery(); - mLight2QueryArea = renderSystem->createHardwareOcclusionQuery(); - mLight2QueryVisible = renderSystem->createHardwareOcclusionQuery(); - - mUseOcclusionQuery = (mLight1QueryArea != NULL) && - (mLight1QueryVisible != NULL) && - (mLight2QueryArea != NULL) && - (mLight2QueryVisible != NULL); - } - catch (Exception& e) - { - mUseOcclusionQuery = false; - } + RenderSystem* renderSystem = Ogre::Root::getSingleton().getRenderSystem(); + mLight1QueryArea = renderSystem->createHardwareOcclusionQuery(); + mLight1QueryVisible = renderSystem->createHardwareOcclusionQuery(); + mLight2QueryArea = renderSystem->createHardwareOcclusionQuery(); + mLight2QueryVisible = renderSystem->createHardwareOcclusionQuery(); - if (mUseOcclusionQuery == false) + if (!mLight1QueryArea) { - LogManager::getSingleton().logError("Sample_Lighting - failed to create hardware occlusion query"); + LogManager::getSingleton().logWarning("Sample_Lighting - hardware occlusion query not available"); } // Create the materials to be used by the objects used fo the occlusion query @@ -195,7 +205,7 @@ class _OgreSampleClassExport Sample_Lighting : public SdkSample, public RenderOb bbs->setRenderQueueGroup(cPriorityLights); node->attachObject(bbs); - if (mUseOcclusionQuery) + if (mLight1QueryArea) { // Attach a billboard which will be used to get a relative area occupied by the light mLight1BBQueryArea = mSceneMgr->createBillboardSet(1); @@ -254,7 +264,7 @@ class _OgreSampleClassExport Sample_Lighting : public SdkSample, public RenderOb bbs->setRenderQueueGroup(cPriorityLights); node->attachObject(bbs); - if (mUseOcclusionQuery) + if (mLight1QueryArea) { // Attach a billboard which will be used to get a relative area occupied by the light mLight2BBQueryArea = mSceneMgr->createBillboardSet(1); @@ -271,65 +281,23 @@ class _OgreSampleClassExport Sample_Lighting : public SdkSample, public RenderOb mLight2BBQueryVisible->setMaterial(matQueryVisible); mLight2BBQueryVisible->setRenderQueueGroup(cPriorityQuery); node->attachObject(mLight2BBQueryVisible); - } - - // Setup the listener for the occlusion query - if (mUseOcclusionQuery) - { - mSceneMgr->addRenderObjectListener(this); - mDoOcclusionQuery = true; - } - } - - // Event raised when render single object started. - void notifyRenderSingleObject(Renderable* rend, const Pass* pass, const AutoParamDataSource* source, - const LightList* pLightList, bool suppressRenderStateChanges) override - { - // - // 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 (mDoOcclusionQuery == true) - { - // Check if a the object being rendered needs - // to be occlusion queried, and by which query instance. - if (rend == mLight1BBQueryArea) - mActiveQuery = mLight1QueryArea; - else if (rend == mLight1BBQueryVisible) - mActiveQuery = mLight1QueryVisible; - else if (rend == mLight2BBQueryArea) - mActiveQuery = mLight2QueryArea; - else if (rend == mLight2BBQueryVisible) - mActiveQuery = mLight2QueryVisible; - - if (mActiveQuery != NULL) - { - mActiveQuery->beginOcclusionQuery(); - } + mOcclusionQueryActivator.mQueryMap[mLight2BBQueryArea] = mLight2QueryArea; + mOcclusionQueryActivator.mQueryMap[mLight2BBQueryVisible] = mLight2QueryVisible; + mOcclusionQueryActivator.mQueryMap[mLight1BBQueryArea] = mLight1QueryArea; + mOcclusionQueryActivator.mQueryMap[mLight1BBQueryVisible] = mLight1QueryVisible; + // Setup the listener for the occlusion query + mSceneMgr->addRenderObjectListener(&mOcclusionQueryActivator); } } void cleanupContent() override { RenderSystem* renderSystem = Ogre::Root::getSingleton().getRenderSystem(); - if (mLight1QueryArea != NULL) - renderSystem->destroyHardwareOcclusionQuery(mLight1QueryArea); - if (mLight1QueryVisible != NULL) - renderSystem->destroyHardwareOcclusionQuery(mLight1QueryVisible); - if (mLight2QueryArea != NULL) - renderSystem->destroyHardwareOcclusionQuery(mLight2QueryArea); - if (mLight2QueryVisible != NULL) - renderSystem->destroyHardwareOcclusionQuery(mLight2QueryVisible); + for (const auto& it : mOcclusionQueryActivator.mQueryMap) + { + renderSystem->destroyHardwareOcclusionQuery(it.second); + } } RibbonTrail* mTrail; @@ -345,10 +313,10 @@ class _OgreSampleClassExport Sample_Lighting : public SdkSample, public RenderOb HardwareOcclusionQuery* mLight1QueryVisible; HardwareOcclusionQuery* mLight2QueryArea; HardwareOcclusionQuery* mLight2QueryVisible; - HardwareOcclusionQuery* mActiveQuery; + + OcclusionQueryActivator mOcclusionQueryActivator; bool mUseOcclusionQuery; - bool mDoOcclusionQuery; }; #endif