[Solved] HardwareOcclusionQuery -- Query in RenderSingleObj
-
tgraupmann
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
Unfortunately, when I incorporate this same logic in my project the Pixel Counts are not correct. Or not behaving the same way.
I converted to use Planes instead of BillboardSets and my earlier bad results.
I am suspicious that having multiple SceneManagers could be part of the problem. But I can't be certain.
I also have several queueGroupIds in use. I'm wondering if they step on each other's toes.
In the working example above I used 3 unique queueGroupIds without issues.
Maybe I should use PIX and record beginOcclusionQuery to endOcclusionQuery to diagnose the problem.
I'm a hair's width from using a shader solution. But having the working example above gives me some hope...
I converted to use Planes instead of BillboardSets and my earlier bad results.
I am suspicious that having multiple SceneManagers could be part of the problem. But I can't be certain.
I also have several queueGroupIds in use. I'm wondering if they step on each other's toes.
In the working example above I used 3 unique queueGroupIds without issues.
Maybe I should use PIX and record beginOcclusionQuery to endOcclusionQuery to diagnose the problem.
I'm a hair's width from using a shader solution. But having the working example above gives me some hope...
-
tgraupmann
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
Here's a texture example where the lighting get's all funky because we have two render queues with entities that share the same texture.

Again to run this overwrite your Samples\Demo_TextureFX\TextureFX.h file with this. And then run the Demo_TextureFX sample.

Again to run this overwrite your Samples\Demo_TextureFX\TextureFX.h file with this. And then run the Demo_TextureFX sample.
Code: Select all
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/
Copyright (c) 2000-2005 The OGRE Team
Also see acknowledgements in Readme.html
You may use this sample code for anything you like, it is not covered by the
LGPL like the rest of the engine.
-----------------------------------------------------------------------------
*/
/**
\file
TextureFX.h
\brief
Shows OGRE's ability to handle different types of texture effects.
*/
#include "ExampleApplication.h"
class TextureEffectsApplication : public ExampleApplication, RenderQueueListener
{
public:
TextureEffectsApplication() :
mScalingPlane_PixelCount (0), // Hold the pixel count for
mScrollingKnot_PixelCount (0), // Hardware Occlusion Testing
mWateryPlane_PixelCount (0) // " "
{
}
// Implements RenderQueueListener, For Hardware Occlusion Testing
void renderQueueStarted(uint8 queueGroupId, const std::string &invocation, bool &skipThisInvocation)
{
switch (queueGroupId)
{
case mScalingPlane_RenderQueueGroup:
break;
case mScrollingKnot_RenderQueueGroup:
break;
case mWateryPlane_RenderQueueGroup:
break;
default:
// not interested
return;
};
// CREATE HardwareOcclusionQuery
Ogre::HardwareOcclusionQuery* hardwareOcclusionQuery = Root::getSingleton().getRenderSystem()->createHardwareOcclusionQuery();
assert (hardwareOcclusionQuery);
// Start the HardwareOcclusionQuery
hardwareOcclusionQuery->beginOcclusionQuery();
// Render the Item
mSceneMgr->_renderQueueGroupObjects(mSceneMgr->getRenderQueue()->getQueueGroup(queueGroupId), Ogre::QueuedRenderableCollection::OrganisationMode::OM_PASS_GROUP);
// Stop the HardwareOcclusionQuery
hardwareOcclusionQuery->endOcclusionQuery();
// ALREADY RENDERED
skipThisInvocation = true;
switch (queueGroupId)
{
case mScalingPlane_RenderQueueGroup:
// GET THE PIXEL COUNT
hardwareOcclusionQuery->pullOcclusionQuery(&mScalingPlane_PixelCount);
break;
case mScrollingKnot_RenderQueueGroup:
// GET THE PIXEL COUNT
hardwareOcclusionQuery->pullOcclusionQuery(&mScrollingKnot_PixelCount);
break;
case mWateryPlane_RenderQueueGroup:
// GET THE PIXEL COUNT
hardwareOcclusionQuery->pullOcclusionQuery(&mWateryPlane_PixelCount);
break;
};
// DELETE HardwareOcclusionQuery
Root::getSingleton().getRenderSystem()->destroyHardwareOcclusionQuery(hardwareOcclusionQuery);
hardwareOcclusionQuery = 0;
// SET THE DEBUG TEXT TO DISPLAY THE PIXEL COUNTS
char buffer[250] = {0};
sprintf(buffer,
"ScalingPlane: [%d], WateryPlane [%d], ScrollingKnot [%d]",
mScalingPlane_PixelCount, mWateryPlane_PixelCount, mScrollingKnot_PixelCount);
mWindow->setDebugText(buffer);
}
// Implements RenderQueueListener, For Hardware Occlusion Testing
void renderQueueEnded(uint8 queueGroupId, const std::string &invocation, bool &repeatThisInvocation)
{
}
protected:
// Hardware Occlusion Testing CONSTANT
static const unsigned int mScalingPlane_RenderQueueGroup = 1;
// Pixel Count
unsigned int mScalingPlane_PixelCount;
void createScalingPlane()
{
// Set up a material for the plane
// Create a prefab plane
Entity *planeEnt = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
// Give the plane a texture
planeEnt->setMaterialName("Examples/TextureEffect1");
// For Hardware Occlusion Testing
planeEnt->setRenderQueueGroup(mScalingPlane_RenderQueueGroup);
SceneNode* node =
mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-250,-40,-100));
node->attachObject(planeEnt);
}
// Hardware Occlusion Testing CONSTANT
static const unsigned int mScrollingKnot_RenderQueueGroup = 2;
// Pixel Count
unsigned int mScrollingKnot_PixelCount;
void createScrollingKnot()
{
Entity *ent = mSceneMgr->createEntity("knot", "knot.mesh");
ent->setMaterialName("Examples/TextureEffect2");
// For Hardware Occlusion Testing
ent->setRenderQueueGroup(mScrollingKnot_RenderQueueGroup);
// Add entity to the root scene node
SceneNode* node =
mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(200,50,150));
node->attachObject(ent);
}
// Hardware Occlusion Testing CONSTANT
static const unsigned int mWateryPlane_RenderQueueGroup = 3;
// Pixel Count
unsigned int mWateryPlane_PixelCount;
void createWateryPlane()
{
// Create a prefab plane
Entity *planeEnt = mSceneMgr->createEntity("WaterPlane", SceneManager::PT_PLANE);
// For Hardware Occlusion Testing
planeEnt->setRenderQueueGroup(mWateryPlane_RenderQueueGroup);
// Give the plane a texture
planeEnt->setMaterialName("Examples/TextureEffect3");
mSceneMgr->getRootSceneNode()->attachObject(planeEnt);
}
void createImposterPlane()
{
// Create a prefab plane
Entity *ent = mSceneMgr->createEntity("ImposterPlane", SceneManager::PT_PLANE);
// Give the plane a texture
ent->setMaterialName("Examples/TextureEffect2");
ent->setRenderQueueGroup(0);
// Add entity to the root scene node
SceneNode* node =
mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,0,-250));
assert (node);
node->setScale(5, 5, 0);
node->_updateBounds();
node->attachObject(ent);
}
// Just override the mandatory create scene method
void createScene(void)
{
// Set ambient light
mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
// Create a point light
Light* l = mSceneMgr->createLight("MainLight");
// Accept default settings: point light, white diffuse, just set position
// NB I could attach the light to a SceneNode if I wanted it to move automatically with
// other objects, but I don't
l->setPosition(20,80,50);
// Added for Hardware Occlusion Testing
mSceneMgr->addRenderQueueListener(this);
createScalingPlane();
createScrollingKnot();
createWateryPlane();
createImposterPlane();
// Set up a material for the skydome
MaterialPtr skyMat = MaterialManager::getSingleton().create("SkyMat",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
// Perform no dynamic lighting on the sky
skyMat->setLightingEnabled(false);
// Use a cloudy sky
TextureUnitState* t = skyMat->getTechnique(0)->getPass(0)->createTextureUnitState("clouds.jpg");
// Scroll the clouds
t->setScrollAnimation(0.15, 0);
// System will automatically set no depth write
// Create a skydome
mSceneMgr->setSkyDome(true, "SkyMat", -5, 2);
}
};
-
tgraupmann
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
-
Lee04
- Minaton
- Posts: 945
- Joined: Mon Jul 05, 2004 4:06 pm
- Location: Sweden
- x 1
Hmmm I think the demos here are toy demos, right?
A complex scene and this won't work. Because on how Ogre renders scenes are not compaible with the what the use of hardware occlusion query requires.
HOQ requires scenes render sorted on depth.
While Ogre sorts the rendered scene based on materials.
So if you have a deep complex scene with many different materials
and use standard Ogre rendering you will get a random result on your pixel count. Thats why I have done a special rendering plug-in for Ogre that does a first pass just for getting hardware occlusion qyuery and early z out working like it should.
Lee04
A complex scene and this won't work. Because on how Ogre renders scenes are not compaible with the what the use of hardware occlusion query requires.
HOQ requires scenes render sorted on depth.
While Ogre sorts the rendered scene based on materials.
So if you have a deep complex scene with many different materials
and use standard Ogre rendering you will get a random result on your pixel count. Thats why I have done a special rendering plug-in for Ogre that does a first pass just for getting hardware occlusion qyuery and early z out working like it should.
Lee04
Ph.D. student in game development
-
tgraupmann
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
Care to share your source code? Because that's exactly what I'm seeing random pixel values. Because I've done some things. Bad things. I've changed the sort order by using depth functions, used depth biases, added particle systems, and added billboard sets on top of that. Plus there's a lot of sharing materials going on. So I'll need to use whatever solution you have.Lee04 wrote:Hmmm I think the demos here are toy demos, right?
A complex scene and this won't work. Because on how Ogre renders scenes are not compaible with the what the use of hardware occlusion query requires.
HOQ requires scenes render sorted on depth.
While Ogre sorts the rendered scene based on materials.
So if you have a deep complex scene with many different materials
and use standard Ogre rendering you will get a random result on your pixel count. Thats why I have done a special rendering plug-in for Ogre that does a first pass just for getting hardware occlusion qyuery and early z out working like it should.
Lee04
-
jacmoe
- OGRE Retired Moderator

- Posts: 20570
- Joined: Thu Jan 22, 2004 10:13 am
- Location: Denmark
- x 179
Lee04 is sellling that plugin.. 
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
-
tgraupmann
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
Re-implementing another Ogre::SceneManager doesn't seem like a difficult task.
Let's see, I'd need to make a CustomSceneManager class.
CustomSceneManager.h
Since Ogre::SceneManager is an abstract class, we need to provide a little implementation.
CustomSceneManager.cpp
And then we need to modify the Texture Demo again to add the CustomSceneManagerFactory.
TextureFX.h
Remaining Logic
Now I just need to provide a little logic in our CustomSceneManager to sort objects in DECENDING DISTANCE ORDER, instead of SORTED BY RENDER QUEUE ID or material or whatever...
(To be continued...)
Let's see, I'd need to make a CustomSceneManager class.
CustomSceneManager.h
Code: Select all
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/
Copyright (c) 2000-2005 The OGRE Team
Also see acknowledgements in Readme.html
You may use this sample code for anything you like, it is not covered by the
LGPL like the rest of the engine.
-----------------------------------------------------------------------------
*/
/**
\file
CustomSceneManager.h
\brief
Shows OGRE's ability to handle a different scene manager.
*/
#ifndef __CUSTOM_SCENE_MANAGER__H__
#define __CUSTOM_SCENE_MANAGER__H__
#include <OgreNoMemoryMacros.h>
#include <OgreSceneManagerEnumerator.h>
#include <OgreMemoryMacros.h>
class CustomSceneManagerFactory : public Ogre::SceneManagerFactory
{
protected:
void initMetaData(void) const;
public:
CustomSceneManagerFactory() {}
~CustomSceneManagerFactory() {}
/// Factory type name
static const Ogre::String FACTORY_TYPE_NAME;
Ogre::SceneManager* createInstance(const Ogre::String& instanceName);
void destroyInstance(Ogre::SceneManager* instance);
};
class CustomSceneManager : public Ogre::SceneManager
{
public:
CustomSceneManager(const Ogre::String& name);
~CustomSceneManager();
const Ogre::String& getTypeName(void) const;
};
#endif // __CUSTOM_SCENE_MANAGER__H__CustomSceneManager.cpp
Code: Select all
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/
Copyright (c) 2000-2005 The OGRE Team
Also see acknowledgements in Readme.html
You may use this sample code for anything you like, it is not covered by the
LGPL like the rest of the engine.
-----------------------------------------------------------------------------
*/
/**
\file
CustomSceneManager.cpp
\brief
Shows OGRE's ability to handle a different scene manager.
*/
#include "CustomSceneManager.h"
void CustomSceneManagerFactory::initMetaData(void) const
{
mMetaData.typeName = FACTORY_TYPE_NAME;
mMetaData.description = "The custom scene manager";
mMetaData.sceneTypeMask = Ogre::ST_GENERIC;
mMetaData.worldGeometrySupported = false;
}
const Ogre::String CustomSceneManagerFactory::FACTORY_TYPE_NAME = "CustomSceneManager";
Ogre::SceneManager* CustomSceneManagerFactory::createInstance(const Ogre::String& instanceName)
{
return new CustomSceneManager(instanceName);
}
void CustomSceneManagerFactory::destroyInstance(Ogre::SceneManager* instance)
{
delete instance;
}
CustomSceneManager::CustomSceneManager(const Ogre::String& name)
: Ogre::SceneManager(name)
{
}
CustomSceneManager::~CustomSceneManager()
{
}
const Ogre::String& CustomSceneManager::getTypeName(void) const
{
return CustomSceneManagerFactory::FACTORY_TYPE_NAME;
}TextureFX.h
Code: Select all
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/
Copyright (c) 2000-2005 The OGRE Team
Also see acknowledgements in Readme.html
You may use this sample code for anything you like, it is not covered by the
LGPL like the rest of the engine.
-----------------------------------------------------------------------------
*/
/**
\file
TextureFX.h
\brief
Shows OGRE's ability to handle different types of texture effects.
*/
#include "ExampleApplication.h"
#include "CustomSceneManager.h"
class TextureEffectsApplication : public ExampleApplication, RenderQueueListener
{
public:
TextureEffectsApplication() :
mScalingPlane_PixelCount (0), // Hold the pixel count for
mScrollingKnot_PixelCount (0), // Hardware Occlusion Testing
mWateryPlane_PixelCount (0) // " "
{
}
// Implements RenderQueueListener, For Hardware Occlusion Testing
void renderQueueStarted(uint8 queueGroupId, const std::string &invocation, bool &skipThisInvocation)
{
switch (queueGroupId)
{
case mScalingPlane_RenderQueueGroup:
break;
case mScrollingKnot_RenderQueueGroup:
break;
case mWateryPlane_RenderQueueGroup:
break;
default:
// not interested
return;
};
// CREATE HardwareOcclusionQuery
Ogre::HardwareOcclusionQuery* hardwareOcclusionQuery = Root::getSingleton().getRenderSystem()->createHardwareOcclusionQuery();
assert (hardwareOcclusionQuery);
// Start the HardwareOcclusionQuery
hardwareOcclusionQuery->beginOcclusionQuery();
// Render the Item
mSceneMgr->_renderQueueGroupObjects(mSceneMgr->getRenderQueue()->getQueueGroup(queueGroupId), Ogre::QueuedRenderableCollection::OrganisationMode::OM_PASS_GROUP);
// Stop the HardwareOcclusionQuery
hardwareOcclusionQuery->endOcclusionQuery();
// ALREADY RENDERED
skipThisInvocation = true;
switch (queueGroupId)
{
case mScalingPlane_RenderQueueGroup:
// GET THE PIXEL COUNT
hardwareOcclusionQuery->pullOcclusionQuery(&mScalingPlane_PixelCount);
break;
case mScrollingKnot_RenderQueueGroup:
// GET THE PIXEL COUNT
hardwareOcclusionQuery->pullOcclusionQuery(&mScrollingKnot_PixelCount);
break;
case mWateryPlane_RenderQueueGroup:
// GET THE PIXEL COUNT
hardwareOcclusionQuery->pullOcclusionQuery(&mWateryPlane_PixelCount);
break;
};
// DELETE HardwareOcclusionQuery
Root::getSingleton().getRenderSystem()->destroyHardwareOcclusionQuery(hardwareOcclusionQuery);
hardwareOcclusionQuery = 0;
// SET THE DEBUG TEXT TO DISPLAY THE PIXEL COUNTS
char buffer[250] = {0};
sprintf(buffer,
"ScalingPlane: [%d], WateryPlane [%d], ScrollingKnot [%d]",
mScalingPlane_PixelCount, mWateryPlane_PixelCount, mScrollingKnot_PixelCount);
mWindow->setDebugText(buffer);
}
// Implements RenderQueueListener, For Hardware Occlusion Testing
void renderQueueEnded(uint8 queueGroupId, const std::string &invocation, bool &repeatThisInvocation)
{
}
protected:
// To create a custom scene manager you need a factory
CustomSceneManagerFactory* mCustomSceneManagerFactory;
// For custom scene manager
virtual void chooseSceneManager(void)
{
if (!mCustomSceneManagerFactory)
{
// Create custom scene manager factory
mCustomSceneManagerFactory = new CustomSceneManagerFactory();
assert (mCustomSceneManagerFactory);
// Allows creation of Custom Scene Managers
Root::getSingleton().addSceneManagerFactory(mCustomSceneManagerFactory); //only do this once
}
// Create the SceneManager, in this case a custom one
mSceneMgr = mRoot->createSceneManager(ST_GENERIC, "CustomSceneManager");
}
// Hardware Occlusion Testing CONSTANT
static const unsigned int mScalingPlane_RenderQueueGroup = 1;
// Pixel Count
unsigned int mScalingPlane_PixelCount;
void createScalingPlane()
{
// Set up a material for the plane
// Create a prefab plane
Entity *planeEnt = mSceneMgr->createEntity("Plane", SceneManager::PT_PLANE);
// Give the plane a texture
planeEnt->setMaterialName("Examples/TextureEffect1");
// For Hardware Occlusion Testing
planeEnt->setRenderQueueGroup(mScalingPlane_RenderQueueGroup);
SceneNode* node =
mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-250,-40,-100));
node->attachObject(planeEnt);
}
// Hardware Occlusion Testing CONSTANT
static const unsigned int mScrollingKnot_RenderQueueGroup = 2;
// Pixel Count
unsigned int mScrollingKnot_PixelCount;
void createScrollingKnot()
{
Entity *ent = mSceneMgr->createEntity("knot", "knot.mesh");
ent->setMaterialName("Examples/TextureEffect2");
// For Hardware Occlusion Testing
ent->setRenderQueueGroup(mScrollingKnot_RenderQueueGroup);
// Add entity to the root scene node
SceneNode* node =
mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(200,50,150));
node->attachObject(ent);
}
// Hardware Occlusion Testing CONSTANT
static const unsigned int mWateryPlane_RenderQueueGroup = 3;
// Pixel Count
unsigned int mWateryPlane_PixelCount;
void createWateryPlane()
{
// Create a prefab plane
Entity *planeEnt = mSceneMgr->createEntity("WaterPlane", SceneManager::PT_PLANE);
// For Hardware Occlusion Testing
planeEnt->setRenderQueueGroup(mWateryPlane_RenderQueueGroup);
// Give the plane a texture
planeEnt->setMaterialName("Examples/TextureEffect3");
mSceneMgr->getRootSceneNode()->attachObject(planeEnt);
}
void createImposterPlane()
{
// Create a prefab plane
Entity *ent = mSceneMgr->createEntity("ImposterPlane", SceneManager::PT_PLANE);
// Give the plane a texture
ent->setMaterialName("Examples/TextureEffect2");
ent->setRenderQueueGroup(0);
// Add entity to the root scene node
SceneNode* node =
mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,0,-250));
assert (node);
node->setScale(5, 5, 0);
node->_updateBounds();
node->attachObject(ent);
}
// Just override the mandatory create scene method
void createScene(void)
{
// Set ambient light
mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
// Create a point light
Light* l = mSceneMgr->createLight("MainLight");
// Accept default settings: point light, white diffuse, just set position
// NB I could attach the light to a SceneNode if I wanted it to move automatically with
// other objects, but I don't
l->setPosition(20,80,50);
// Added for Hardware Occlusion Testing
mSceneMgr->addRenderQueueListener(this);
createScalingPlane();
createScrollingKnot();
createWateryPlane();
createImposterPlane();
// Set up a material for the skydome
MaterialPtr skyMat = MaterialManager::getSingleton().create("SkyMat",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
// Perform no dynamic lighting on the sky
skyMat->setLightingEnabled(false);
// Use a cloudy sky
TextureUnitState* t = skyMat->getTechnique(0)->getPass(0)->createTextureUnitState("clouds.jpg");
// Scroll the clouds
t->setScrollAnimation(0.15, 0);
// System will automatically set no depth write
// Create a skydome
mSceneMgr->setSkyDome(true, "SkyMat", -5, 2);
}
};
Now I just need to provide a little logic in our CustomSceneManager to sort objects in DECENDING DISTANCE ORDER, instead of SORTED BY RENDER QUEUE ID or material or whatever...
(To be continued...)
-
tgraupmann
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
I've been reading the source comments and looking deeper in the Ogre::SceneManager source.
Is it possible to do HOQ queries around a SpecialCaseRenderQueue? I had just been assigning unused values for the RenderingQueueId.
I guess that's what I was trying earlier anyway. When the pixel values were seemingly random. Most likely because other objects were sneaking into Hardware Occlusion Query test.
But I'm starting to see the Ogre rendering system is more complex:
http://www.ogre3d.org/phpBB2/viewtopic. ... enderqueue
Digging deeper... Down the rabbit hole...
Is it possible to do HOQ queries around a SpecialCaseRenderQueue? I had just been assigning unused values for the RenderingQueueId.
I guess that's what I was trying earlier anyway. When the pixel values were seemingly random. Most likely because other objects were sneaking into Hardware Occlusion Query test.
But I'm starting to see the Ogre rendering system is more complex:
http://www.ogre3d.org/phpBB2/viewtopic. ... enderqueue
Digging deeper... Down the rabbit hole...
-
Lee04
- Minaton
- Posts: 945
- Joined: Mon Jul 05, 2004 4:06 pm
- Location: Sweden
- x 1
-
tgraupmann
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
-
Lee04
- Minaton
- Posts: 945
- Joined: Mon Jul 05, 2004 4:06 pm
- Location: Sweden
- x 1
-
tgraupmann
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
The simplest answer is always the best solution. I got occlusion working. Check it out:

I just got something working. I just implemented RenderSingle on an extended interface of DefaultSceneManager. I do the query at the beginning and end of the method. The pixel counts are correct now. It's amazing.
Right now it works for a single object, but it's relatively simple to add a list of objects to test for.
...

I just got something working. I just implemented RenderSingle on an extended interface of DefaultSceneManager. I do the query at the beginning and end of the method. The pixel counts are correct now. It's amazing.
Right now it works for a single object, but it's relatively simple to add a list of objects to test for.
Code: Select all
class CustomSceneManager : public Ogre::SceneManager
{
friend class StarElement;
public:
CustomSceneManager(const Ogre::String& name);
~CustomSceneManager();
const Ogre::String& getTypeName(void) const;
/** Internal utility method for rendering a single object.
@remarks
Assumes that the pass has already been set up.
@param rend The renderable to issue to the pipeline
@param pass The pass which is being used
@param doLightIteration If true, this method will issue the renderable to
the pipeline possibly multiple times, if the pass indicates it should be
done once per light
@param manualLightList Only applicable if doLightIteration is false, this
method allows you to pass in a previously determined set of lights
which will be used for a single render of this object.
*/
virtual void renderSingleObject(const Ogre::Renderable* rend, const Ogre::Pass* pass,
bool doLightIteration, const Ogre::LightList* manualLightList = 0);
};Code: Select all
#include <OgreNoMemoryMacros.h>
#include "OgreCamera.h"
#include "OgreString.h"
#include "OgreSceneNode.h"
#include "OgrePlane.h"
#include "OgreQuaternion.h"
#include "OgreColourValue.h"
#include "OgreCommon.h"
#include "OgreSceneQuery.h"
#include "OgreAutoParamDataSource.h"
#include "OgreAnimationState.h"
#include "OgreRenderQueue.h"
#include "OgreRenderQueueSortingGrouping.h"
#include "OgreRenderSystem.h"
#include "OgreRectangle2D.h"
#include "OgrePixelFormat.h"
#include "OgreRoot.h"
#include <OgreHardwareOcclusionQuery.h>
#include "OgreResourceGroupManager.h"
#include "OgreTexture.h"
#include <OgreMemoryMacros.h>
Ogre::Renderable* g_InspectRenderable = 0;
unsigned int g_PixelCount = 0;Code: Select all
void CustomSceneManager::renderSingleObject(const Ogre::Renderable* rend, const Ogre::Pass* pass,
bool doLightIteration, const Ogre::LightList* manualLightList)
{
/// <!-- START OF CUSTOM CODE -->
///
/// CREATE HardwareOcclusionQuery
///
static Ogre::HardwareOcclusionQuery* hardwareOcclusionQuery;
if (g_InspectRenderable == rend)
{
hardwareOcclusionQuery = Ogre::Root::getSingleton().getRenderSystem()->createHardwareOcclusionQuery();
assert (hardwareOcclusionQuery);
///
/// Start the HardwareOcclusionQuery
///
hardwareOcclusionQuery->beginOcclusionQuery();
}
/// <!-- END OF CUSTOM CODE -->
unsigned short numMatrices;
static Ogre::RenderOperation ro;
static Ogre::LightList localLightList;
// Set up rendering operation
// I know, I know, const_cast is nasty but otherwise it requires all internal
// state of the Renderable assigned to the rop to be mutable
const_cast<Ogre::Renderable*>(rend)->getRenderOperation(ro);
ro.srcRenderable = rend;
// Set world transformation
rend->getWorldTransforms(mTempXform);
numMatrices = rend->getNumWorldTransforms();
if (numMatrices > 1)
{
mDestRenderSystem->_setWorldMatrices(mTempXform, numMatrices);
}
else
{
mDestRenderSystem->_setWorldMatrix(*mTempXform);
}
// Issue view / projection changes if any
useRenderableViewProjMode(rend);
if (!mSuppressRenderStateChanges)
{
bool passSurfaceAndLightParams = true;
if (pass->isProgrammable())
{
// Tell auto params object about the renderable change
mAutoParamDataSource.setCurrentRenderable(rend);
pass->_updateAutoParamsNoLights(mAutoParamDataSource);
if (pass->hasVertexProgram())
{
passSurfaceAndLightParams = pass->getVertexProgram()->getPassSurfaceAndLightStates();
}
}
// Reissue any texture gen settings which are dependent on view matrix
Ogre::Pass::ConstTextureUnitStateIterator texIter = pass->getTextureUnitStateIterator();
size_t unit = 0;
while(texIter.hasMoreElements())
{
Ogre::TextureUnitState* pTex = texIter.getNext();
if (pTex->hasViewRelativeTextureCoordinateGeneration())
{
mDestRenderSystem->_setTextureUnitSettings(unit, *pTex);
}
++unit;
}
// Sort out normalisation
mDestRenderSystem->setNormaliseNormals(rend->getNormaliseNormals());
// Set up the solid / wireframe override
// Precedence is Camera, Object, Material
// Camera might not override object if not overrideable
Ogre::PolygonMode reqMode = pass->getPolygonMode();
if (rend->getPolygonModeOverrideable())
{
Ogre::PolygonMode camPolyMode = mCameraInProgress->getPolygonMode();
// check camera detial only when render detail is overridable
if (reqMode > camPolyMode)
{
// only downgrade detail; if cam says wireframe we don't go up to solid
reqMode = camPolyMode;
}
}
mDestRenderSystem->_setPolygonMode(reqMode);
mDestRenderSystem->setClipPlanes(rend->getClipPlanes());
if (doLightIteration)
{
// Here's where we issue the rendering operation to the render system
// Note that we may do this once per light, therefore it's in a loop
// and the light parameters are updated once per traversal through the
// loop
const Ogre::LightList& rendLightList = rend->getLights();
bool iteratePerLight = pass->getIteratePerLight();
size_t numIterations = iteratePerLight ? rendLightList.size() : 1;
const Ogre::LightList* pLightListToUse;
for (size_t i = 0; i < numIterations; ++i)
{
// Determine light list to use
if (iteratePerLight)
{
// Change the only element of local light list to be
// the light at index i
localLightList.clear();
// Check whether we need to filter this one out
if (pass->getRunOnlyForOneLightType() &&
pass->getOnlyLightType() != rendLightList[i]->getType())
{
// Skip
continue;
}
localLightList.push_back(rendLightList[i]);
pLightListToUse = &localLightList;
}
else
{
// Use complete light list
pLightListToUse = &rendLightList;
}
// Do we need to update GPU program parameters?
if (pass->isProgrammable())
{
// Update any automatic gpu params for lights
// Other bits of information will have to be looked up
mAutoParamDataSource.setCurrentLightList(pLightListToUse);
pass->_updateAutoParamsLightsOnly(mAutoParamDataSource);
// NOTE: We MUST bind parameters AFTER updating the autos
// TEST
if (pass->hasVertexProgram())
{
mDestRenderSystem->bindGpuProgramParameters(Ogre::GPT_VERTEX_PROGRAM,
pass->getVertexProgramParameters());
}
if (pass->hasFragmentProgram())
{
mDestRenderSystem->bindGpuProgramParameters(Ogre::GPT_FRAGMENT_PROGRAM,
pass->getFragmentProgramParameters());
}
}
// Do we need to update light states?
// Only do this if fixed-function vertex lighting applies
if (pass->getLightingEnabled() && passSurfaceAndLightParams)
{
mDestRenderSystem->_useLights(*pLightListToUse, pass->getMaxSimultaneousLights());
}
// issue the render op
// nfz: check for gpu_multipass
mDestRenderSystem->setCurrentPassIterationCount(pass->getPassIterationCount());
mDestRenderSystem->_render(ro);
} // possibly iterate per light
}
else // no automatic light processing
{
// Do we need to update GPU program parameters?
if (pass->isProgrammable())
{
// Do we have a manual light list?
if (manualLightList)
{
// Update any automatic gpu params for lights
mAutoParamDataSource.setCurrentLightList(manualLightList);
pass->_updateAutoParamsLightsOnly(mAutoParamDataSource);
}
if (pass->hasVertexProgram())
{
mDestRenderSystem->bindGpuProgramParameters(Ogre::GPT_VERTEX_PROGRAM,
pass->getVertexProgramParameters());
}
if (pass->hasFragmentProgram())
{
mDestRenderSystem->bindGpuProgramParameters(Ogre::GPT_FRAGMENT_PROGRAM,
pass->getFragmentProgramParameters());
}
}
// Use manual lights if present, and not using vertex programs that don't use fixed pipeline
if (manualLightList &&
pass->getLightingEnabled() && passSurfaceAndLightParams)
{
mDestRenderSystem->_useLights(*manualLightList, pass->getMaxSimultaneousLights());
}
// issue the render op
// nfz: set up multipass rendering
mDestRenderSystem->setCurrentPassIterationCount(pass->getPassIterationCount());
mDestRenderSystem->_render(ro);
}
}
else // mSuppressRenderStateChanges
{
// Just render
mDestRenderSystem->setCurrentPassIterationCount(1);
mDestRenderSystem->_render(ro);
}
// Reset view / projection changes if any
resetViewProjMode();
/// <!-- START OF CUSTOM CODE -->
if (g_InspectRenderable == rend)
{
///
/// Stop the HardwareOcclusionQuery
///
hardwareOcclusionQuery->endOcclusionQuery();
///
/// GET THE PIXEL COUNT
///
hardwareOcclusionQuery->pullOcclusionQuery(&g_PixelCount);
///
/// DELETE HardwareOcclusionQuery
///
Ogre::Root::getSingleton().getRenderSystem()->destroyHardwareOcclusionQuery(hardwareOcclusionQuery);
hardwareOcclusionQuery = 0;
}
/// <!-- END OF CUSTOM CODE -->
}-
tgraupmann
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
I just realized another key thing for making this work is your material script.
Here are the sample values that I used:
Here are the sample values that I used:
Code: Select all
material star_1_element_blank
{
technique
{
pass
{
lighting off
scene_blend src_alpha dest_alpha
depth_write off
cull_hardware none
cull_software none
texture_unit
{
tex_address_mode clamp
texture star_1_element_blank.png
}
}
}
}-
tgraupmann
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
I should also mention that you should disabling culling:
This helps when the Billboard is off the screen the pixel count will be zero. Without this, if the billboard gets culled it won't update the pixel count.
Code: Select all
cull_hardware none
cull_software none -
syedhs
- Silver Sponsor

- Posts: 2703
- Joined: Mon Aug 29, 2005 3:24 pm
- Location: Kuala Lumpur, Malaysia
- x 51
-
tgraupmann
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
Alright, step one create the page:
http://www.ogre3d.org/wiki/index.php/Ha ... sion_Query
http://www.ogre3d.org/wiki/index.php/Ha ... sion_Query
-
tgraupmann
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
Alright I got around to improving the HOQ documentation.tgraupmann wrote:Alright, step one create the page:
http://www.ogre3d.org/wiki/index.php/Ha ... sion_Query
-
big_o
- Goblin
- Posts: 279
- Joined: Sun Feb 19, 2006 1:08 am