Wednesday, June 17, 2015

debugging - Bullet physics debug drawing not working


Background


I am following on from this question, which isn't answered yet. Basically I have a cube and a UVSphere in my scene, with UVSphere on the top of the cube without touching the cube. Both exported from blender.


When I run the app The UVSphere does circle around the cube for 3 or 4 times and jump out of the scene. What I actually expect was the sphere to fall on top of the cube.


What this question about


From the comment to the linked question, I got to know about bullet debug drawing, which helps in debugging by drawing outline of physics bodies which are normally invisible. I did some research on that and came up with the code given below. From whatever I have read, below code should work, but it doesn't.


My Code


My bullet initialization code.


-(void) initializeScene {
/*Setup physics world*/

_physicsWorld = [[CC3PhysicsWorld alloc] init];
[_physicsWorld setGravity:0 y:-9.8 z:0];

/*Setting up debug draw*/
MyDebugDraw *draw = new MyDebugDraw;
draw->setDebugMode(draw->getDebugMode()
| btIDebugDraw::DBG_DrawWireframe );
_physicsWorld._discreteDynamicsWorld->setDebugDrawer(draw);

/*Setup camera and lamb*/

…………..

//This simpleCube.pod contains the cube
[self addContentFromPODFile: @"simpleCube.pod"];
//This file contains sphere
[self addContentFromPODFile: @"SimpleSphere.pod"];

[self createGLBuffers];

CC3MeshNode* cubeNode = (CC3MeshNode*)[self getNodeNamed:@"Cube"];

CC3MeshNode* sphereNode = (CC3MeshNode*)[self getNodeNamed:@"Sphere"];
// both cubeNode and sphereNode are not nil from this point


float *cVertexData = (float*)((CC3VertexArrayMesh*)cubeNode.mesh)
.vertexLocations.vertices;
int cVertexCount = ((CC3VertexArrayMesh*)cubeNode.mesh)
.vertexLocations.vertexCount;

btTriangleMesh* cTriangleMesh = new btTriangleMesh();


int offset = 0;
for (int i = 0; i < (cVertexCount / 3); i++)
{
unsigned int index1 = offset;
unsigned int index2 = offset+6;
unsigned int index3 = offset+12;
cTriangleMesh->addTriangle(
btVector3(cVertexData[index1], cVertexData[index1+1], cVertexData[index1+2]),
btVector3(cVertexData[index2], cVertexData[index2+1], cVertexData[index2+2]),

btVector3(cVertexData[index3], cVertexData[index3+1], cVertexData[index3+2]));
offset += 18;
}

[self releaseRedundantData];

/*Create a triangle mesh from the vertices*/
btBvhTriangleMeshShape* cTriMeshShape
= new btBvhTriangleMeshShape(cTriangleMesh,true);
btCollisionShape *sphereShape = new btSphereShape(1);


gTriMeshObject = [_physicsWorld createPhysicsObjectTrimesh:cubeNode
shape:cTriMeshShape
mass:0
restitution:1.0
position:cubeNode.location];
sphereObject = [_physicsWorld createPhysicsObject:sphereNode
shape:sphereShape
mass:1
restitution:0.1

position:sphereNode.location];
sphereObject.rigidBody->setDamping(0.1,0.8);

/*Enable debug drawing*/
_physicsWorld._discreteDynamicsWorld->debugDrawWorld();
}

And My btIDebugDraw implementation (MyDebugDraw.h)


//MyDebugDraw.h
class MyDebugDraw: public btIDebugDraw{

int m_debugMode;

public:

virtual void drawLine(const btVector3& from,const btVector3& to
,const btVector3& color);

virtual void drawContactPoint(const btVector3& PointOnB
,const btVector3& normalOnB,btScalar distance
,int lifeTime,const btVector3& color);


virtual void reportErrorWarning(const char* warningString);

virtual void draw3dText(const btVector3& location
,const char* textString);

virtual void setDebugMode(int debugMode);

virtual int getDebugMode() const;
};


void MyDebugDraw::drawLine(const btVector3& from,const btVector3& to
,const btVector3& color){
LogInfo(@"Works!!");
glPushMatrix();
glColor4f(color.getX(), color.getY(), color.getZ(), 1.0);

const GLfloat line[] = {
from.getX()*1, from.getY()*1, from.getZ()*1, //point A
to.getX()*1, to.getY()*1,to.getZ()*1 //point B

};
glVertexPointer( 3,
GL_FLOAT,
0,
&line );
glPointSize( 5.0f );
glDrawArrays( GL_POINTS, 0, 2 );
glDrawArrays( GL_LINES, 0, 2 );
glPopMatrix();
}


void MyDebugDraw::drawContactPoint(const btVector3 &PointOnB
,const btVector3 &normalOnB, btScalar distance
,int lifeTime, const btVector3 &color){
}

void MyDebugDraw::reportErrorWarning(const char *warningString){
}

void MyDebugDraw::draw3dText(const btVector3 &location

, const char *textString){
}

void MyDebugDraw::setDebugMode(int debugMode){
}

int MyDebugDraw::getDebugMode() const{
return DBG_DrawWireframe;
}


My Problem


The drawLine method is getting called. I can see the cube and sphere in place. Sphere again does some circling around the cube before jumping off.


No debug lines are getting drawn.



Answer



Okay I got it working. For everyone who faces this in the future..



Note : I use Cocos3D (2D) functions to draw the line. So this is not a generic solution.



This is how I done it.


1) Create a RuleSet objective C class



RuleSet.h


#import "CC3Scene.h"

@interface RuleSet : NSObject{
}
@property(strong, nonatomic) CC3Scene *currentScene;
@property (strong, nonatomic) NSMutableArray *lines;
+(id)sharedRuleSet;
-(void) debugLineFromX:(float)fromX fromY:(float)fromY
fromZ:(float)fromZ toX:(float)toX toY:(float)toY toZ:(float)toZ;

@end

RuleSet.m


#import "RuleSet.h"
#import "CC3MeshNode.h"

@implementation RuleSet
+(id)sharedRuleSet{
static RuleSet *sharedRuleSet = nil;
static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{
sharedRuleSet = [[self alloc] init];
});
return sharedRuleSet;
}

-(void) debugLineFromX:(float)fromX fromY:(float)fromY fromZ:(float)fromZ
toX:(float)toX toY:(float)toY toZ:(float)toZ {
if (!self.lines) {
self.lines = [NSMutableArray array];

}
float arr_location[] = {fromX,fromY,fromZ, toX,toY, toZ };
CC3LineNode* lineNode = [CC3LineNode nodeWithName: @"Line test"];
[lineNode populateAsLineStripWith: 2
vertices: arr_location
andRetain: YES];
lineNode.color = ccRED;

[self.lines addObject:lineNode];
[self.currentScene addChild:lineNode];

}
@end

2) Create a custom btDebugDraw implementation


MyDebugDraw.h


#include 
#include "btIDebugDraw.h"
#import "RuleSet.h"

class MyDebugDraw: public btIDebugDraw{

int m_debugMode;

public:
virtual void drawLine(const btVector3& from,const btVector3& to
,const btVector3& color);
virtual void drawContactPoint(const btVector3& PointOnB
,const btVector3& normalOnB,btScalar distance
,int lifeTime,const btVector3& color);
virtual void reportErrorWarning(const char* warningString);
virtual void draw3dText(const btVector3& location,const char* textString);

virtual void setDebugMode(int debugMode);
virtual int getDebugMode() const;
};

void MyDebugDraw::drawLine(const btVector3& from,const btVector3& to
,const btVector3& color)
{
RuleSet *rule = [RuleSet sharedToolSet];
[rule debugLineFromX:from.x() fromY:from.y() fromZ:from.z()
toX:to.x() toY:to.y() toZ:to.z()];

}

void MyDebugDraw::drawContactPoint(const btVector3 &PointOnB
, const btVector3 &normalOnB, btScalar distance
, int lifeTime, const btVector3 &color){}

void MyDebugDraw::reportErrorWarning(const char *warningString){}

void MyDebugDraw::draw3dText(const btVector3 &location
, const char *textString){}


void MyDebugDraw::setDebugMode(int debugMode){}

int MyDebugDraw::getDebugMode() const{
return DBG_DrawWireframe;
}

3) During physics world initialization


YourScene.m


......

#import "RuleSet.h"
#import "MyDebugDraw.h"
.......

-(void) initializeScene {
RuleSet *rule = [RuleSet sharedToolSet];
rule.currentScene = self;

//Create physics world
btBroadphaseInterface* broadphase = new btDbvtBroadphase();

btDefaultCollisionConfiguration* collisionConfiguration
= new btDefaultCollisionConfiguration();
btCollisionDispatcher* dispatcher
= new btCollisionDispatcher(collisionConfiguration);
btSequentialImpulseConstraintSolver* solver
= new btSequentialImpulseConstraintSolver();
dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher
,broadphase,solver,collisionConfiguration);
dynamicsWorld->setGravity(btVector3(0,-10.0,0));


/*Create custom debug drawer*/
MyDebugDraw *draw = new MyDebugDraw;
draw->setDebugMode( draw->getDebugMode()
| btIDebugDraw::DBG_DrawWireframe );
dynamicsWorld->setDebugDrawer(draw);

/*Add rigid bodies and collision objects to physics world*/
.....
.....


/*At the end of initializeScene function
, after adding physics bodies*/
dynamicsWorld->debugDrawWorld();
}

And credit goes here. This is not my code.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...