Hi,
I have been able to add Bullet physics to my code and I am trying to create a character controller - however I didn't see any demo on the character control to see how its done in bullet. I am a little new to physics integration and I am not sure how I should approach this.
I am thinking that I should make the object a kinematic actor but I don't see how.
Thanks.
Gautam
Character control
-
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
Re: Character control
Please make Bullet related postings in the Bullet section. This FAQ section is more general physics questions (not Bullet specific).
As a starting point, you can try to model the character with a dynamic btRigidBody, using a sphere shape or capsule, and set the angular impulse factor to zero:
This will prevent the sphere from rolling, and only sliding. Note you can create a capsule, by using the btMultiSphereShape, and adding 2 spheres at different locations.
I am planning a more advanced custom character controller, but that is not in Bullet 2.39 yet.
Thanks,
Erwin
As a starting point, you can try to model the character with a dynamic btRigidBody, using a sphere shape or capsule, and set the angular impulse factor to zero:
Code: Select all
void setAngularFactor(float angFac)
I am planning a more advanced custom character controller, but that is not in Bullet 2.39 yet.
Thanks,
Erwin
gautam wrote:Hi,
I have been able to add Bullet physics to my code and I am trying to create a character controller - however I didn't see any demo on the character control to see how its done in bullet. I am a little new to physics integration and I am not sure how I should approach this.
I am thinking that I should make the object a kinematic actor but I don't see how.
Thanks.
Gautam
-
- Posts: 8
- Joined: Sun Dec 10, 2006 5:14 am
-
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
You can set the gravity per body. Make sure you do this AFTER you add the rigidbody to the world, and after you set the global gravity. Note that dynamicsWorld.setGravity will overwrite gravity of rigidbodies added to the world. So the order makes a difference.gautam wrote:Hi Erwin,
Thanks for the reply. I will definitely put other bullet requests on this section. I will definitely try that.
I also want to nullify the effect of gravity on one rigid body only - that is the characters - is this possible.
Thanks
Gautam
It is also recommended to move the body (character) using setLinearVelocity, instead of directly setting the world transform. If the character still gets some angular drift, you can apply a 'pure angular' hinge, without the translation part: add a usual hinge, with the character 'up' vector as axis, and (0,0,0) as pivot. Then, call 'setAngularOnly(true) for that hinge.
Please let us know if this "setAngularFactor" works out for you.
Erwin
-
- Posts: 8
- Joined: Sun Dec 10, 2006 5:14 am
Hi,
Yes the setAngularFactor works for me at the moment but now I have another problem. Whenever 2 rigid body i.e. dynamic body collide the model seems to disappear. However it works fine when colliding with a user defined mesh.
I have taken the liberty to post an image as I may be able to explain better with it.
If you see the image the - sphere collide fine with the floors but when the 2 spheres collide with each other both vanish from the screen.
Is there any specific reason for this to happen. I use a btBvhTriangleMeshShape to create a rigidbody for the floor and register that as the first object in the world. Is this an issue.
Thanks
Yes the setAngularFactor works for me at the moment but now I have another problem. Whenever 2 rigid body i.e. dynamic body collide the model seems to disappear. However it works fine when colliding with a user defined mesh.
I have taken the liberty to post an image as I may be able to explain better with it.
If you see the image the - sphere collide fine with the floors but when the 2 spheres collide with each other both vanish from the screen.
Is there any specific reason for this to happen. I use a btBvhTriangleMeshShape to create a rigidbody for the floor and register that as the first object in the world. Is this an issue.
Thanks
-
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
-
- Posts: 8
- Joined: Sun Dec 10, 2006 5:14 am
No - this happens even with regular rigid bodies and character rigid bodies. When they collide their position seems to go astray on the y and z coordinates - I start seeing values like the followingErwin Coumans wrote:Does this happen only between two character-rigidbodies that have a modified 'angular factor'?
Or does it also happen between two regula' rigidbodies, and/or character versus regular rigidbody (unmodified angular factor)?
-472.421875 -18379186.000000 351334944.000000
-300.936829 4987717632.000000 -2644217856.000000
Indeed I can - but its quite a bit of code as I encapsulated a lot of things - so please bear with me.Erwin Coumans wrote: Can you share your testbed that reproduces the problem?
Thanks,
Erwin
This is how set up the physics and physics bodies for now.
Code: Select all
CPhysics::GetInstance().InitPhysics();
CPhysics::GetInstance().SetGravity(vector3(0.0f, -10.0f, 0.0f));
model.LoadModel("media/land.flex");
castleObject = new GameObject();
castleObject->RegisterObject();
castleObject->SetModel(&model);
castleObject->SetPosition(vector3(0, -2, 0));
castleObject->SetMass(0.0f);
castleObject->SetPhysics(WORLD); castleObject->SetCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
// setup the box information
box.LoadModel("media/sphere.flex");
boxObject = new GameObject();
boxObject->RegisterObject();
boxObject->SetModel(&box);
boxObject->SetPosition(vector3(-20.0f, 0.0f, -10.0f));
boxObject->SetMass(5.0f);
boxObject->SetCenterofMass(btTransform::getIdentity());
boxObject->SetLinearVelocity(vector3(0.0f, -10.0f, 0.0f));
boxObject->SetScale(vector3(5.0f, 5.0f, 5.0f));
boxObject->SetPhysics(SPHERE);
//boxObject->SetAngularFactor(0.0f);
boxObject->SetPlayerVelocity(vector3(0.1f, 0.1f, 0.1f));
//boxObject->SetCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
//boxObject->SetActivationState(DISABLE_DEACTIVATION);
sphere.LoadModel("media/sphere.flex");
sphereObject = new GameObject();
sphereObject->RegisterObject();
sphereObject->SetModel(&sphere);
sphereObject->SetPosition(vector3(-20.0f, 20.0f, -15.0f));
sphereObject->SetScale(vector3(5.0f, 5.0f, 5.0f));
sphereObject->SetLinearVelocity(vector3(0.0f, -1.0f, 0.0f));
sphereObject->SetMass(1.0f);
sphereObject->SetPhysics(SPHERE);
Code: Select all
void GameObject::SetPhysics(RIGIDBODY_SHAPE shape)
{
btVector3 v = ConvertToBulletVector(m_Position);
btTransform transform;
transform.setIdentity();
transform.setOrigin(v);
btVector3 scale = ConvertToBulletVector(m_Scale);
switch(shape)
{
case BOX :
this->m_Body = createRigidBodyBox(scale, transform, m_Mass);
break;
case TRIANGLES :
this->m_Body = createRigidBodyFromTriangles(*m_Model, transform, m_Mass);
break;
case SPHERE :
this->m_Body = createRigidBodySphere(scale.getX(), transform, m_Mass);
break;
case WORLD:
{
m_Body = createRigidBodyFromTriangles(*m_Model, transform, 0.0f);
CPhysics::GetInstance().SetupWorldRigidBody(m_Body);
}
break;
default :
break;
}
if(!m_Body->isStaticObject() && !m_Body->isKinematicObject())
{
GameObject::SetPhysicsAttribute();
}
CPhysics::GetInstance().AddRigidBody(m_Body);
}
Code: Select all
void GameObject::SetPhysicsAttribute()
{
if(m_Body != NULL)
{
btVector3 lVel = ConvertToBulletVector(m_LinearVel);
m_Body->setLinearVelocity(lVel);
btVector3 aVel = ConvertToBulletVector(m_AngularVel);
m_Body->setAngularVelocity(aVel);
m_Body->setRestitution(m_Restitution);
btDynamicsWorld *m_World = CPhysics::GetInstance().GetPhysicsWorld();
m_World->getBroadphase()->cleanProxyFromPairs(m_Body->getBroadphaseHandle());
}
}
Code: Select all
btRigidBody* localCreateRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape)
{
//rigidbody is dynamic if and only if mass is non zero, otherwise static
bool isDynamic = (mass != 0.f);
btVector3 localInertia(0,0,0);
if (isDynamic)
shape->calculateLocalInertia(mass,localInertia);
//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
#define USE_MOTIONSTATE 1
#ifdef USE_MOTIONSTATE
btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
btRigidBody* body = new btRigidBody(mass,myMotionState,shape,localInertia);
#else
btRigidBody* body = new btRigidBody(mass,startTransform,shape,localInertia);
#endif//
return body;
}
btRigidBody *createRigidBodyFromTriangles(CModel &model, const btTransform &startTransform,
float mass)
{
unsigned int numVertices = model.GetNumberOfVertices();
CustomVertex *vertex = model.GetVertexInfoPointer();
btVector3 *gVertices = new btVector3[numVertices];
int *gIndices = new int[numVertices];
for(unsigned int i = 0; i < numVertices; i++)
{
gVertices[i] = ConvertToBulletVector(vertex[i].m_Vertex);
gIndices[i] = i;
}
int vertStride = sizeof(btVector3);
int indexStride = 3*sizeof(int);
int totalTriangles = numVertices / 3;
btTriangleIndexVertexArray* indexVertexArrays = new btTriangleIndexVertexArray(totalTriangles,
gIndices,
indexStride,
(int)numVertices,
(float*) &gVertices[0].x(),
vertStride);
btCollisionShape* trimeshShape = new btBvhTriangleMeshShape(indexVertexArrays);
btRigidBody *body = localCreateRigidBody(mass, startTransform,trimeshShape);
return body;
}
btRigidBody *createRigidBodyBox(const btVector3 &halfExtents,
const btTransform &transform, float mass)
{
btCollisionShape* shape = new btBoxShape(halfExtents);
btRigidBody *boxBody = localCreateRigidBody(mass,transform,shape);
return boxBody;
}
btRigidBody *createRigidBodySphere(float radius, const btTransform &transform, float mass)
{
btCollisionShape* shape = new btSphereShape(radius);
btRigidBody *sphereBody = localCreateRigidBody(mass,transform,shape);
return sphereBody;
}
Code: Select all
void CPhysics::InitPhysics()
{
btCollisionDispatcher *dispatcher = new btCollisionDispatcher();
btVector3 worldAabbMin(-100,-100,-100);
btVector3 worldAabbMax(100,100,100);
btOverlappingPairCache* broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,maxProxies);
btSequentialImpulseConstraintSolver *solver = new btSequentialImpulseConstraintSolver();
m_bWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver);
btVector3 gravity = ConvertToBulletVector(m_Gravity);
m_bWorld->setGravity(gravity);
}
void CPhysics::Update()
{
m_bWorld->updateAabbs();
m_bWorld->stepSimulation(0.002f);
}
Code: Select all
inline btVector3 ConvertToBulletVector(const vector3 &v)
{
btVector3 ret;
ret.setX(v.x);
ret.setY(v.y);
ret.setZ(v.z);
return ret;
}
inline vector3 ConvertFromBulletVector(const btVector3 &v)
{
vector3 ret;
ret.x = v.getX();
ret.y = v.getY();
ret.z = v.getZ();
return ret;
}
Code: Select all
void GameObject::UpdateTransform()
{
btDefaultMotionState *state = static_cast<btDefaultMotionState *>(m_Body->getMotionState());
float m[16];
state->m_graphicsWorldTrans.getOpenGLMatrix(m);
m_Model->SetTransform(m);
if(!m_Body->isStaticObject())
{
FILE *fp = fopen("errorlog", "a+");
if(fp)
{
btTransform tr;
state->getWorldTransform(tr);
btVector3 v = tr.getOrigin();
fprintf(fp, "%f %f %f\n", v.getX(), v.getY(), v.getZ());
fclose(fp);
}
}
}
Please let me know if you need anything else.
Thanks and regards.