Box2D C++ tutorials - Using debug draw
Last edited: July 14 2013Chinese version -> 中文
Chinese version 2 -> 中文、第二
Using debug draw
The testbed makes use of a feature known as "debug draw" to draw the shapes you see. Obviously if you are making a game you will want to have all kinds of eye-popping fancy graphics instead of these boring polygons, but the debug draw feature can be very useful when you are having trouble getting the physics scene to work right. Sometimes the problem can be in the rendering part of your game, for example a sprite may be drawn at the wrong position or rotation, giving the appearance of incorrect physics. I recommend keeping the debug draw ready to hand for times when you want to check exactly what is going on in the Box2D world.
The way it works is quite simple. Box2D tells you all the shapes it sees and where they are eg. "a circle of radius r at x,y", or "an edge from a to b", etc and you draw what you are told. You don't have to do any transforming or worry about where the actual body positions are or which fixtures belong to which bodies, you simply draw the geometry. The idea is that if all you have to do is draw a few lines, you can't mess it up :-)
The default debug draw used by the testbed is done by subclassing the b2DebugDraw class, which has a bunch of virtual functions that can be overridden. Here are the main players:
1 2 3 4 5 6 | virtual void DrawPolygon(b2Vec2* vertices, int32 vertexCount, b2Color& color) = 0; virtual void DrawSolidPolygon(b2Vec2* vertices, int32 vertexCount, b2Color& color) = 0; virtual void DrawCircle(b2Vec2& center, float32 radius, b2Color& color) = 0; virtual void DrawSolidCircle(b2Vec2& center, float32 radius, b2Vec2& axis, b2Color& color) = 0; virtual void DrawSegment(b2Vec2& p1, b2Vec2& p2, b2Color& color) = 0; virtual void DrawTransform(const b2Transform& xf) = 0; |
Although the testbed's default debug draw works just fine and we don't really need to customize it, since we're on the topic let's try using our own subclass to alter the appearance a bit. Any scene from the previous topics will be ok to use - I'll start with the same scene as for the moving at constant speed topic.

1 2 3 4 5 6 7 8 9 10 | class FooDraw : public b2DebugDraw { public: void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) {} void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) {} void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) {} void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) {} void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) {} void DrawTransform(const b2Transform& xf) {} }; |
1 2 3 4 5 6 7 8 | //at global scope FooDraw fooDrawInstance; //in constructor, usually m_world->SetDebugDraw( &fooDrawInstance ); //somewhere appropriate fooDrawInstance.SetFlags( b2DebugDraw::e_shapeBit ); |
- e_shapeBit ( draw shapes )
- e_jointBit ( draw joint connections
- e_aabbBit ( draw axis aligned bounding boxes )
- e_pairBit ( draw broad-phase pairs )
- e_centerOfMassBit ( draw a marker at body CoM )
If you use a debug draw class in your own projects, there is one other important point to be aware of: you need to call the DrawDebugData() function of your world, which will in turn cause Box2D to call back to your debug draw class functions for each shape that needs drawing.
Running the testbed now you should see nothing showing in the scene. This is because we still have a completely empty debug draw implementation. From this point, what you fill in the drawing functions depends on what platform and rendering API you are using. As an example, let's implement the DrawSolidPolygon function in OpenGL ES, as used on embedded platforms such as the iPhone. This is a handy example because OpenGL ES is a subset of OpenGL so we can still run it on our PC in the testbed as normal, and also because it's one of those questions that comes up often.
OpenGL ES does not have the glBegin/glEnd/glVertex functions, so rendering is done with vertex arrays instead:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) { //set up vertex array GLfloat glverts[16]; //allow for polygons up to 8 vertices glVertexPointer(2, GL_FLOAT, 0, glverts); //tell OpenGL where to find vertices glEnableClientState(GL_VERTEX_ARRAY); //use vertices in subsequent calls to glDrawArrays //fill in vertex positions as directed by Box2D for (int i = 0; i < vertexCount; i++) { glverts[i*2] = vertices[i].x; glverts[i*2+1] = vertices[i].y; } //draw solid area glColor4f( color.r, color.g, color.b, 1); glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount); //draw lines glLineWidth(3); //fat lines glColor4f( 1, 0, 1, 1 ); //purple glDrawArrays(GL_LINE_LOOP, 0, vertexCount); } |

Update: I noticed that there is a good implementation for an OpenGL ES debug draw in the Box2D source code iPhone contribution. This is written for Obj-C but it appears to be regular C++ so you can use it without modification:
GLES-Render.mm