Debug Drawing Utility Class
Table of contents
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.
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:
// 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:
// 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:
// 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():
// 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():
// 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):
// 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:
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):
Another Usage Example: Pretty Cubes
For the sake of fun, let's draw lots of pretty colorful cubes! ๐:
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):
Icosphere Example
The class can now draw icospheres!
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):
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.
// 2 is more than enough! DebugDrawer::getSingleton().setIcoSphereRecursionLevel(2);
The result:
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