[Solved] HardwareOcclusionQuery -- Query in RenderSingleObj
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
[Solved] HardwareOcclusionQuery -- Query in RenderSingleObj
I have a question about how to implement a particular feature.
I would like to render an Ogre::Billboard.
However, I would like to adjust the alpha value of this Ogre::Billboard based on how much the Ogre::Billboard is occluded. I'd also like to do a fluid transition.
The idea is the Ogre::Billboard would fade out as an Ogre::Entity mesh appears in front of the Ogre::Billboard.
Any suggestions how to do this?
I have one idea. If the material has depth_test and depth_check on, maybe I could use the Ogre sort order value to make an educated guess how much the object is occluded?
Say if the sort order is 0-25 then alpha 100%-75%.
If the sort order is 25-50 then alpha 75%-50%.
If the sort order is 50-75 then alpha 50%-25%.
If the sort order is 75-100 then alpha 25%-0%.
I'm willing to try any better ideas.
Apparently, the worst idea is to use the depth buffer.
I would like to render an Ogre::Billboard.
However, I would like to adjust the alpha value of this Ogre::Billboard based on how much the Ogre::Billboard is occluded. I'd also like to do a fluid transition.
The idea is the Ogre::Billboard would fade out as an Ogre::Entity mesh appears in front of the Ogre::Billboard.
Any suggestions how to do this?
I have one idea. If the material has depth_test and depth_check on, maybe I could use the Ogre sort order value to make an educated guess how much the object is occluded?
Say if the sort order is 0-25 then alpha 100%-75%.
If the sort order is 25-50 then alpha 75%-50%.
If the sort order is 50-75 then alpha 50%-25%.
If the sort order is 75-100 then alpha 25%-0%.
I'm willing to try any better ideas.
Apparently, the worst idea is to use the depth buffer.
Last edited by tgraupmann on Wed Dec 06, 2006 5:26 pm, edited 5 times in total.
- sinbad
- OGRE Retired Team Member
- Posts: 19269
- Joined: Sun Oct 06, 2002 11:19 pm
- Location: Guernsey, Channel Islands
- x 66
- Contact:
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
Found another post for somebody else also working on a lens flare:
http://www.ogre3d.org/phpBB2/viewtopic. ... a872313ca8
http://www.ogre3d.org/phpBB2/viewtopic. ... a872313ca8
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
How do you go about setting a rendering callback for begin and end on a Ogre::Billboard or Ogre::BillboardSet?
And then I could use HardwareOcclusionQuery:
http://www.ogre3d.org/docs/api/html/cla ... Query.html
Make a call to HardwareOcclusionQuery::beginOcclusionQuery in the begin render callback.
And make a call to HardwareOcclusionQuery::endOcclusionQuery in the end render callback.
HardwareOcclusionQuery::getLastQuerysPixelcount should tell me how many pixels were shown and I'll be able to base the alpha on that.
So my only question is how do you set up a rendering callback for a single Ogre::Billboard?
Must have something to do with Ogre::RenderQueueListener on the Ogre::SceneManager.:
http://www.ogre3d.org/docs/api/html/cla ... anagera173
And then I could use HardwareOcclusionQuery:
http://www.ogre3d.org/docs/api/html/cla ... Query.html
Make a call to HardwareOcclusionQuery::beginOcclusionQuery in the begin render callback.
And make a call to HardwareOcclusionQuery::endOcclusionQuery in the end render callback.
HardwareOcclusionQuery::getLastQuerysPixelcount should tell me how many pixels were shown and I'll be able to base the alpha on that.
So my only question is how do you set up a rendering callback for a single Ogre::Billboard?
Must have something to do with Ogre::RenderQueueListener on the Ogre::SceneManager.:
http://www.ogre3d.org/docs/api/html/cla ... anagera173
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
Ahh this was easy. RenderQueueListener is a delegate. So I created a class that inherits from Ogre::RenderQueueListener and implements (renderQueueStarted & renderQueueEnded).
And then within that class you do a:
The next step is:
But where do we get the IDirect3DDevice9?
http://www.ogre3d.org/phpBB2/viewtopic. ... t3ddevice9
And then within that class you do a:
Code: Select all
Ogre::SceneNodeManager::addRenderQueueListener(this);
Code: Select all
m_HardwareOcclusionQuery = new D3D9HardwareOcclusionQuery(pD3DDevice);
http://www.ogre3d.org/phpBB2/viewtopic. ... t3ddevice9
So my nice problem is I need to figure out how to access D3D9RenderWindow.sinbad wrote:You'll have to use D3D9RenderWindow::getCustomAttribute("D3DDEVICE", &lpD3DDev), because this is a D3D-specific property and therefore not accessible through the normal interfaces.
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
Ok to get D3D9RenderWindow I just casted the regular window into a D3D9RenderWindow.
And then used the LPDIRECT3DDEVICE9 with D3D9HardwareOcclusionQuery.
Now I'm getting a link error. Even though I've added RenderSystem_Direct3D9.lib.
Code: Select all
LPDIRECT3DDEVICE9 lpD3DDev;;
((D3D9RenderWindow*)window)->getCustomAttribute("D3DDEVICE", &lpD3DDev);
Code: Select all
m_HardwareOcclusionQuery = new D3D9HardwareOcclusionQuery(lpD3DDev);
assert (m_HardwareOcclusionQuery);
Code: Select all
error LNK2001: unresolved external symbol "public: __thiscall Ogre::D3D9HardwareOcclusionQuery::D3D9HardwareOcclusionQuery(struct IDirect3DDevice9 *)" (??0D3D9HardwareOcclusionQuery@Ogre@@QAE@PAUIDirect3DDevice9@@@Z)
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
Ah that was completely unnecessary. All I needed to do was:
Code: Select all
m_HardwareOcclusionQuery = Root::getSingleton().getRenderSystem()->createHardwareOcclusionQuery();
assert (m_HardwareOcclusionQuery);
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
Ok now I am seeing the pixel counts get populated:
Is it possible to set the queueGroupId on an Ogre::BillboardSet, so that I can test just that set?
Code: Select all
StarElement: renderQueueStarted [0] [] [0]
StarElement: renderQueueEnded [0] [] [0]
StarElement: renderQueueStarted [5] [] [0]
StarElement: renderQueueEnded [5] [] [0]
StarElement: renderQueueStarted [50] [] [0]
StarElement: renderQueueEnded [50] [] [0]
StarElement: renderQueueStarted [95] [] [0]
StarElement: renderQueueEnded [95] [] [0]
StarElement: renderQueueStarted [100] [] [0]
StarElement: renderQueueEnded [100] [] [0]
StarElement: Pixel Count: [2084383]
Code: Select all
void StarElement::renderQueueStarted(uint8 queueGroupId, const std::string &invocation, bool &skipThisInvocation)
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
I found an example where the queueGroupId was set at the SceneManager level:
http://www.ogre3d.org/phpBB2/viewtopic. ... euegroupid
Is it possible to set at the SceneNode or BillboardSet or Billboard level?
http://www.ogre3d.org/phpBB2/viewtopic. ... euegroupid
Is it possible to set at the SceneNode or BillboardSet or Billboard level?
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
I don't think HardwareOcclusionQuery works like I pictured.
I set the render queue group.
I enabled the listener:
When the BillboardSet that I'm trying to test is not on the screen, the Pixel Count fluctates up to 1000k. When I'm looking directly at the Billboard set, the Pixel count is 200k. If a mesh goes between the BillboardSet and the camera, I see no effect.
Am I not doing something correctly?
I set the render queue group.
Code: Select all
static unsigned int s_RenderQueueGroup = 11;
m_RenderQueueGroup = s_RenderQueueGroup++;
m_BillboardSet->setRenderQueueGroup(m_RenderQueueGroup);
Code: Select all
GetSceneManager()->addRenderQueueListener(this);
Code: Select all
void StarElement::renderQueueStarted(uint8 queueGroupId, const std::string &invocation, bool &skipThisInvocation)
{
//
// SELECT OUR BILLBOARDSET
//
if (queueGroupId != m_RenderQueueGroup)
{
return;
}
if (m_HardwareOcclusionQuery)
{
m_HardwareOcclusionQuery->beginOcclusionQuery();
}
}
Code: Select all
void StarElement::renderQueueEnded(uint8 queueGroupId, const std::string &invocation, bool &repeatThisInvocation)
{
//
// SELECT OUR BILLBOARDSET
//
if (queueGroupId != m_RenderQueueGroup)
{
return;
}
if (m_HardwareOcclusionQuery)
{
m_HardwareOcclusionQuery->endOcclusionQuery();
m_LastPixelCount = m_PixelCount;
m_HardwareOcclusionQuery->pullOcclusionQuery(&m_PixelCount);
}
}
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
Is it possible to pause the HardwareOcclusionQuery for queueGroupIds that I'm not interested in?
If the queueGroupId isn't desired. In Started I would pause the query and in End I would unpause the query.
With the code snippets above I should only be capturing the queueGroupId but it doesn't seem like it...
Is there an Ogre handy way to get an queueGroupId that isn't already in use?
What are the ranges of acceptable queueGroupIds? (because depending on which one I use the Billboard will disappear or show behind other Billboards)
Will choosing a different queueGroupId affect the rendering order?
If the queueGroupId isn't desired. In Started I would pause the query and in End I would unpause the query.
With the code snippets above I should only be capturing the queueGroupId but it doesn't seem like it...
Is there an Ogre handy way to get an queueGroupId that isn't already in use?
What are the ranges of acceptable queueGroupIds? (because depending on which one I use the Billboard will disappear or show behind other Billboards)
Will choosing a different queueGroupId affect the rendering order?
Last edited by tgraupmann on Tue Nov 28, 2006 7:35 pm, edited 1 time in total.
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
Am I stalling the pipeline and getting bogus results? I'm doing a HardwareOcclusionQuery on several objects, so if I wait a few frames, how will I know which object that I'm getting a Pixel Count for?sinbad wrote:You'd need to use HardwareOcclusionQuery. Bear in mind that you probably want to lag behind a frame or two in pulling the results of the query since they are pipelined elements, and pulling them too early will stall the pipeline.
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
Here is another idea. What if I do the occlusion testing all from renderQueueStarted. First beginOcclusionQuery, render just the queueGroupId, endOcclusionQuery, and then collect the pixel count.
Unfortunately, it seems the Pixel count is still off. For a billboard, the number shouldn't be higher than texture->width times texture->Height. But I'm getting Pixel Counts even when the Billboard is not on the screen.
I know the BillboardSet is the only thing in the queueGroupId.
Code: Select all
void StarElement::renderQueueStarted(uint8 queueGroupId, const std::string &invocation, bool &skipThisInvocation)
{
//
// SELECT OUR BILLBOARDSET
//
if (queueGroupId != m_RenderQueueGroup)
{
return;
}
if (m_HardwareOcclusionQuery)
{
m_HardwareOcclusionQuery->beginOcclusionQuery();
GetSceneManager()->_renderQueueGroupObjects(GetSceneManager()->getRenderQueue()->getQueueGroup(queueGroupId), Ogre::QueuedRenderableCollection::OrganisationMode::OM_PASS_GROUP);
m_HardwareOcclusionQuery->endOcclusionQuery();
///
/// ALREADY RENDERED
///
skipThisInvocation = true;
///
/// GET THE PIXEL COUNT
///
m_LastPixelCount = m_PixelCount;
m_HardwareOcclusionQuery->pullOcclusionQuery(&m_PixelCount);
}
Code: Select all
void StarElement::renderQueueEnded(uint8 queueGroupId, const std::string &invocation, bool &repeatThisInvocation)
{
}
I know the BillboardSet is the only thing in the queueGroupId.
Last edited by tgraupmann on Tue Nov 28, 2006 11:49 pm, edited 2 times in total.
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
I'm seeing one other odd behavior.
The renderQueueStarted for the BillboardSet queueGroupId doesn't start getting called until the Billboard comes into view. Which is expected.
But if the Billboard leaves view, renderQueueStarted for the BillboardSet queueGroupId keeps getting called. I think I'd expect that the callback should not occur when the BillboardSet is out of view.
The renderQueueStarted for the BillboardSet queueGroupId doesn't start getting called until the Billboard comes into view. Which is expected.
But if the Billboard leaves view, renderQueueStarted for the BillboardSet queueGroupId keeps getting called. I think I'd expect that the callback should not occur when the BillboardSet is out of view.
- xavier
- OGRE Retired Moderator
- Posts: 9481
- Joined: Fri Feb 18, 2005 2:03 am
- Location: Dublin, CA, US
- x 22
The docs explain this -- the billboard set will continue rendering for a while after it leaves the view. You can set the amount of time the set will continue to update -- see the API docs for more.
And for the love of God, please stop spamming every topic in the forums since the dawn of Man that remotely mentions HOQ. I'm waiting for you to dredge something up that was written about the time of Ogre 0.10...
And for the love of God, please stop spamming every topic in the forums since the dawn of Man that remotely mentions HOQ. I'm waiting for you to dredge something up that was written about the time of Ogre 0.10...
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
I didn't run across that. The Ogre.CHM is my constant companion. Good feature. I don't see a function on the BillboardSet that can do this. What class/function will allow me to do this?xavier wrote:The docs explain this -- the billboard set will continue rendering for a while after it leaves the view. You can set the amount of time the set will continue to update -- see the API docs for more.
- xavier
- OGRE Retired Moderator
- Posts: 9481
- Joined: Fri Feb 18, 2005 2:03 am
- Location: Dublin, CA, US
- x 22
My bad -- I was thinking ParticleSystem:
http://www.ogre3d.org/docs/api/html/cla ... eSystema37
Like I said in PM, make sure you are calling _updateBounds() when you are done setting up your billboard set, and make sure that the bbox for the set doesn't intersect the frustum (even if no actual bboards are visible).
http://www.ogre3d.org/docs/api/html/cla ... eSystema37
Like I said in PM, make sure you are calling _updateBounds() when you are done setting up your billboard set, and make sure that the bbox for the set doesn't intersect the frustum (even if no actual bboards are visible).
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
I can get the frustum to clip the BillboardSet by doing a:xavier wrote:and make sure that the bbox for the set doesn't intersect the frustum (even if no actual bboards are visible).
Code: Select all
m_BillboardSet->setDefaultDimensions(0, 0);
Unfortunately, this doesn't appear to be the case.
When I can see the Billboard is being clipped, the Pixel count is: 5719714.
I think something deep down in Ogre is broken...
Would it help if I give you a small demo app that illustrates the problem? Or is the source code above enough?
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact:
I wonder if my problem is specific to BillboardSets. Because I was able to get this to work for Plane Entities.tgraupmann wrote:Would it help if I give you a small demo app that illustrates the problem? Or is the source code above enough?
I modified the Samples\Demo_TextureFX\TextureFX.h example source code to do Hardware Occlusion Testing. Here is the source code. It works!
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);
}
// 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();
// 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);
}
};
-
- Gnoll
- Posts: 696
- Joined: Sun Feb 20, 2005 5:28 am
- Contact: