[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