#include "btBulletDynamicsCommon.h" #include "RagdollDemo.h" #include "OpenGLWindow/SimpleOpenGL3App.h" #include "OpenGLWindow/GLInstancingRenderer.h" #include "BulletCollision/CollisionShapes/btShapeHull.h" #define CONSTRAINT_DEBUG_SIZE 0.2f struct GraphicsVertex { float pos[4]; float normal[3]; float texcoord[2]; }; class RagDoll { enum { BODYPART_PELVIS = 0, BODYPART_SPINE, BODYPART_HEAD, BODYPART_LEFT_UPPER_LEG, BODYPART_LEFT_LOWER_LEG, BODYPART_RIGHT_UPPER_LEG, BODYPART_RIGHT_LOWER_LEG, BODYPART_LEFT_UPPER_ARM, BODYPART_LEFT_LOWER_ARM, BODYPART_RIGHT_UPPER_ARM, BODYPART_RIGHT_LOWER_ARM, BODYPART_COUNT }; enum { JOINT_PELVIS_SPINE = 0, JOINT_SPINE_HEAD, JOINT_LEFT_HIP, JOINT_LEFT_KNEE, JOINT_RIGHT_HIP, JOINT_RIGHT_KNEE, JOINT_LEFT_SHOULDER, JOINT_LEFT_ELBOW, JOINT_RIGHT_SHOULDER, JOINT_RIGHT_ELBOW, JOINT_COUNT }; btDynamicsWorld* m_ownerWorld; btConvexShape* m_shapes[BODYPART_COUNT]; btRigidBody* m_bodies[BODYPART_COUNT]; btTypedConstraint* m_joints[JOINT_COUNT]; SimpleOpenGL3App* m_app;//used to create graphics shapes btRigidBody* localCreateRigidBody (btScalar mass, const btTransform& startTransform, btConvexShape* shape) { bool isDynamic = (mass != 0.f); btVector3 localInertia(0,0,0); if (isDynamic) shape->calculateLocalInertia(mass,localInertia); btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,shape,localInertia); btRigidBody* body = new btRigidBody(rbInfo); m_ownerWorld->addRigidBody(body); btVector3 color(1,0,0); btVector3 scaling(1,1,1); btShapeHull* hull = new btShapeHull(shape); hull->buildHull(0.01); { int strideInBytes = 9*sizeof(float); int numVertices = hull->numVertices(); int numIndices =hull->numIndices(); btAlignedObjectArray gvertices; for (int i=0;igetVertexPointer()[i]; vtx.pos[0] = pos.x(); vtx.pos[1] = pos.y(); vtx.pos[2] = pos.z(); vtx.pos[3] = 1.f; pos.normalize(); vtx.normal[0] =pos.x(); vtx.normal[1] =pos.y(); vtx.normal[2] =pos.z(); vtx.texcoord[0] = 0.5f; vtx.texcoord[1] = 0.5f; gvertices.push_back(vtx); } btAlignedObjectArray indices; for (int i=0;igetIndexPointer()[i]); int shapeId = m_app->m_instancingRenderer->registerShape(&gvertices[0].pos[0],numVertices,&indices[0],numIndices); m_app->m_instancingRenderer->registerGraphicsInstance(shapeId,body->getWorldTransform().getOrigin(),body->getWorldTransform().getRotation(),color,scaling); } delete hull; return body; } public: RagDoll (btDynamicsWorld* ownerWorld, const btVector3& positionOffset,SimpleOpenGL3App* app) : m_ownerWorld (ownerWorld), m_app(app) { // Setup the geometry m_shapes[BODYPART_PELVIS] = new btCapsuleShape(btScalar(0.15), btScalar(0.20)); m_shapes[BODYPART_SPINE] = new btCapsuleShape(btScalar(0.15), btScalar(0.28)); m_shapes[BODYPART_HEAD] = new btCapsuleShape(btScalar(0.10), btScalar(0.05)); m_shapes[BODYPART_LEFT_UPPER_LEG] = new btCapsuleShape(btScalar(0.07), btScalar(0.45)); m_shapes[BODYPART_LEFT_LOWER_LEG] = new btCapsuleShape(btScalar(0.05), btScalar(0.37)); m_shapes[BODYPART_RIGHT_UPPER_LEG] = new btCapsuleShape(btScalar(0.07), btScalar(0.45)); m_shapes[BODYPART_RIGHT_LOWER_LEG] = new btCapsuleShape(btScalar(0.05), btScalar(0.37)); m_shapes[BODYPART_LEFT_UPPER_ARM] = new btCapsuleShape(btScalar(0.05), btScalar(0.33)); m_shapes[BODYPART_LEFT_LOWER_ARM] = new btCapsuleShape(btScalar(0.04), btScalar(0.25)); m_shapes[BODYPART_RIGHT_UPPER_ARM] = new btCapsuleShape(btScalar(0.05), btScalar(0.33)); m_shapes[BODYPART_RIGHT_LOWER_ARM] = new btCapsuleShape(btScalar(0.04), btScalar(0.25)); // Setup all the rigid bodies btTransform offset; offset.setIdentity(); offset.setOrigin(positionOffset); btTransform transform; transform.setIdentity(); transform.setOrigin(btVector3(btScalar(0.), btScalar(1.), btScalar(0.))); m_bodies[BODYPART_PELVIS] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_PELVIS]); transform.setIdentity(); transform.setOrigin(btVector3(btScalar(0.), btScalar(1.2), btScalar(0.))); m_bodies[BODYPART_SPINE] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_SPINE]); transform.setIdentity(); transform.setOrigin(btVector3(btScalar(0.), btScalar(1.6), btScalar(0.))); m_bodies[BODYPART_HEAD] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_HEAD]); transform.setIdentity(); transform.setOrigin(btVector3(btScalar(-0.18), btScalar(0.65), btScalar(0.))); m_bodies[BODYPART_LEFT_UPPER_LEG] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_LEFT_UPPER_LEG]); transform.setIdentity(); transform.setOrigin(btVector3(btScalar(-0.18), btScalar(0.2), btScalar(0.))); m_bodies[BODYPART_LEFT_LOWER_LEG] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_LEFT_LOWER_LEG]); transform.setIdentity(); transform.setOrigin(btVector3(btScalar(0.18), btScalar(0.65), btScalar(0.))); m_bodies[BODYPART_RIGHT_UPPER_LEG] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_RIGHT_UPPER_LEG]); transform.setIdentity(); transform.setOrigin(btVector3(btScalar(0.18), btScalar(0.2), btScalar(0.))); m_bodies[BODYPART_RIGHT_LOWER_LEG] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_RIGHT_LOWER_LEG]); transform.setIdentity(); transform.setOrigin(btVector3(btScalar(-0.35), btScalar(1.45), btScalar(0.))); transform.getBasis().setEulerZYX(0,0,SIMD_HALF_PI); m_bodies[BODYPART_LEFT_UPPER_ARM] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_LEFT_UPPER_ARM]); transform.setIdentity(); transform.setOrigin(btVector3(btScalar(-0.7), btScalar(1.45), btScalar(0.))); transform.getBasis().setEulerZYX(0,0,SIMD_HALF_PI); m_bodies[BODYPART_LEFT_LOWER_ARM] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_LEFT_LOWER_ARM]); transform.setIdentity(); transform.setOrigin(btVector3(btScalar(0.35), btScalar(1.45), btScalar(0.))); transform.getBasis().setEulerZYX(0,0,-SIMD_HALF_PI); m_bodies[BODYPART_RIGHT_UPPER_ARM] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_RIGHT_UPPER_ARM]); transform.setIdentity(); transform.setOrigin(btVector3(btScalar(0.7), btScalar(1.45), btScalar(0.))); transform.getBasis().setEulerZYX(0,0,-SIMD_HALF_PI); m_bodies[BODYPART_RIGHT_LOWER_ARM] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_RIGHT_LOWER_ARM]); // Setup some damping on the m_bodies for (int i = 0; i < BODYPART_COUNT; ++i) { m_bodies[i]->setDamping(0.05, 0.85); m_bodies[i]->setDeactivationTime(0.8); m_bodies[i]->setSleepingThresholds(1.6, 2.5); } // Now setup the constraints btHingeConstraint* hingeC; btConeTwistConstraint* coneC; btTransform localA, localB; localA.setIdentity(); localB.setIdentity(); localA.getBasis().setEulerZYX(0,SIMD_HALF_PI,0); localA.setOrigin(btVector3(btScalar(0.), btScalar(0.15), btScalar(0.))); localB.getBasis().setEulerZYX(0,SIMD_HALF_PI,0); localB.setOrigin(btVector3(btScalar(0.), btScalar(-0.15), btScalar(0.))); hingeC = new btHingeConstraint(*m_bodies[BODYPART_PELVIS], *m_bodies[BODYPART_SPINE], localA, localB); hingeC->setLimit(btScalar(-0.5f*SIMD_HALF_PI), btScalar(SIMD_HALF_PI)); m_joints[JOINT_PELVIS_SPINE] = hingeC; hingeC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE); m_ownerWorld->addConstraint(m_joints[JOINT_PELVIS_SPINE], true); localA.setIdentity(); localB.setIdentity(); localA.getBasis().setEulerZYX(0,0,SIMD_HALF_PI); localA.setOrigin(btVector3(btScalar(0.), btScalar(0.30), btScalar(0.))); localB.getBasis().setEulerZYX(0,0,SIMD_HALF_PI); localB.setOrigin(btVector3(btScalar(0.), btScalar(-0.14), btScalar(0.))); coneC = new btConeTwistConstraint(*m_bodies[BODYPART_SPINE], *m_bodies[BODYPART_HEAD], localA, localB); coneC->setLimit(0.5f*SIMD_HALF_PI, 0.5f*SIMD_HALF_PI, SIMD_HALF_PI); m_joints[JOINT_SPINE_HEAD] = coneC; coneC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE); m_ownerWorld->addConstraint(m_joints[JOINT_SPINE_HEAD], true); localA.setIdentity(); localB.setIdentity(); localA.getBasis().setEulerZYX(0,0,-0.5f*SIMD_HALF_PI*5); localA.setOrigin(btVector3(btScalar(-0.18), btScalar(-0.10), btScalar(0.))); localB.getBasis().setEulerZYX(0,0,-0.5f*SIMD_HALF_PI*5); localB.setOrigin(btVector3(btScalar(0.), btScalar(0.225), btScalar(0.))); coneC = new btConeTwistConstraint(*m_bodies[BODYPART_PELVIS], *m_bodies[BODYPART_LEFT_UPPER_LEG], localA, localB); coneC->setLimit(0.5f*SIMD_HALF_PI, 0.5f*SIMD_HALF_PI, 0); m_joints[JOINT_LEFT_HIP] = coneC; coneC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE); m_ownerWorld->addConstraint(m_joints[JOINT_LEFT_HIP], true); localA.setIdentity(); localB.setIdentity(); localA.getBasis().setEulerZYX(0,SIMD_HALF_PI,0); localA.setOrigin(btVector3(btScalar(0.), btScalar(-0.225), btScalar(0.))); localB.getBasis().setEulerZYX(0,SIMD_HALF_PI,0); localB.setOrigin(btVector3(btScalar(0.), btScalar(0.185), btScalar(0.))); hingeC = new btHingeConstraint(*m_bodies[BODYPART_LEFT_UPPER_LEG], *m_bodies[BODYPART_LEFT_LOWER_LEG], localA, localB); hingeC->setLimit(btScalar(0), btScalar(SIMD_HALF_PI)); m_joints[JOINT_LEFT_KNEE] = hingeC; hingeC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE); m_ownerWorld->addConstraint(m_joints[JOINT_LEFT_KNEE], true); localA.setIdentity(); localB.setIdentity(); localA.getBasis().setEulerZYX(0,0,0.5f*SIMD_HALF_PI); localA.setOrigin(btVector3(btScalar(0.18), btScalar(-0.10), btScalar(0.))); localB.getBasis().setEulerZYX(0,0,0.5f*SIMD_HALF_PI); localB.setOrigin(btVector3(btScalar(0.), btScalar(0.225), btScalar(0.))); coneC = new btConeTwistConstraint(*m_bodies[BODYPART_PELVIS], *m_bodies[BODYPART_RIGHT_UPPER_LEG], localA, localB); coneC->setLimit(0.5f*SIMD_HALF_PI, 0.5f*SIMD_HALF_PI, 0); m_joints[JOINT_RIGHT_HIP] = coneC; coneC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE); m_ownerWorld->addConstraint(m_joints[JOINT_RIGHT_HIP], true); localA.setIdentity(); localB.setIdentity(); localA.getBasis().setEulerZYX(0,SIMD_HALF_PI,0); localA.setOrigin(btVector3(btScalar(0.), btScalar(-0.225), btScalar(0.))); localB.getBasis().setEulerZYX(0,SIMD_HALF_PI,0); localB.setOrigin(btVector3(btScalar(0.), btScalar(0.185), btScalar(0.))); hingeC = new btHingeConstraint(*m_bodies[BODYPART_RIGHT_UPPER_LEG], *m_bodies[BODYPART_RIGHT_LOWER_LEG], localA, localB); hingeC->setLimit(btScalar(0), btScalar(SIMD_HALF_PI)); m_joints[JOINT_RIGHT_KNEE] = hingeC; hingeC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE); m_ownerWorld->addConstraint(m_joints[JOINT_RIGHT_KNEE], true); localA.setIdentity(); localB.setIdentity(); localA.getBasis().setEulerZYX(0,0,SIMD_PI); localA.setOrigin(btVector3(btScalar(-0.2), btScalar(0.15), btScalar(0.))); localB.getBasis().setEulerZYX(0,0,SIMD_HALF_PI); localB.setOrigin(btVector3(btScalar(0.), btScalar(-0.18), btScalar(0.))); coneC = new btConeTwistConstraint(*m_bodies[BODYPART_SPINE], *m_bodies[BODYPART_LEFT_UPPER_ARM], localA, localB); coneC->setLimit(SIMD_HALF_PI, SIMD_HALF_PI, 0); coneC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE); m_joints[JOINT_LEFT_SHOULDER] = coneC; m_ownerWorld->addConstraint(m_joints[JOINT_LEFT_SHOULDER], true); localA.setIdentity(); localB.setIdentity(); localA.getBasis().setEulerZYX(0,SIMD_HALF_PI,0); localA.setOrigin(btVector3(btScalar(0.), btScalar(0.18), btScalar(0.))); localB.getBasis().setEulerZYX(0,SIMD_HALF_PI,0); localB.setOrigin(btVector3(btScalar(0.), btScalar(-0.14), btScalar(0.))); hingeC = new btHingeConstraint(*m_bodies[BODYPART_LEFT_UPPER_ARM], *m_bodies[BODYPART_LEFT_LOWER_ARM], localA, localB); // hingeC->setLimit(btScalar(-SIMD_HALF_PI), btScalar(0)); hingeC->setLimit(btScalar(0), btScalar(SIMD_HALF_PI)); m_joints[JOINT_LEFT_ELBOW] = hingeC; hingeC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE); m_ownerWorld->addConstraint(m_joints[JOINT_LEFT_ELBOW], true); localA.setIdentity(); localB.setIdentity(); localA.getBasis().setEulerZYX(0,0,0); localA.setOrigin(btVector3(btScalar(0.2), btScalar(0.15), btScalar(0.))); localB.getBasis().setEulerZYX(0,0,SIMD_HALF_PI); localB.setOrigin(btVector3(btScalar(0.), btScalar(-0.18), btScalar(0.))); coneC = new btConeTwistConstraint(*m_bodies[BODYPART_SPINE], *m_bodies[BODYPART_RIGHT_UPPER_ARM], localA, localB); coneC->setLimit(SIMD_HALF_PI, SIMD_HALF_PI, 0); m_joints[JOINT_RIGHT_SHOULDER] = coneC; coneC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE); m_ownerWorld->addConstraint(m_joints[JOINT_RIGHT_SHOULDER], true); localA.setIdentity(); localB.setIdentity(); localA.getBasis().setEulerZYX(0,SIMD_HALF_PI,0); localA.setOrigin(btVector3(btScalar(0.), btScalar(0.18), btScalar(0.))); localB.getBasis().setEulerZYX(0,SIMD_HALF_PI,0); localB.setOrigin(btVector3(btScalar(0.), btScalar(-0.14), btScalar(0.))); hingeC = new btHingeConstraint(*m_bodies[BODYPART_RIGHT_UPPER_ARM], *m_bodies[BODYPART_RIGHT_LOWER_ARM], localA, localB); // hingeC->setLimit(btScalar(-SIMD_HALF_PI), btScalar(0)); hingeC->setLimit(btScalar(0), btScalar(SIMD_HALF_PI)); m_joints[JOINT_RIGHT_ELBOW] = hingeC; hingeC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE); m_ownerWorld->addConstraint(m_joints[JOINT_RIGHT_ELBOW], true); } virtual ~RagDoll () { int i; // Remove all constraints for ( i = 0; i < JOINT_COUNT; ++i) { m_ownerWorld->removeConstraint(m_joints[i]); delete m_joints[i]; m_joints[i] = 0; } // Remove all bodies and shapes for ( i = 0; i < BODYPART_COUNT; ++i) { m_ownerWorld->removeRigidBody(m_bodies[i]); delete m_bodies[i]->getMotionState(); delete m_bodies[i]; m_bodies[i] = 0; delete m_shapes[i]; m_shapes[i] = 0; } } }; RagDollDemo::RagDollDemo(SimpleOpenGL3App* app) :BasicDemo(app) { } RagDollDemo::~RagDollDemo() { } void RagDollDemo::initPhysics() { Bullet2RigidBodyDemo::initPhysics(); int cubeShapeId = m_glApp->registerCubeShape(); createGround(cubeShapeId); btVector3 offset(0,10,0); RagDoll* doll = new RagDoll(this->m_dynamicsWorld,offset,m_glApp); m_glApp->m_instancingRenderer->writeTransforms(); }