[Orxonox-commit 4779] r9448 - in code/branches/shaders/src/orxonox: . graphics
davidsa at orxonox.net
davidsa at orxonox.net
Wed Nov 14 21:16:19 CET 2012
Author: davidsa
Date: 2012-11-14 21:16:18 +0100 (Wed, 14 Nov 2012)
New Revision: 9448
Modified:
code/branches/shaders/src/orxonox/RenderQueueListener.cc
code/branches/shaders/src/orxonox/RenderQueueListener.h
code/branches/shaders/src/orxonox/Scene.cc
code/branches/shaders/src/orxonox/Scene.h
code/branches/shaders/src/orxonox/graphics/Billboard.cc
code/branches/shaders/src/orxonox/graphics/Billboard.h
code/branches/shaders/src/orxonox/graphics/LensFlare.cc
code/branches/shaders/src/orxonox/graphics/LensFlare.h
Log:
Added Hardware Occlusion Query Capabilities for use in dynamic flare effects, this is still a pretty static implemenation, meaning it will fail with mutltiple HOQ objects on screen, also needs some tidying up and documentation at a later point
Modified: code/branches/shaders/src/orxonox/RenderQueueListener.cc
===================================================================
--- code/branches/shaders/src/orxonox/RenderQueueListener.cc 2012-11-13 16:02:14 UTC (rev 9447)
+++ code/branches/shaders/src/orxonox/RenderQueueListener.cc 2012-11-14 20:16:18 UTC (rev 9448)
@@ -36,14 +36,42 @@
#include <OgreRoot.h>
#include <OgreRenderQueueListener.h>
+#include <OgreHardwareOcclusionQuery.h>
namespace orxonox
{
+ RenderQueueListener::RenderQueueListener() : pixelCount_(0), pixelState_(RenderQueueListener::READY_FOR_RENDER)
+ {
+ hardwareOcclusionQuery_ = Ogre::Root::getSingleton().getRenderSystem()->createHardwareOcclusionQuery(); //create a new HOQ for the scene this listener is used in
+ }
+
+ RenderQueueListener::~RenderQueueListener()
+ {
+ Ogre::Root::getSingleton().getRenderSystem()->destroyHardwareOcclusionQuery(hardwareOcclusionQuery_); //destroy the created HOQ
+ }
+
/**
@brief
+ This function is returning the current pixel count and resets the pixel state if we're ready to do another Hardware Occlusion Query
+
+ @return
+ current pixel count taken from the last Hardware Occlusion Query
+ */
+ unsigned int RenderQueueListener::getPixelCount()
+ {
+ if(this->pixelState_==RenderQueueListener::READY_FOR_ACCESS)
+ {
+ this->hardwareOcclusionQuery_->pullOcclusionQuery(&(this->pixelCount_));
+ this->pixelState_=RenderQueueListener::READY_FOR_RENDER;
+ }
+ return this->pixelCount_;
+ }
+
+ /**
+ @brief
This function is called just before a RenderQueueGroup is rendered, this function is called by Ogre automatically with the correct parameters.
- In this case we use it to set the stencil buffer parameters of the render system
+ In this case we use it to set the stencil buffer parameters of the render system and issue a Hardware Occlusion Query
*/
void RenderQueueListener::renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& skipThisInvocation)
{
@@ -59,12 +87,18 @@
}
if (queueGroupId == RENDER_QUEUE_STENCIL_GLOW)
{
- Ogre::RenderSystem * renderSystem = Ogre::Root::getSingleton().getRenderSystem();
- renderSystem->setStencilCheckEnabled(true);
- renderSystem->setStencilBufferParams(Ogre::CMPF_NOT_EQUAL,
- STENCIL_VALUE_FOR_GLOW, STENCIL_FULL_MASK,
- Ogre::SOP_KEEP,Ogre::SOP_KEEP,Ogre::SOP_REPLACE,false);
+ Ogre::RenderSystem * renderSystem = Ogre::Root::getSingleton().getRenderSystem();
+ renderSystem->setStencilCheckEnabled(true);
+ renderSystem->setStencilBufferParams(Ogre::CMPF_NOT_EQUAL,
+ STENCIL_VALUE_FOR_GLOW, STENCIL_FULL_MASK,
+ Ogre::SOP_KEEP,Ogre::SOP_KEEP,Ogre::SOP_REPLACE,false);
}
+ if (queueGroupId == RENDER_QUEUE_HOQ && this->pixelState_==RenderQueueListener::READY_FOR_RENDER)
+ {
+ this->hardwareOcclusionQuery_->beginOcclusionQuery();
+ this->pixelState_=RenderQueueListener::QUERY_STARTED;
+ //TODO: Skip this rendering step altogheter if we haven't requested the pixel count yet, not sure if this is possible without a custom SceneManager
+ }
}
/**
@@ -81,5 +115,10 @@
renderSystem->setStencilCheckEnabled(false);
renderSystem->setStencilBufferParams();
}
+ if (queueGroupId == RENDER_QUEUE_HOQ && this->pixelState_==RenderQueueListener::QUERY_STARTED)
+ {
+ this->hardwareOcclusionQuery_->endOcclusionQuery();
+ this->pixelState_=RenderQueueListener::READY_FOR_ACCESS;
+ }
}
}
\ No newline at end of file
Modified: code/branches/shaders/src/orxonox/RenderQueueListener.h
===================================================================
--- code/branches/shaders/src/orxonox/RenderQueueListener.h 2012-11-13 16:02:14 UTC (rev 9447)
+++ code/branches/shaders/src/orxonox/RenderQueueListener.h 2012-11-14 20:16:18 UTC (rev 9448)
@@ -38,6 +38,7 @@
#include "OrxonoxPrereqs.h"
#include <OgreRenderQueueListener.h>
+#include <OgreHardwareOcclusionQuery.h>
namespace orxonox
{
@@ -46,7 +47,8 @@
RENDER_QUEUE_MAIN = Ogre::RENDER_QUEUE_MAIN, //reference to the main render queue
RENDER_QUEUE_STENCIL_OBJECTS = RENDER_QUEUE_MAIN+1,
RENDER_QUEUE_STENCIL_GLOW = RENDER_QUEUE_MAIN+2,
- RENDER_QUEUE_STENCIL_LAST = RENDER_QUEUE_STENCIL_GLOW //this is a reference to the last render queue to be affected by stencil glow effects
+ RENDER_QUEUE_STENCIL_LAST = RENDER_QUEUE_STENCIL_GLOW, //this is a reference to the last render queue to be affected by stencil glow effects
+ RENDER_QUEUE_HOQ = RENDER_QUEUE_STENCIL_LAST+1 //this is where we render the objects for occlusion queries (use transparent material)
};
const int STENCIL_VALUE_FOR_GLOW = 1; //!< this is a reference value for our mask,
@@ -64,8 +66,20 @@
class _OrxonoxExport RenderQueueListener : public Ogre::RenderQueueListener
{
public:
+ RenderQueueListener();
+ ~RenderQueueListener();
+
/**
@brief
+ This function is returning the current pixel count and resets the pixel state if we're ready to do another Hardware Occlusion Query
+
+ @return
+ current pixel count taken from the last Hardware Occlusion Query
+ */
+ unsigned int getPixelCount();
+
+ /**
+ @brief
This function is called just before a RenderQueueGroup is rendered, this function is called by Ogre automatically with the correct parameters.
In this case we use it to set the stencil buffer parameters of the render system
@@ -78,6 +92,19 @@
in this case we use it to unset the stencil buffer parameters, so the rest of the render queue is unaffected by it.
*/
virtual void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation);
+
+ private:
+ Ogre::HardwareOcclusionQuery* hardwareOcclusionQuery_; //!< this stores the current instance of the HOQ used in the render system
+ unsigned int pixelCount_; //!< this stores the last pixel count returned by the last HOQ in the corresponding render group
+
+ enum PixelState //!< enum to distinguish the several HOQ pixel count states
+ {
+ READY_FOR_RENDER,
+ QUERY_STARTED,
+ READY_FOR_ACCESS
+ };
+
+ PixelState pixelState_; //!< this stores the current state of the Hardware Occlusion Query
};
}
Modified: code/branches/shaders/src/orxonox/Scene.cc
===================================================================
--- code/branches/shaders/src/orxonox/Scene.cc 2012-11-13 16:02:14 UTC (rev 9447)
+++ code/branches/shaders/src/orxonox/Scene.cc 2012-11-14 20:16:18 UTC (rev 9448)
@@ -77,8 +77,8 @@
assert(Ogre::Root::getSingletonPtr());
this->sceneManager_ = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
this->rootSceneNode_ = this->sceneManager_->getRootSceneNode();
- RenderQueueListener* renderQueueListener = new RenderQueueListener();
- this->sceneManager_->addRenderQueueListener(renderQueueListener);//add our own renderQueueListener
+ this->renderQueueListener_ = new RenderQueueListener();
+ this->sceneManager_->addRenderQueueListener(this->renderQueueListener_);//add our own renderQueueListener
this->radar_ = new Radar();
}
Modified: code/branches/shaders/src/orxonox/Scene.h
===================================================================
--- code/branches/shaders/src/orxonox/Scene.h 2012-11-13 16:02:14 UTC (rev 9447)
+++ code/branches/shaders/src/orxonox/Scene.h 2012-11-14 20:16:18 UTC (rev 9448)
@@ -68,6 +68,8 @@
{ return this->sceneManager_; }
inline Ogre::SceneNode* getRootSceneNode() const
{ return this->rootSceneNode_; }
+ inline RenderQueueListener* getRenderQueueListener() const
+ { return this->renderQueueListener_; }
void setSkybox(const std::string& skybox);
inline const std::string& getSkybox() const
@@ -106,6 +108,7 @@
Ogre::SceneManager* sceneManager_; //!< This is a pointer to the Ogre SceneManager we're using to render the Scene
Ogre::SceneNode* rootSceneNode_; //!< This is a pointer to the root node of the Scene tree
+ RenderQueueListener* renderQueueListener_; //!< this is a pointer to the RenderQueueListener we're using for this Scene
std::string skybox_; //!< This string holds information about the skybox we're using
ColourValue ambientLight_; //!< This variable holds the color value for the ambient light in our scene, usually black in space
Modified: code/branches/shaders/src/orxonox/graphics/Billboard.cc
===================================================================
--- code/branches/shaders/src/orxonox/graphics/Billboard.cc 2012-11-13 16:02:14 UTC (rev 9447)
+++ code/branches/shaders/src/orxonox/graphics/Billboard.cc 2012-11-14 20:16:18 UTC (rev 9448)
@@ -170,4 +170,13 @@
bSet->setDefaultDimensions(width, height);
}
}
+
+ void Billboard::setRenderQueueGroup(unsigned char groupID)
+ {
+ Ogre::BillboardSet* bSet = this->billboard_.getBillboardSet();
+ if( bSet != NULL )
+ {
+ bSet->setRenderQueueGroup(groupID);
+ }
+ }
}
Modified: code/branches/shaders/src/orxonox/graphics/Billboard.h
===================================================================
--- code/branches/shaders/src/orxonox/graphics/Billboard.h 2012-11-13 16:02:14 UTC (rev 9447)
+++ code/branches/shaders/src/orxonox/graphics/Billboard.h 2012-11-14 20:16:18 UTC (rev 9448)
@@ -80,6 +80,8 @@
void setCommonUpVector(Vector3 vec); //!< normalised Vector vec as argument
void setDefaultDimensions(float width, float height);
+
+ void setRenderQueueGroup(unsigned char groupID);
protected:
Modified: code/branches/shaders/src/orxonox/graphics/LensFlare.cc
===================================================================
--- code/branches/shaders/src/orxonox/graphics/LensFlare.cc 2012-11-13 16:02:14 UTC (rev 9447)
+++ code/branches/shaders/src/orxonox/graphics/LensFlare.cc 2012-11-14 20:16:18 UTC (rev 9448)
@@ -37,12 +37,16 @@
#include "core/XMLPort.h"
#include "graphics/Billboard.h"
#include "CameraManager.h"
+#include "RenderQueueListener.h"
+#include <OgreSphere.h>
+#include <OgreRenderWindow.h>
+
namespace orxonox
{
CreateFactory(LensFlare);
- LensFlare::LensFlare(BaseObject* creator) : StaticEntity(creator)
+ LensFlare::LensFlare(BaseObject* creator) : StaticEntity(creator), scale_(1.0f)
{
RegisterObject(LensFlare);
@@ -58,15 +62,23 @@
void LensFlare::XMLPort(Element& xmlelement, XMLPort::Mode mode)
{
SUPER(LensFlare, XMLPort, xmlelement, mode);
+ XMLPortParam(LensFlare, "scale", setScale, getScale, xmlelement, mode).defaultValues(1.0f);
}
void LensFlare::registerVariables()
{
-
+ registerVariable(this->scale_, VariableDirection::ToClient, new NetworkCallback<LensFlare>(this, &LensFlare::updateBillboardPositions));
}
void LensFlare::createBillboards()
{
+ this->occlusionBillboard_ = new Billboard(this);
+ this->occlusionBillboard_->setMaterial("lensflare/hoq");
+ this->occlusionBillboard_->setPosition(this->getPosition());
+ this->occlusionBillboard_->setVisible(false);
+ this->occlusionBillboard_->setRenderQueueGroup(RENDER_QUEUE_HOQ);
+ this->attach(this->occlusionBillboard_);
+
Billboard* burst = new Billboard(this);
burst->setMaterial("lensflare/burst");
burst->setPosition(this->getPosition());
@@ -78,12 +90,17 @@
{
Ogre::Camera* camera=CameraManager::getInstance().getActiveCamera()->getOgreCamera(); //get active Ogre Camera Instance, so we can check whether the light source is visible
bool lightIsVisible=camera->isVisible(this->getPosition()); //is the light source visible from our point of view?
- int scale=camera->getPosition().distance(this->getPosition());
+ this->cameraDistance_=camera->getPosition().distance(this->getPosition());
+ unsigned int dimension=this->cameraDistance_*this->scale_;
- Billboard* burst=static_cast<Billboard*>(getAttachedObject(0));
+ this->occlusionBillboard_->setPosition(this->getPosition());
+ this->occlusionBillboard_->setVisible(lightIsVisible);
+ this->occlusionBillboard_->setDefaultDimensions(dimension,dimension);
+
+ Billboard* burst=static_cast<Billboard*>(getAttachedObject(1));
burst->setPosition(this->getPosition());
burst->setVisible(lightIsVisible);
- burst->setDefaultDimensions(scale,scale);
+ burst->setDefaultDimensions(dimension,dimension);
}
void LensFlare::tick(float dt)
@@ -91,6 +108,25 @@
if(this->isVisible())
{
updateBillboardPositions();
+ if(this->occlusionBillboard_->isVisible()) {
+ unsigned int dimension=this->cameraDistance_*this->scale_;
+ Ogre::Sphere* sphere=new Ogre::Sphere(this->getPosition(),dimension*0.25);
+ Ogre::Camera* camera=CameraManager::getInstance().getActiveCamera()->getOgreCamera();
+ float left, right, top, bottom;
+ camera->projectSphere(*sphere,&left,&top,&right,&bottom);//approximate maximum pixel count of billboard with a sphere
+ delete sphere;
+
+ Ogre::RenderWindow* window = GraphicsManager::getInstance().getRenderWindow();
+ float maxCount=(right-left)*(top-bottom)*window->getWidth()*window->getHeight()*0.25;
+ float pixelCount=this->getScene()->getRenderQueueListener()->getPixelCount();//get pixel count
+ float ratio=pixelCount/maxCount;
+ //orxout() << "maxCount: " << maxCount << " HOQ: " << pixelCount << " ratio: " << ratio << std::endl;
+ ColourValue* colour = new ColourValue(1.0f,1.0f,1.0f,ratio); //adjust alpha of billboard
+
+ Billboard* burst=static_cast<Billboard*>(getAttachedObject(1));
+ burst->setColour(*colour);
+ delete colour;
+ }
}
}
Modified: code/branches/shaders/src/orxonox/graphics/LensFlare.h
===================================================================
--- code/branches/shaders/src/orxonox/graphics/LensFlare.h 2012-11-13 16:02:14 UTC (rev 9447)
+++ code/branches/shaders/src/orxonox/graphics/LensFlare.h 2012-11-14 20:16:18 UTC (rev 9448)
@@ -39,6 +39,7 @@
#include "OgreBillboardSet.h"
+#include "core/GraphicsManager.h"
#include "util/Math.h"
#include "worldentities/StaticEntity.h"
#include "graphics/Billboard.h"
@@ -53,11 +54,20 @@
@author
David 'davidsa' Salvisberg
*/
+ //TODO: The Hardware Occlusion only works properly for a single Flare on the screen,
+ // if we have multiple strong lights it'll become way more complicated to determine how much of every object is occluded individually
+ // there's below a 100 render queue groups, so maybe we should take turns for each object to be tested, so we only have one of the objects rendered at a time
+ // obviously we shouldn't use too much of these effects anyways, since they use a lot of performance, so not sure whether it's worth implementing a solution that works for multiple lens flares on screen
class _OrxonoxExport LensFlare : public StaticEntity, public Tickable
{
public:
LensFlare(BaseObject* creator);
virtual ~LensFlare();
+
+ inline void setScale(float scale)
+ { this->scale_=scale; }
+ inline float getScale()
+ { return this->scale_; }
virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
@@ -71,6 +81,10 @@
void createBillboards();
void updateBillboardPositions();
+
+ Billboard* occlusionBillboard_;
+ unsigned int cameraDistance_;
+ float scale_;
};
}
More information about the Orxonox-commit
mailing list