Skip to main content
Debug Drawing Utility Class         Utility class for rendering simple primitives like 3D lines, quads and cuboids.
dedugdraw_box.png

Debug Drawing Utility Class

Description

It's a utility class for rendering simple primitives like 3D lines, quads and cuboids, without having to keep track of manual objects. It is useful for debugging purposes, since it is quite a hassle to keep track of ManualObject instances, initializing them, attaching them to scene nodes and destroying them just for the sake of debugging. Using this class, all it takes is just one function call to draw a primitive. Note that it works like 2D rendering, e.g. it is cleared every frame. Thus, the draw functions need to be called every frame.

Currently, it supports rendering of:

  • lines
  • quads
  • circles
  • cuboids
  • icospheres
  • cylinders
  • tetrahedrons


For questions use this forum topic.
A C# and Visual Basic port for Mogre is available here.

Source code

The needed files DebugDrawer.h and DebugDrawer.cpp are available in this https://github.com/hasyimibhar/ogre-debug-drawing-utility.

NOTE: Be sure to add this line to the initializer list of the DebugDrawer constructor.
It's missing from the archive and without it, the debug display may or may not appear.

Copy to clipboard
isEnabled(true)


Usage Example: Drawing a Bounding Box

This usage example is made based on the basic application framework generated by OgreApp Wizard. It requires destroyScene(), frameStarted() and frameEnded() to be overridden:

Copy to clipboard
// Override me! virtual void createScene(void); virtual bool frameStarted(const Ogre::FrameEvent& evt); virtual bool frameEnded(const Ogre::FrameEvent& evt);


First, the DebugDrawer instance (DebugDrawer is a singleton) needs to be created and initialized. This is done inside createScene() by initializing DebugDrawer's singleton instance:

Copy to clipboard
// Initialise the DebugDrawer singleton new DebugDrawer(mSceneMgr, 0.5f);


Don't forget to destroy DebugDrawer once you're done using it. This is done inside destroyScene() by calling deleting its singleton's instance:

Copy to clipboard
// Goodbye~ delete DebugDrawer::getSingletonPtr();


Right before the frame is rendered, DebugDrawer::build() needs to be called. This will build the ManualObject wrapped by the class. In this example, DebugDrawer::build() is called at the end of frameStarted():

Copy to clipboard
// Right before the frame is rendered, call DebugDrawer::build(). DebugDrawer::getSingleton().build();


At the end of each frame (after the frame has been rendered), DebugDrawer needs to be cleared. This is done by calling DebugDrawer::clear() inside frameEnded():

Copy to clipboard
// After the frame is rendered, call DebugDrawer::clear() DebugDrawer::getSingleton().clear();


Finally, the class can be used. Since the framework lacks a proper update loop, the draw functions need to be called inside frameStarted(), but before DebugDrawer::build() is called. The code below will draw a filled cuboid as the bounding box of the entity (the ogre head):

Copy to clipboard
// Let's draw the bounding box for the ogre head! DebugDrawer::getSingleton().drawCuboid(mOgreHead->getBoundingBox().getAllCorners(), Ogre::ColourValue::Red, true);


The entire example application code:

Copy to clipboard
void DebugDrawingUtility::createScene(void) { mOgreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh"); Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); headNode->attachObject(mOgreHead ); // Set ambient light mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5)); // Create a light Ogre::Light* l = mSceneMgr->createLight("MainLight"); l->setPosition(20,80,50); // Initialise the DebugDrawer singleton new DebugDrawer(mSceneMgr, 0.5f); } void DebugDrawingUtility::destroyScene(void) { // Goodbye~ delete DebugDrawer::getSingletonPtr(); } bool DebugDrawingUtility::frameStarted(const Ogre::FrameEvent& evt) { // Since this framework lacks a proper update loop, let's just place the drawing codes here. // Drawing codes should go inside an update loop, before the frame is rendered. // Let's draw the bounding box for the ogre head! DebugDrawer::getSingleton().drawCuboid(mOgreHead->getBoundingBox().getAllCorners(), Ogre::ColourValue::Red, true); // =================================================================== // Right before the frame is rendered, call DebugDrawer::build(). DebugDrawer::getSingleton().build(); return true; } bool DebugDrawingUtility::frameEnded(const Ogre::FrameEvent& evt) { // After the frame is rendered, call DebugDrawer::clear() DebugDrawer::getSingleton().clear(); return true; }


The result (release build):

dedugdraw_box.png

Another Usage Example: Pretty Cubes

For the sake of fun, let's draw lots of pretty colorful cubes! ๐Ÿ˜€:

Copy to clipboard
for (int i = 0; i < 5; ++i) { for (int j = 0; j < 5; j++) { for (int k = 0; k < 5; k++) { Ogre::AxisAlignedBox box (Ogre::Vector3(i * 10.0f + 2.0f, j * 10.0f + 2.0f, k * 10.0f + 2.0f), Ogre::Vector3((i + 1) * 10.0f - 2.0f, (j + 1) * 10.0f - 2.0f, (k + 1) * 10.0f - 2.0f)); DebugDrawer::getSingleton().drawCuboid(box.getAllCorners(), Ogre::ColourValue(51.0f * i / 255.0f, 51.0f * j / 255.0f, 51.0f * k / 255.0f), true); } } }


The result (release build):

debugdraw_cubes.png

Icosphere Example

The class can now draw icospheres!

Copy to clipboard
for (int i = 0; i < 5; ++i) { for (int j = 0; j < 5; j++) { for (int k = 0; k < 5; k++) { // Draws a sphere with radius 20.0f DebugDrawer::getSingleton().drawSphere(Ogre::Vector3(i * 50.0f, j * 50.0f, k * 50.0f), 20.0f, Ogre::ColourValue(51.0f * i / 255.0f, 51.0f * j / 255.0f, 51.0f * k / 255.0f), true); } } }


The result (to be honest, this example was run from a more powerful PC than the previous examples):

ManySpheres.png

The recursion level of the icosphere can be changed to get a more detailed icosphere. This is done by calling setIcoSphereRecursionLevel(). Note that this function rebuilds the icosphere, so don't call it in a loop.

Copy to clipboard
// 2 is more than enough! DebugDrawer::getSingleton().setIcoSphereRecursionLevel(2);


The result:

debugDraw_icosphere.png

To Do

  • Properly document the class. Currently, the class is being documented through usage examples, which is inadequate
  • Add more primitives!
  • Add screen shots to show all the primitives
  • Further optimize the class