Hardware Occlusion Culling - Occlusion Query for Irrlicht

Announce new projects or updates of Irrlicht Engine related tools, games, and applications.
Also check the Wiki

Hardware Occlusion Culling - Occlusion Query for Irrlicht

Postby Nadro » Tue Aug 12, 2008 9:15 am

Hi, This is occlusion query example for Irrlicht (support Direct3D9 and OpenGL modes). For query test I use normal Hi-Poly meshes, so FPS results isn't so good, but in next release I will use Bounding meshes for Occlusion Query Pass and FPS will be better. This culling is very useful for large levels.

First pre alpha demo for D3D9 / OpenGL from (only binaries):
http://rapidshare.com/files/136728949/OcclusionQuery.zip

Pre builded Irrlicht (rev 1498) with Occlusion Query support and example demo of usage it with source code:
http://rapidshare.com/files/137400230/OcclusionQuery_Binary_Rev1498.zip

Patches for update Irrlicht (rev 1498) to support Occlusion Query:
http://nadro.net46.net/Patches/Occlusio ... 1498.patch
http://nadro.net46.net/Patches/Occlusio ... 1498.patch
Last edited by Nadro on Fri Aug 15, 2008 12:51 pm, edited 2 times in total.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Nadro
 
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Postby JP » Tue Aug 12, 2008 9:24 am

There's quite a delay before it seems the cull is done on the little elephant... or is it just updating the stats every second instead of every frame?

By using bounding meshes do you mean just using a bounding box? And is that the bounding box of the mesh doing the blocking? That wouldn't work very well obviously due to the elephant (and many other) mesh not being an actual box. Or do you mean you'd do bounding box tests first and then the high poly tests?

Maybe you could provide a lower poly version of the elephant for doing the tests on, but that would have to fit completely within the high poly elephant for it to not give inaccurate results.....
Image Image Image
User avatar
JP
 
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK

Postby Nadro » Tue Aug 12, 2008 9:36 am

Stats are update only when FPS are change, so this delay is not true, all is ok for it. Bounding meshes is very low poly mesh of object (all elements of it can't be higher than orginal elements of Hi Poly mesh)
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Nadro
 
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Postby JP » Tue Aug 12, 2008 9:38 am

Sounds good then! Hopefully this can improve performance for a lot of people!
Image Image Image
User avatar
JP
 
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK

Postby Nadro » Thu Aug 14, 2008 11:41 pm

Hi, I made first version of Irrlicht interface for functions usage in Hardware Occlusion Query (support Direct3D9 and OpenGL):
Code: Select all
//! Create query. Get node for identification query and bounding mesh for occlusion test.
void createQuery( scene::ISceneNode* vNode, scene::IMesh* vMesh );

//! Remove query.
void removeQuery( scene::ISceneNode* vNode );

//! Remove all queries.
void removeAllQueries();

//! Run query. Draw a mesh stored in query.
void runQuery( scene::ISceneNode* vNode );


//! Run all queries. Draw all meshes stored in all queries.
void runAllQueries();

//! Return query result.
int getQueryResult( scene::ISceneNode* vNode );

And small and easy, usefull function for clean buffers:
Code: Select all
//! Clears BackBuffer and/or ZBuffer.
void clearBuffers(bool backBuffer, bool zBuffer, SColor color);


I created *.patch files for update Irrlicht to support Hardware Occlusion Query (tested with the latest rev 1498), and I release package with precompiled Irrlicht r1498 with Occlusion Query support and example demo with source. I add links for it in first post.

Source code of example demo:
Code: Select all
#include <irrlicht.h>
#include <iostream>

using namespace irr;

using namespace core;
using namespace scene;
using namespace video;

int main()
{
    E_DRIVER_TYPE driverType;

   printf("Please select the driver you want for this example:\n"\
      " (a) Direct3D 9.0c\n (b) OpenGL 1.5\n (otherKey) exit\n\n");

    char i;
   std::cin >> i;

   switch(i)
   {
      case 'a': driverType = EDT_DIRECT3D9;break;
      case 'b': driverType = EDT_OPENGL;break;
      default: return 1;
   }

    IrrlichtDevice* device = createDevice( driverType, dimension2d<s32>(800, 600), 32,false, false, false, 0);

   IVideoDriver* driver = device->getVideoDriver();
   ISceneManager* smgr = device->getSceneManager();

   IMesh* mesh = smgr->getMesh("elephant.obj")->getMesh(0);
   IMeshSceneNode* node1 = smgr->addMeshSceneNode( mesh );
   IMeshSceneNode* node2 = smgr->addMeshSceneNode( mesh );

   if (node1)
   {
      node1->setMaterialFlag(EMF_LIGHTING, false);
      node1->setMaterialTexture( 0, driver->getTexture("red.jpg") );

      node1->setPosition(vector3df(0,0,0));
        node1->setScale(vector3df(1,1,1));
        node1->setOcclusionCulling( true ); // Activate occlusion query test for node1, If You need manualy hide node eg. for LOD, You have to disable it, because OC automatic set node1->setVisible(false/true); You can disable/enable OC in each momment.
        driver->createQuery(node1, mesh); // Create query for node1; in query test we will use standard hi poly mesh, because I don't have low poly bounding mesh for it.

   }

   if (node2)
   {
      node2->setMaterialFlag(EMF_LIGHTING, false);
      node2->setMaterialTexture( 0, driver->getTexture("blue.jpg") );

      node2->setPosition(vector3df(0,0,40));
        node2->setScale(vector3df(0.1,0.1,0.1));
        node2->setOcclusionCulling( true );
        driver->createQuery(node2, mesh);
   }

   ICameraSceneNode* cam = smgr->addCameraSceneNodeFPS();
   cam->setPosition(vector3df(100,0,60));
   cam->setTarget(vector3df(3,0,37));

   int lastFPS = -1;
    SColor Color = SColor(255,100,101,140);

   while(device->run())
   {
      driver->beginScene(true, true, Color);

      // *** Occlusion Query Pass *** //

      // At first we have to render transformed camera
      cam->OnRegisterSceneNode();
        cam->OnAnimate(device->getTimer()->getTime());
        cam->render();

      driver->runAllQueries(); // Run all occlusion queries test, if node has got 'setOcclusionCulling(0)' is skipping in this test, if object is occluded: node1->setVisible(0); if not: node1->setVisible(1);

      // driver->runQuery(node1); // this is alternative run query method for node1
        // driver->runQuery(node2);

      driver->clearBuffers(true,true,Color); // We can clear BackBuffer and ZBuffer after OC Pass

      // *** End of Occlusion Query Pass *** //

      if(lastFPS == -1)
      cam->setTarget(vector3df(3,0,37)); // Set camera target in first frame

      smgr->drawAll();

      driver->endScene();

      int tris = driver->getPrimitiveCountDrawn();
      int fps = driver->getFPS();

      if (lastFPS != fps)
      {
         core::stringw str = L"Occlusion Query Demo FPS: ";
         str += fps;
         str += " Tris: ";
         str += tris;
         str += " Node 1 fragments: ";
         str += driver->getQueryResult(node1); // get visible fragments count for node
         str += " Node 2 fragments: ";
         str += driver->getQueryResult(node2);

         device->setWindowCaption(str.c_str());
         lastFPS = fps;
      }
   }
   driver->removeAllQueries(); // Remove All Queries
   // driver->removeQuery(node1); // this is alternative remove query method for node1
   // driver->removeQuery(node2);

   device->drop();

   return 0;
}


I'm waiting for Your comments and suggestions.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Nadro
 
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Postby wyrmmage » Fri Aug 15, 2008 3:36 am

that was a massive quintuple post! :D

Looks cool...I'll definitely be bookmarking this :)
-wyrmmage
Worlds at War (Current Project) - http://www.awkward-games.com
Ganadu'r, The Eternal Sage (Other Current Project) - http://rpg.naget.com
User avatar
wyrmmage
 
Posts: 204
Joined: Sun Mar 16, 2008 3:12 am

Postby JP » Fri Aug 15, 2008 7:49 am

lmao... everyone's being fooled by the debug messages
Image Image Image
User avatar
JP
 
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK

Postby Nadro » Fri Aug 15, 2008 12:42 pm

Ehh, when I submit my post I see error message from phpBB, so I don't update first post because I think than my post isn't submited, but now I see than this error is joke:D OK, links are ready in first post.

BTW. I forgot add in this release EAC_BOX frustum culling test in query test, but I add it in the next release.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Nadro
 
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Postby full.metal.coder » Tue Aug 26, 2008 11:47 am

Link broken, please fix it (preferably with a more up to date version of your code).

I might be able to go beyond 500fps on The First King test level with proper occlusion culling... :D
full.metal.coder
 
Posts: 68
Joined: Sat May 10, 2008 11:30 am

Postby Nadro » Tue Aug 26, 2008 12:23 pm

Hi full.metal.coder,

Yes, server has got problems... and links are broken. Yes, I use in my engine this oc code with bounding meshes and I have got big speed up of my project. You have to manualy add to this source EAC_BOX frustum culling test eg. from CSceneManager.cpp (and put it in query test), because I forgot about this usefull stuff in this version.

I don't have access to stable server so I put code here:

OcclusionQuery_Include_Rev1498.patch
Code: Select all
Index: ISceneNode.h
===================================================================
--- ISceneNode.h   (revision 1498)
+++ ISceneNode.h   (working copy)
@@ -44,7 +44,8 @@
          : RelativeTranslation(position), RelativeRotation(rotation), RelativeScale(scale),
             Parent(0), ID(id), SceneManager(mgr), TriangleSelector(0),
             AutomaticCullingState(EAC_BOX), IsVisible(true),
-            DebugDataVisible(EDS_OFF), IsDebugObject(false)
+            DebugDataVisible(EDS_OFF), IsDebugObject(false),
+            QueryPosition(-1), IsOcclusionCulling(0)
       {
          if (parent)
             parent->addChild(this);
@@ -663,6 +664,31 @@
          return 0; // to be implemented by derived classes
       }
 
+      //! Set position on Qcclusion Query list.
+      void setQueryPosition( int vPosition )
+      {
+         if(vPosition >= 0)
+         QueryPosition = vPosition;
+      }
+
+      //! Get position on Qcclusion Query list.
+      int getQueryPosition()
+      {
+         return QueryPosition;
+      }
+
+      //! Set occlusion status.
+      void setOcclusionCulling( bool Value )
+      {
+         IsOcclusionCulling = Value;
+      }
+
+      //! Get occlusion status.
+      bool getOcclusionCulling()
+      {
+         return IsOcclusionCulling;
+      }
+
    protected:
 
       //! A clone function for the ISceneNode members.
@@ -753,6 +779,12 @@
 
       //! Is debug object?
       bool IsDebugObject;
+
+      //! Position on Qcclusion Query list.
+      int QueryPosition;
+
+      //! Is occluded?
+      bool IsOcclusionCulling;
    };
 
 } // end namespace scene
@@ -760,3 +792,4 @@
 
 #endif
 
+
Index: IVideoDriver.h
===================================================================
--- IVideoDriver.h   (revision 1498)
+++ IVideoDriver.h   (working copy)
@@ -25,11 +25,14 @@
 {
    class IAttributes;
    class IReadFile;
+   class ISceneNode;
 } // end namespace io
 namespace scene
 {
    class IMeshBuffer;
    class IMeshManipulator;
+   class IMesh;
+   class ISceneNode;
 } // end namespace scene
 
 namespace video
@@ -917,6 +920,9 @@
       */
       virtual void clearZBuffer() = 0;
 
+      //! Clears BackBuffer and/or ZBuffer.
+      virtual void clearBuffers(bool backBuffer, bool zBuffer, SColor color) = 0;
+
       //! Make a screenshot of the last rendered frame.
       /** \return An image created from the last rendered frame. */
       virtual IImage* createScreenShot() = 0;
@@ -957,6 +963,24 @@
       //! Returns the graphics card vendor name.
       virtual core::stringc getVendorInfo() = 0;
 
+      //! Create query. Get node for identification query and bounding mesh for occlusion test.
+      virtual void createQuery( scene::ISceneNode* vNode, scene::IMesh* vMesh ) = 0;
+
+      //! Remove query.
+      virtual void removeQuery( scene::ISceneNode* vNode ) = 0;
+
+      //! Remove all queries.
+      virtual void removeAllQueries() = 0;
+
+      //! Run query. Draw a mesh stored in query.
+      virtual void runQuery( scene::ISceneNode* vNode ) = 0;
+
+      //! Run all queries. Draw all meshes stored in all queries.
+      virtual void runAllQueries() = 0;
+
+      //! Return query result.
+      virtual int getQueryResult( scene::ISceneNode* vNode ) = 0;
+
    };
 
 } // end namespace video


OcclusionQuery_Source_Rev1498.patch
Code: Select all
Index: CD3D9Driver.cpp
===================================================================
--- CD3D9Driver.cpp   (revision 1498)
+++ CD3D9Driver.cpp   (working copy)
@@ -2410,6 +2410,26 @@
 }
 
 
+//! Clears BackBuffer and/or ZBuffer.
+void CD3D9Driver::clearBuffers(bool backBuffer, bool zBuffer, SColor color)
+{
+   if (backBuffer || zBuffer)
+   {
+      DWORD flags = 0;
+
+      if (backBuffer)
+         flags |= D3DCLEAR_TARGET;
+
+      if (zBuffer)
+         flags |= D3DCLEAR_ZBUFFER;
+
+      HRESULT hr = pID3DDevice->Clear( 0, NULL, flags, color.color, 1.0, 0);
+      if (FAILED(hr))
+         os::Printer::log("CD3D9Driver clearBuffers() failed.", ELL_WARNING);
+   }
+}
+
+
 //! Returns an image created from the last rendered frame.
 IImage* CD3D9Driver::createScreenShot()
 {
@@ -2519,6 +2539,147 @@
 }
 
 
+//! Create query.
+void CD3D9Driver::createQuery( scene::ISceneNode* vNode, scene::IMesh* vMesh )
+{
+   if(!vNode || !vMesh)
+   return;
+
+   if(vNode->getQueryPosition() != -1)
+   return;
+
+   int Position = Query.size();
+   vNode->setQueryPosition(Position);
+
+   Query.push_back(0);
+   QueryResult.push_back(0);
+   QueryNode.push_back(vNode);
+   QueryMesh.push_back(vMesh);
+
+   pID3DDevice->CreateQuery( D3DQUERYTYPE_OCCLUSION, &Query[Position] );
+}
+
+//! Remove query.
+void CD3D9Driver::removeQuery( scene::ISceneNode* vNode )
+{
+   if(!vNode)
+   return;
+
+   int Position = vNode->getQueryPosition();
+
+   if(Position == -1)
+   return;
+
+   for(int current = Position + 1; current < Query.size(); current++)
+   {
+      QueryNode[current]->setQueryPosition(QueryNode[current]->getQueryPosition() - 1);
+   }
+
+   if( Query[Position] != NULL )
+   Query[Position]->Release();
+
+   Query.erase(Position);
+   QueryResult.erase(Position);
+   QueryNode.erase(Position);
+   QueryMesh.erase(Position);
+}
+
+//! Remove all queries.
+void CD3D9Driver::removeAllQueries()
+{
+   for(int current = 0; current < Query.size(); current++)
+   {
+      if( Query[current] != NULL )
+      Query[current]->Release();
+   }
+
+   Query.clear();
+   QueryResult.clear();
+   QueryNode.clear();
+   QueryMesh.clear();
+}
+
+//! Run query.
+void CD3D9Driver::runQuery( scene::ISceneNode* vNode )
+{
+   if(!vNode)
+   return;
+
+   int Position = vNode->getQueryPosition();
+
+   if(Position == -1)
+   return;
+
+   if(QueryNode[Position]->getOcclusionCulling() && QueryMesh[Position])
+   {
+      setTransform(video::ETS_WORLD, QueryNode[Position]->getRelativeTransformation());
+      Query[Position]->Issue( D3DISSUE_BEGIN );
+      {
+         for(int current = 0; current < QueryMesh[Position]->getMeshBufferCount(); current++)
+         drawMeshBuffer(QueryMesh[Position]->getMeshBuffer(current));
+      }
+      Query[Position]->Issue( D3DISSUE_END );
+
+      while( Query[Position]->GetData( (void*)&QueryResult[Position], sizeof(DWORD), D3DGETDATA_FLUSH) == S_FALSE )
+      {
+      }
+
+      if(QueryResult[Position] < 1)
+      {
+         QueryNode[Position]->setVisible(false);
+      }
+      else
+      {
+         QueryNode[Position]->setVisible(true);
+      }
+   }
+}
+
+//! Run all queries.
+void CD3D9Driver::runAllQueries()
+{
+   for(int current = 0; current < Query.size(); current++)
+   {
+      if(QueryNode[current])
+      {
+         if(QueryNode[current]->getOcclusionCulling() && QueryMesh[current])
+         {
+            setTransform(video::ETS_WORLD, QueryNode[current]->getRelativeTransformation());
+            Query[current]->Issue( D3DISSUE_BEGIN );
+            {
+               for(int scurrent = 0; scurrent < QueryMesh[current]->getMeshBufferCount(); scurrent++)
+               drawMeshBuffer(QueryMesh[current]->getMeshBuffer(scurrent));
+            }
+            Query[current]->Issue( D3DISSUE_END );
+
+            while( Query[current]->GetData( (void*)&QueryResult[current], sizeof(DWORD), D3DGETDATA_FLUSH) == S_FALSE )
+            {
+            }
+
+            if(QueryResult[current] < 1)
+            {
+               QueryNode[current]->setVisible(false);
+            }
+            else
+            {
+               QueryNode[current]->setVisible(true);
+            }
+         }
+      }
+   }
+}
+
+//! Return query result.
+int CD3D9Driver::getQueryResult( scene::ISceneNode* vNode )
+{
+   if(!vNode)
+   return -1;
+
+   int Position = vNode->getQueryPosition();
+   return QueryResult[Position];
+}
+
+
 } // end namespace video
 } // end namespace irr
 
Index: CD3D9Driver.h
===================================================================
--- CD3D9Driver.h   (revision 1498)
+++ CD3D9Driver.h   (working copy)
@@ -202,6 +202,9 @@
       //! Clears the ZBuffer.
       virtual void clearZBuffer();
 
+      //! Clears BackBuffer and/or ZBuffer.
+      virtual void clearBuffers(bool backBuffer, bool zBuffer, SColor color);
+
       //! Returns an image created from the last rendered frame.
       virtual IImage* createScreenShot();
 
@@ -221,6 +224,25 @@
       //! Returns the graphics card vendor name.
       virtual core::stringc getVendorInfo() {return vendorName;};
 
+      //! Create query.
+      virtual void createQuery( scene::ISceneNode* vNode, scene::IMesh* vMesh );
+
+      //! Remove query.
+      virtual void removeQuery( scene::ISceneNode* vNode );
+
+      //! Remove all queries.
+      virtual void removeAllQueries();
+
+      //! Run query.
+      virtual void runQuery( scene::ISceneNode* vNode );
+
+      //! Run all queries.
+      virtual void runAllQueries();
+
+      //! Return query result.
+      virtual int getQueryResult( scene::ISceneNode* vNode );
+
+
    private:
 
       // enumeration for rendering modes such as 2d and 3d for minizing the switching of renderStates.
@@ -326,6 +348,11 @@
       SColorf AmbientLight;
 
       core::stringc vendorName;
+
+      core::array<IDirect3DQuery9*> Query;
+      core::array<int> QueryResult;
+      core::array<scene::ISceneNode*> QueryNode;
+      core::array<scene::IMesh*> QueryMesh;
    };
 
 
Index: CNullDriver.cpp
===================================================================
--- CNullDriver.cpp   (revision 1498)
+++ CNullDriver.cpp   (working copy)
@@ -1813,6 +1813,11 @@
 }
 
 
+void CNullDriver::clearBuffers(bool backBuffer, bool zBuffer, SColor color)
+{
+}
+
+
 //! Returns a pointer to the mesh manipulator.
 scene::IMeshManipulator* CNullDriver::getMeshManipulator()
 {
@@ -1871,7 +1876,38 @@
    // not necessary
 }
 
+//! Create query.
+void CNullDriver::createQuery( scene::ISceneNode* vNode, scene::IMesh* vMesh )
+{
+}
 
+//! Remove query.
+void CNullDriver::removeQuery( scene::ISceneNode* vNode )
+{
+}
+
+//! Remove all queries.
+void CNullDriver::removeAllQueries()
+{
+}
+
+//! Run query.
+void CNullDriver::runQuery( scene::ISceneNode* vNode )
+{
+}
+
+//! Run all queries.
+void CNullDriver::runAllQueries()
+{
+}
+
+//! Return query result.
+int CNullDriver::getQueryResult( scene::ISceneNode* vNode )
+{
+   return -1;
+}
+
+
 } // end namespace
 } // end namespace
 
Index: CNullDriver.h
===================================================================
--- CNullDriver.h   (revision 1498)
+++ CNullDriver.h   (working copy)
@@ -14,6 +14,8 @@
 #include "irrMap.h"
 #include "IAttributes.h"
 #include "IMeshBuffer.h"
+#include "IMesh.h"
+#include "ISceneNode.h"
 #include "CFPSCounter.h"
 #include "S3DVertex.h"
 #include "SLight.h"
@@ -456,6 +458,9 @@
       //! Clears the ZBuffer.
       virtual void clearZBuffer();
 
+      //! Clears BackBuffer and/or ZBuffer.
+      virtual void clearBuffers(bool backBuffer, bool zBuffer, SColor color);
+
       //! Returns an image created from the last rendered frame.
       virtual IImage* createScreenShot();
 
@@ -490,6 +495,24 @@
       //! Returns the graphics card vendor name.
       virtual core::stringc getVendorInfo() {return "Not available on this driver.";};
 
+      //! Create query.
+      virtual void createQuery( scene::ISceneNode* vNode, scene::IMesh* vMesh );
+
+      //! Remove query.
+      virtual void removeQuery( scene::ISceneNode* vNode );
+
+      //! Remove all queries.
+      virtual void removeAllQueries();
+
+      //! Run query.
+      virtual void runQuery( scene::ISceneNode* vNode );
+
+      //! Run all queries.
+      virtual void runAllQueries();
+
+      //! Return query result.
+      virtual int getQueryResult( scene::ISceneNode* vNode );
+
    protected:
 
       //! deletes all textures
Index: COpenGLDriver.cpp
===================================================================
--- COpenGLDriver.cpp   (revision 1498)
+++ COpenGLDriver.cpp   (working copy)
@@ -2603,6 +2603,33 @@
 }
 
 
+//! Clears BackBuffer and/or ZBuffer.
+void COpenGLDriver::clearBuffers(bool backBuffer, bool zBuffer, SColor color)
+{
+   if (backBuffer || zBuffer)
+   {
+      GLbitfield mask = 0;
+
+      if (backBuffer)
+      {
+         const f32 inv = 1.0f / 255.0f;
+         glClearColor(color.getRed() * inv, color.getGreen() * inv,
+               color.getBlue() * inv, color.getAlpha() * inv);
+
+         mask |= GL_COLOR_BUFFER_BIT;
+      }
+
+      if (zBuffer)
+      {
+         glDepthMask(GL_TRUE);
+         mask |= GL_DEPTH_BUFFER_BIT;
+      }
+
+      glClear(mask);
+   }
+}
+
+
 //! Returns an image created from the last rendered frame.
 IImage* COpenGLDriver::createScreenShot()
 {
@@ -2707,6 +2734,141 @@
 }
 
 
+//! Create query.
+void COpenGLDriver::createQuery( scene::ISceneNode* vNode, scene::IMesh* vMesh )
+{
+   if(!vNode || !vMesh)
+   return;
+
+   if(vNode->getQueryPosition() != -1)
+   return;
+
+   int Position = Query.size();
+   vNode->setQueryPosition(Position);
+
+   Query.push_back(0);
+   QueryResult.push_back(0);
+   QueryNode.push_back(vNode);
+   QueryMesh.push_back(vMesh);
+
+   extGlGenQueries( 1, &Query[Position] );
+}
+
+//! Remove query.
+void COpenGLDriver::removeQuery( scene::ISceneNode* vNode )
+{
+   if(!vNode)
+   return;
+
+   int Position = vNode->getQueryPosition();
+
+   if(Position == -1)
+   return;
+
+   for(int current = Position + 1; current < Query.size(); current++)
+   {
+      QueryNode[current]->setQueryPosition(QueryNode[current]->getQueryPosition() - 1);
+   }
+
+   extGlDeleteQueries( 1, &Query[Position] );
+
+   Query.erase(Position);
+   QueryResult.erase(Position);
+   QueryNode.erase(Position);
+   QueryMesh.erase(Position);
+}
+
+//! Remove all queries.
+void COpenGLDriver::removeAllQueries()
+{
+   for(int current = 0; current < Query.size(); current++)
+   {
+      extGlDeleteQueries( 1, &Query[current] );
+   }
+
+   Query.clear();
+   QueryResult.clear();
+   QueryNode.clear();
+   QueryMesh.clear();
+}
+
+//! Run query.
+void COpenGLDriver::runQuery( scene::ISceneNode* vNode )
+{
+   if(!vNode)
+   return;
+
+   int Position = vNode->getQueryPosition();
+
+   if(Position == -1)
+   return;
+
+   if(QueryNode[Position]->getOcclusionCulling() && QueryMesh[Position])
+   {
+      setTransform(video::ETS_WORLD, QueryNode[Position]->getRelativeTransformation());
+      extGlBeginQuery( GL_SAMPLES_PASSED_ARB, Query[Position] );
+      {
+         for(int current = 0; current < QueryMesh[Position]->getMeshBufferCount(); current++)
+         drawMeshBuffer(QueryMesh[Position]->getMeshBuffer(current));
+      }
+      extGlEndQuery( GL_SAMPLES_PASSED_ARB );
+
+      extGlGetQueryObjectuiv( Query[Position], GL_QUERY_RESULT_ARB, (GLuint*)&QueryResult[Position] );
+
+      if(QueryResult[Position] < 1)
+      {
+         QueryNode[Position]->setVisible(false);
+      }
+      else
+      {
+         QueryNode[Position]->setVisible(true);
+      }
+   }
+}
+
+//! Run all queries.
+void COpenGLDriver::runAllQueries()
+{
+   for(int current = 0; current < Query.size(); current++)
+   {
+      if(QueryNode[current])
+      {
+         if(QueryNode[current]->getOcclusionCulling() && QueryMesh[current])
+         {
+            setTransform(video::ETS_WORLD, QueryNode[current]->getRelativeTransformation());
+            extGlBeginQuery( GL_SAMPLES_PASSED_ARB, Query[current] );
+            {
+               for(int scurrent = 0; scurrent < QueryMesh[current]->getMeshBufferCount(); scurrent++)
+               drawMeshBuffer(QueryMesh[current]->getMeshBuffer(scurrent));
+            }
+            extGlEndQuery( GL_SAMPLES_PASSED_ARB );
+
+            extGlGetQueryObjectuiv( Query[current], GL_QUERY_RESULT_ARB, (GLuint*)&QueryResult[current] );
+
+            if(QueryResult[current] < 1)
+            {
+               QueryNode[current]->setVisible(false);
+            }
+            else
+            {
+               QueryNode[current]->setVisible(true);
+            }
+         }
+      }
+   }
+}
+
+//! Return query result.
+int COpenGLDriver::getQueryResult( scene::ISceneNode* vNode )
+{
+   if(!vNode)
+   return -1;
+
+   int Position = vNode->getQueryPosition();
+   return QueryResult[Position];
+}
+
+
 } // end namespace
 } // end namespace
 
Index: COpenGLDriver.h
===================================================================
--- COpenGLDriver.h   (revision 1498)
+++ COpenGLDriver.h   (working copy)
@@ -307,6 +307,9 @@
       //! Clears the ZBuffer.
       virtual void clearZBuffer();
 
+      //! Clears BackBuffer and/or ZBuffer.
+      virtual void clearBuffers(bool backBuffer, bool zBuffer, SColor color);
+
       //! Returns an image created from the last rendered frame.
       virtual IImage* createScreenShot();
 
@@ -330,6 +333,24 @@
       //! Returns the graphics card vendor name.
       virtual core::stringc getVendorInfo() {return vendorName;};
 
+      //! Create query.
+      virtual void createQuery( scene::ISceneNode* vNode, scene::IMesh* vMesh );
+
+      //! Remove query.
+      virtual void removeQuery( scene::ISceneNode* vNode );
+
+      //! Remove all queries.
+      virtual void removeAllQueries();
+
+      //! Run query.
+      virtual void runQuery( scene::ISceneNode* vNode );
+
+      //! Run all queries.
+      virtual void runAllQueries();
+
+      //! Return query result.
+      virtual int getQueryResult( scene::ISceneNode* vNode );
+
    private:
 
       void uploadClipPlane(u32 index);
@@ -392,6 +413,11 @@
       //! Color buffer format
       ECOLOR_FORMAT ColorFormat;
 
+      core::array<GLuint> Query;
+      core::array<int> QueryResult;
+      core::array<scene::ISceneNode*> QueryNode;
+      core::array<scene::IMesh*> QueryMesh;
+
       #ifdef _IRR_WINDOWS_API_
          HDC HDc; // Private GDI Device Context
          HWND Window;
Index: COpenGLExtensionHandler.cpp
===================================================================
--- COpenGLExtensionHandler.cpp   (revision 1498)
+++ COpenGLExtensionHandler.cpp   (working copy)
@@ -47,7 +47,9 @@
    pGlRenderbufferStorageEXT(0), pGlFramebufferRenderbufferEXT(0),
    pGlGenBuffersARB(0), pGlBindBufferARB(0), pGlBufferDataARB(0), pGlDeleteBuffersARB(0),
    pGlBufferSubDataARB(0), pGlGetBufferSubDataARB(0), pGlMapBufferARB(0), pGlUnmapBufferARB(0),
-   pGlIsBufferARB(0), pGlGetBufferParameterivARB(0), pGlGetBufferPointervARB(0)
+   pGlIsBufferARB(0), pGlGetBufferParameterivARB(0), pGlGetBufferPointervARB(0),
+   pGlGenQueriesARB(0), pGlDeleteQueriesARB(0), pGlIsQueryARB(0), pGlBeginQueryARB(0), pGlEndQueryARB(0),
+   pGlGetQueryivARB(0), pGlGetQueryObjectivARB(0), pGlGetQueryObjectuivARB(0)
 
 
 #endif // _IRR_OPENGL_USE_EXTPOINTER_
@@ -177,6 +179,15 @@
    pGlGetBufferParameterivARB= (PFNGLGETBUFFERPARAMETERIVARBPROC) wglGetProcAddress("glGetBufferParameterivARB");
    pGlGetBufferPointervARB= (PFNGLGETBUFFERPOINTERVARBPROC) wglGetProcAddress("glGetBufferPointervARB");
 
+   // occlusion query
+   pGlGenQueriesARB = (PFNGLGENQUERIESARBPROC) wglGetProcAddress("glGenQueriesARB");
+   pGlDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC) wglGetProcAddress("glDeleteQueriesARB");
+   pGlIsQueryARB = (PFNGLISQUERYARBPROC) wglGetProcAddress("glIsQueryARB");
+   pGlBeginQueryARB = (PFNGLBEGINQUERYARBPROC) wglGetProcAddress("glBeginQueryARB");
+   pGlEndQueryARB = (PFNGLENDQUERYARBPROC) wglGetProcAddress("glEndQueryARB");
+   pGlGetQueryivARB = (PFNGLGETQUERYIVARBPROC) wglGetProcAddress("glGetQueryivARB");
+   pGlGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC) wglGetProcAddress("glGetQueryObjectivARB");
+   pGlGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC) wglGetProcAddress("glGetQueryObjectuivARB");
 
    // vsync extension
    wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC) wglGetProcAddress("wglSwapIntervalEXT");
@@ -384,8 +395,32 @@
 
    pGlGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)
    IRR_OGL_LOAD_EXTENSION(reinterpret_cast<const GLubyte*>("glGetBufferPointervARB"));
+
+   pGlGenQueriesARB = (PFNGLGENQUERIESARBPROC)
+   IRR_OGL_LOAD_EXTENSION(reinterpret_cast<const GLubyte*>("glGenQueriesARB"));
+
+   pGlDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC)
+   IRR_OGL_LOAD_EXTENSION(reinterpret_cast<const GLubyte*>("glDeleteQueriesARB"));
 
+   pGlIsQueryARB = (PFNGLISQUERYARBPROC)
+   IRR_OGL_LOAD_EXTENSION(reinterpret_cast<const GLubyte*>("glIsQueryARB"));
 
+   pGlBeginQueryARB = (PFNGLBEGINQUERYARBPROC)
+   IRR_OGL_LOAD_EXTENSION(reinterpret_cast<const GLubyte*>("glBeginQueryARB"));
+
+   pGlEndQueryARB = (PFNGLENDQUERYARBPROC)
+   IRR_OGL_LOAD_EXTENSION(reinterpret_cast<const GLubyte*>("glEndQueryARB"));
+
+   pGlGetQueryivARB = (PFNGLGETQUERYIVARBPROC)
+   IRR_OGL_LOAD_EXTENSION(reinterpret_cast<const GLubyte*>("glGetQueryivARB"));
+
+   pGlGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC)
+   IRR_OGL_LOAD_EXTENSION(reinterpret_cast<const GLubyte*>("glGetQueryObjectivARB"));
+
+   pGlGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC)
+   IRR_OGL_LOAD_EXTENSION(reinterpret_cast<const GLubyte*>("glGetQueryObjectuivARB"));
+
+
    #endif // _IRR_OPENGL_USE_EXTPOINTER_
 #endif // _IRR_WINDOWS_API_
 
Index: COpenGLExtensionHandler.h
===================================================================
--- COpenGLExtensionHandler.h   (revision 1498)
+++ COpenGLExtensionHandler.h   (working copy)
@@ -763,7 +763,17 @@
    void extGlGetBufferParameteriv (GLenum target, GLenum pname, GLint *params);
    void extGlGetBufferPointerv (GLenum target, GLenum pname, GLvoid **params);
 
+   // occlusion query
+   void extGlGenQueries (GLsizei n, GLuint *ids);
+   void extGlDeleteQueries (GLsizei n, const GLuint *ids);
+   GLboolean extGlIsQuery (GLuint id);
+   void extGlBeginQuery (GLenum target, GLuint id);
+   void extGlEndQuery (GLenum target);
+   void extGlGetQueryiv (GLenum target, GLenum pname, GLint *params);
+   void extGlGetQueryObjectiv (GLuint id, GLenum pname, GLint *params);
+   void extGlGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params);
 
+
    protected:
    // the global feature array
    bool FeatureAvailable[IRR_OpenGL_Feature_Count];
@@ -831,6 +841,14 @@
       PFNGLISBUFFERARBPROC pGlIsBufferARB;
       PFNGLGETBUFFERPARAMETERIVARBPROC pGlGetBufferParameterivARB;
       PFNGLGETBUFFERPOINTERVARBPROC pGlGetBufferPointervARB;
+      PFNGLGENQUERIESARBPROC pGlGenQueriesARB;
+      PFNGLDELETEQUERIESARBPROC pGlDeleteQueriesARB;
+      PFNGLISQUERYARBPROC pGlIsQueryARB;
+      PFNGLBEGINQUERYARBPROC pGlBeginQueryARB;
+      PFNGLENDQUERYARBPROC pGlEndQueryARB;
+      PFNGLGETQUERYIVARBPROC pGlGetQueryivARB;
+      PFNGLGETQUERYOBJECTIVARBPROC pGlGetQueryObjectivARB;
+      PFNGLGETQUERYOBJECTUIVARBPROC pGlGetQueryObjectuivARB;
 
 
 
@@ -1505,11 +1523,107 @@
 #endif
 }
 
+inline void COpenGLExtensionHandler::extGlGenQueries (GLsizei n, GLuint *ids)
+{
+#ifdef _IRR_OPENGL_USE_EXTPOINTER_
+   if (pGlGenQueriesARB)
+      pGlGenQueriesARB(n, ids);
+#elif defined(GL_ARB_occlusion_query)
+   glGenQueriesARB(n, ids);
+#else
+   os::Printer::log("glGenQueriesARB not supported", ELL_ERROR);
+#endif
+}
 
+inline void COpenGLExtensionHandler::extGlDeleteQueries (GLsizei n, const GLuint *ids)
+{
+#ifdef _IRR_OPENGL_USE_EXTPOINTER_
+   if (pGlDeleteQueriesARB)
+      pGlDeleteQueriesARB(n, ids);
+#elif defined(GL_ARB_occlusion_query)
+   glDeleteQueriesARB(n, ids);
+#else
+   os::Printer::log("glDeleteQueriesARB not supported", ELL_ERROR);
+#endif
 }
+
+inline GLboolean COpenGLExtensionHandler::extGlIsQuery (GLuint id)
+{
+#ifdef _IRR_OPENGL_USE_EXTPOINTER_
+   if (pGlIsQueryARB)
+      pGlIsQueryARB(id);
+#elif defined(GL_ARB_occlusion_query)
+   glIsQueryARB(id);
+#else
+   os::Printer::log("glIsQueryARB not supported", ELL_ERROR);
+#endif
 }
 
+inline void COpenGLExtensionHandler::extGlBeginQuery (GLenum target, GLuint id)
+{
+#ifdef _IRR_OPENGL_USE_EXTPOINTER_
+   if (pGlBeginQueryARB)
+      pGlBeginQueryARB(target, id);
+#elif defined(GL_ARB_occlusion_query)
+   glBeginQueryARB(target, id);
+#else
+   os::Printer::log("glBeginQueryARB not supported", ELL_ERROR);
 #endif
+}
 
+inline void COpenGLExtensionHandler::extGlEndQuery (GLenum target)
+{
+#ifdef _IRR_OPENGL_USE_EXTPOINTER_
+   if (pGlEndQueryARB)
+      pGlEndQueryARB(target);
+#elif defined(GL_ARB_occlusion_query)
+   glEndQueryARB(target);
+#else
+   os::Printer::log("glEndQueryARB not supported", ELL_ERROR);
 #endif
+}
 
+inline void COpenGLExtensionHandler::extGlGetQueryiv (GLenum target, GLenum pname, GLint *params)
+{
+#ifdef _IRR_OPENGL_USE_EXTPOINTER_
+   if (pGlGetQueryivARB)
+      pGlGetQueryivARB(target, pname, params);
+#elif defined(GL_ARB_occlusion_query)
+   glGetQueryivARB(target, pname, params);
+#else
+   os::Printer::log("glGetQueryivARB not supported", ELL_ERROR);
+#endif
+}
+
+inline void COpenGLExtensionHandler::extGlGetQueryObjectiv (GLuint id, GLenum pname, GLint *params)
+{
+#ifdef _IRR_OPENGL_USE_EXTPOINTER_
+   if (pGlGetQueryObjectivARB)
+      pGlGetQueryObjectivARB(id, pname, params);
+#elif defined(GL_ARB_occlusion_query)
+   glGetQueryObjectivARB(id, pname, params);
+#else
+   os::Printer::log("glGetQueryObjectivARB not supported", ELL_ERROR);
+#endif
+}
+
+inline void COpenGLExtensionHandler::extGlGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params)
+{
+#ifdef _IRR_OPENGL_USE_EXTPOINTER_
+   if (pGlGetQueryObjectuivARB)
+      pGlGetQueryObjectuivARB(id, pname, params);
+#elif defined(GL_ARB_occlusion_query)
+   glGetQueryObjectuivARB(id, pname, params);
+#else
+   os::Printer::log("glGetQueryObjectuivARB not supported", ELL_ERROR);
+#endif
+}
+
+
+}
+}
+
+#endif
+
+#endif
+
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Nadro
 
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Postby full.metal.coder » Tue Aug 26, 2008 10:04 pm

thanks a lot.

I've already updated my working copy now I got to implement a smart culling algorithm. I've found a couple of resources after a quick web search but I did not find any implementation so far, let alone a killer(tm) one...

http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter06.html
http://http.developer.nvidia.com/GPUGems/gpugems_ch29.html

I guess I'll have to search more and experiment a bit.
full.metal.coder
 
Posts: 68
Joined: Sat May 10, 2008 11:30 am

Postby Halifax » Sat Aug 30, 2008 3:05 pm

Wow that's great nadro. I'm glad someone finally finished this, and hopefully it can be included in the next Irrlicht release.
TheQuestion = 2B || !2B
User avatar
Halifax
 
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

Postby torleif » Sun Aug 31, 2008 4:27 am

Halifax wrote:Wow that's great nadro. I'm glad someone finally finished this, and hopefully it can be included in the next Irrlicht release.


+1

I'm all for this, under the impression of "lightning fast game engine" seems to make you assume there was already culling in the engine
torleif
 
Posts: 188
Joined: Mon Jun 30, 2008 4:53 am

Postby Halifax » Tue Sep 02, 2008 9:58 am

Hmm, one thing I would like to note though is the naming scheme. You name the functions runAllQueries, createQuery, etc. But you have to remember, there are more queries that OpenGL, and D3D, contain that aren't occlusion queries.

So you might just want to rename that, or the devs can rename it if they accept it into the engine. Just a note.
TheQuestion = 2B || !2B
User avatar
Halifax
 
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

Postby Nadro » Tue Sep 02, 2008 6:35 pm

Hi, I can't replay quickly because I change my PC. Yes this code isn't prepare for implementation in engine. Of course all core system is good, but user interface maybe will be better if We can will disable/enable occlusion per material E_MATERIAL_FLAG? end rename runQuery to runOcclusionQuery etc?
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Nadro
 
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Next

Return to Project Announcements

Who is online

Users browsing this forum: No registered users and 1 guest