コード例 #1
0
ファイル: physics.cpp プロジェクト: DreadIsBack/BlendELF
void elfRecalcJoint(elfJoint* joint)
{
	elfVec3f pos1;
	elfVec3f pos2;
	elfVec4f qua1;
	elfVec4f qua2;
	elfVec4f aqua1;
	elfVec4f aqua2;
	elfVec3f worldCoordPivot1;
	elfVec3f localCoordPivot2;
	elfVec3f localAxis1;
	elfVec3f localAxis2;
	float matrix1[16];
	float matrix2[16];
	float matrix3[16];

	pos1 = elfGetActorPosition(joint->actor1);
	pos2 = elfGetActorPosition(joint->actor2);
	qua1 = elfGetActorOrientation(joint->actor1);
	qua2 = elfGetActorOrientation(joint->actor2);

	worldCoordPivot1.x = joint->pivot[0];
	worldCoordPivot1.y = joint->pivot[1];
	worldCoordPivot1.z = joint->pivot[2];

	worldCoordPivot1 = elfAddVec3fVec3f(elfMulQuaVec3f(qua1, worldCoordPivot1), pos1);
	localCoordPivot2 = elfMulQuaVec3f(elfGetQuaInverted(qua2), elfSubVec3fVec3f(worldCoordPivot1, pos2));

	btVector3 pivotInA(joint->pivot[0], joint->pivot[1], joint->pivot[2]);
	btVector3 pivotInB(localCoordPivot2.x, localCoordPivot2.y, localCoordPivot2.z);

	aqua1 = elfCreateQuaFromEuler(joint->axis[0], joint->axis[1], joint->axis[2]);
	localAxis1 = elfMulQuaVec3f(aqua1, elfCreateVec3f(0.0f, 0.0f, 1.0f));

	aqua2 = elfMulQuaQua(aqua1, elfMulQuaQua(qua1, elfGetQuaInverted(qua2)));
	localAxis2 = elfMulQuaVec3f(aqua2, elfCreateVec3f(0.0f, 0.0f, 1.0f));

	btVector3 axisInA(localAxis1.x, localAxis1.y, localAxis1.z);
	btVector3 axisInB(localAxis2.x, localAxis2.y, localAxis2.z);

	if(joint->jointType == ELF_HINGE)
	{
		joint->constraint = new btHingeConstraint(*joint->actor1->object->body,* joint->actor2->object->body,
			pivotInA, pivotInB, axisInA, axisInB);
		joint->actor1->scene->world->world->addConstraint(joint->constraint);
	}
	else if(joint->jointType == ELF_BALL)
	{
		joint->constraint = new btPoint2PointConstraint(*joint->actor1->object->body,* joint->actor2->object->body, pivotInA, pivotInB);
		joint->actor1->scene->world->world->addConstraint(joint->constraint);
	}
	else if(joint->jointType == ELF_CONE_TWIST)
	{
		gfxMatrix4SetIdentity(matrix1);
		matrix1[12] = joint->pivot[0];
		matrix1[13] = joint->pivot[1];
		matrix1[14] = joint->pivot[2];
		gfxQuaToMatrix4(&aqua1.x, matrix2);
		gfxMulMatrix4Matrix4(matrix1, matrix2, matrix3);
		btTransform frameInA;
		frameInA.setFromOpenGLMatrix(matrix3);

		gfxMatrix4SetIdentity(matrix1);
		matrix1[12] = localCoordPivot2.x;
		matrix1[13] = localCoordPivot2.y;
		matrix1[14] = localCoordPivot2.z;
		gfxQuaToMatrix4(&aqua2.x, matrix2);
		gfxMulMatrix4Matrix4(matrix1, matrix2, matrix3);
		btTransform frameInB;
		frameInB.setFromOpenGLMatrix(matrix3);

		joint->constraint = new btConeTwistConstraint(*joint->actor1->object->body,
			*joint->actor2->object->body, frameInA, frameInB);
		joint->actor1->scene->world->world->addConstraint(joint->constraint);
	}
}
コード例 #2
0
ファイル: BasicDemo.cpp プロジェクト: pbarragan/basicBayes
void BasicDemo::initPhysics(){

  //printing
  debug_print_ = false;

  //set up world
  broadphase_ = new btDbvtBroadphase();
  
  collisionConfiguration_ = new btDefaultCollisionConfiguration();
  dispatcher_ = new btCollisionDispatcher(collisionConfiguration_);
  
  solver_ = new btSequentialImpulseConstraintSolver;
  
  dynamicsWorld_ = new btDiscreteDynamicsWorld(dispatcher_,broadphase_,solver_,collisionConfiguration_);

  //set gravity. y is apparently up.
  dynamicsWorld_->setGravity(btVector3(0,-10,0));

  //--------------OBJECT CREATION SECTION-----------------//

  //make the ground plane
  groundCollisionShape_ = new btBoxShape(btVector3(btScalar(50.),btScalar(50.),btScalar(50.)));
  //collisionShapes_.push_back(groundCollisionShape_);
  btTransform groundTransform;
  groundTransform.setIdentity();
  groundTransform.setOrigin(btVector3(0.0f,-55.0f,0.0f));
  btScalar groundMass(0.0);

  //create the ground plane rigid body
  groundRigidBody_ = createRigidBody(groundCollisionShape_,groundMass,groundTransform);
  //add it to the dynamics world
  dynamicsWorld_->addRigidBody(groundRigidBody_);

  //Calculate the required origins based on startPose_ given by the runSimulation function
  btVector3 bravoOrigin = startPose_;
  btVector3 tangoOrigin = startPose_;
  //tangoOrigin.setX(tangoOrigin.getX()+1.5);
  
  //make bravo rigid body (the sliding box)
  const btVector3 bravoBoxHalfExtents( 1.0f, 1.0f, 1.0f );
  bravoCollisionShape_ = new btBoxShape(bravoBoxHalfExtents);
  //collisionShapes_.push_back(bravoCollisionShape_);
  btTransform bravoTransform;
  bravoTransform.setIdentity();
  //bravoTransform.setOrigin(btVector3(0.0f,1.0f,0.0f));
  bravoTransform.setOrigin(bravoOrigin);
  btScalar bravoMass = 1.0f;

  //create the bravo rigid body
  bravoRigidBody_ = createRigidBody(bravoCollisionShape_,bravoMass,bravoTransform);
  //add it to the dynamics world
  dynamicsWorld_->addRigidBody(bravoRigidBody_);

  //make tango rigid body (the robots manipulator)
  const btVector3 tangoBoxHalfExtents( 0.1f, 0.5f, 0.1f );
  tangoCollisionShape_ = new btBoxShape(tangoBoxHalfExtents);
  //collisionShapes_.push_back(tangoCollisionShape_);
  btTransform tangoTransform;
  tangoTransform.setIdentity();
  //tangoTransform.setOrigin(btVector3(1.5f,1.0f,0.0f));
  tangoTransform.setOrigin(tangoOrigin);
  btScalar tangoMass = 0.1f;

  //create the tango rigid body
  tangoRigidBody_ = createRigidBody(tangoCollisionShape_,tangoMass,tangoTransform);
  //add it to the dynamics world
  dynamicsWorld_->addRigidBody(tangoRigidBody_);

  //--------------END OBJECT CREATION SECTION-----------------//

  //--------------CONSTRAINT CREATION SECTION-----------------//
  
  // create a constraint
  //const btVector3 pivotInA( 1.5f, 0.0f, 0.0f );
  const btVector3 pivotInA( 0.0f, 0.0f, 0.0f );   
  const btVector3 pivotInB( 0.0f, 0.0f, 0.0f );
  btVector3 axisInA( 0.0f, 1.0f, 0.0f );
  btVector3 axisInB( 0.0f, 1.0f, 0.0f );
  bool useReferenceFrameA = false;
  hingeConstraint_ = new btHingeConstraint(*bravoRigidBody_,*tangoRigidBody_,pivotInA,pivotInB,axisInA,axisInB,useReferenceFrameA);
  
  // set joint feedback
  hingeConstraint_->setJointFeedback(&jfRobot_);
  // add constraint to the world
  const bool isDisableCollisionsBetweenLinkedBodies = true; //this used to be false
  dynamicsWorld_->addConstraint(hingeConstraint_, 
				  isDisableCollisionsBetweenLinkedBodies);
  
  //--------------END CONSTRAINT CREATION SECTION-----------------//

  //--------------INITIALIZE REMAINING PARAMETERS SECTION-----------------//
  
  //set controller values
  pGains_.setValue(5.0f,50.0f,5.0f);
  dGains_.setValue(2.0f,2.0f,2.0f);
  
  //initialize
  tangoRigidBody_->getMotionState()->getWorldTransform(tangoBodyTrans_);
  currentPose_ = tangoBodyTrans_.getOrigin();
  desiredPose_ = currentPose_;
  bravoRigidBody_->forceActivationState(4);
  count_ = 0;
  
  //--------------END INITIALIZE REMAINING PARAMETERS SECTION-----------------//
  
}
コード例 #3
0
int main(int argc,char** argv)
{

	int i;
	for (i=0;i<numObjects;i++)
	{
		if (i>0)
		{
			shapePtr[i] = prebuildShapePtr[1];
			shapeIndex[i] = 1;//sphere
		}
		else
		{
			shapeIndex[i] = 0;
			shapePtr[i] = prebuildShapePtr[0];
		}
	}
	
	ConvexDecomposition::WavefrontObj wo;
	char* filename = "file.obj";
	tcount = wo.loadObj(filename);

	class MyConvexDecomposition : public ConvexDecomposition::ConvexDecompInterface
	{
		public:

		MyConvexDecomposition (FILE* outputFile)
			:mBaseCount(0),
			mHullCount(0),
			mOutputFile(outputFile)

		{
		}
		
			virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result)
			{

				TriangleMesh* trimesh = new TriangleMesh();

				SimdVector3 localScaling(6.f,6.f,6.f);

				//export data to .obj
				printf("ConvexResult\n");
				if (mOutputFile)
				{
					fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount );

					fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount);
					fprintf(mOutputFile,"o Object%i\r\n",mBaseCount);

					for (unsigned int i=0; i<result.mHullVcount; i++)
					{
						const float *p = &result.mHullVertices[i*3];
						fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] );
					}

					//calc centroid, to shift vertices around center of mass
					centroids[numObjects] = SimdVector3(0,0,0);
					if ( 1 )
					{
						const unsigned int *src = result.mHullIndices;
						for (unsigned int i=0; i<result.mHullTcount; i++)
						{
							unsigned int index0 = *src++;
							unsigned int index1 = *src++;
							unsigned int index2 = *src++;
							SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]);
							SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]);
							SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]);
							vertex0 *= localScaling;
							vertex1 *= localScaling;
							vertex2 *= localScaling;
							centroids[numObjects] += vertex0;
							centroids[numObjects]+= vertex1;
							centroids[numObjects]+= vertex2;
							
						}
					}

					centroids[numObjects] *= 1.f/(float(result.mHullTcount) * 3);

					if ( 1 )
					{
						const unsigned int *src = result.mHullIndices;
						for (unsigned int i=0; i<result.mHullTcount; i++)
						{
							unsigned int index0 = *src++;
							unsigned int index1 = *src++;
							unsigned int index2 = *src++;


							SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]);
							SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]);
							SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]);
							vertex0 *= localScaling;
							vertex1 *= localScaling;
							vertex2 *= localScaling;
							
							vertex0 -= centroids[numObjects];
							vertex1 -= centroids[numObjects];
							vertex2 -= centroids[numObjects];

							trimesh->AddTriangle(vertex0,vertex1,vertex2);

							index0+=mBaseCount;
							index1+=mBaseCount;
							index2+=mBaseCount;
							
							fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 );
						}
					}

					shapeIndex[numObjects] = numObjects;
					shapePtr[numObjects++] = new ConvexTriangleMeshShape(trimesh);
					
					mBaseCount+=result.mHullVcount; // advance the 'base index' counter.


				}
			}

			int   	mBaseCount;
  			int		mHullCount;
			FILE*	mOutputFile;

	};

	if (tcount)
	{
		numObjects = 1; //always have the ground object first
		
		TriangleMesh* trimesh = new TriangleMesh();

		SimdVector3 localScaling(6.f,6.f,6.f);
		
		for (int i=0;i<wo.mTriCount;i++)
		{
			int index0 = wo.mIndices[i*3];
			int index1 = wo.mIndices[i*3+1];
			int index2 = wo.mIndices[i*3+2];

			SimdVector3 vertex0(wo.mVertices[index0*3], wo.mVertices[index0*3+1],wo.mVertices[index0*3+2]);
			SimdVector3 vertex1(wo.mVertices[index1*3], wo.mVertices[index1*3+1],wo.mVertices[index1*3+2]);
			SimdVector3 vertex2(wo.mVertices[index2*3], wo.mVertices[index2*3+1],wo.mVertices[index2*3+2]);
			
			vertex0 *= localScaling;
			vertex1 *= localScaling;
			vertex2 *= localScaling;

			trimesh->AddTriangle(vertex0,vertex1,vertex2);
		}

		shapePtr[numObjects++] = new ConvexTriangleMeshShape(trimesh);
	}
			

	if (tcount)
	{

		char outputFileName[512];
  		strcpy(outputFileName,filename);
  		char *dot = strstr(outputFileName,".");
  		if ( dot ) 
			*dot = 0;
		strcat(outputFileName,"_convex.obj");
  		FILE* outputFile = fopen(outputFileName,"wb");
				
		unsigned int depth = 7;
		float cpercent     = 5;
		float ppercent     = 15;
		unsigned int maxv  = 16;
		float skinWidth    = 0.01;

		printf("WavefrontObj num triangles read %i",tcount);
		ConvexDecomposition::DecompDesc desc;
		desc.mVcount       =	wo.mVertexCount;
		desc.mVertices     = wo.mVertices;
		desc.mTcount       = wo.mTriCount;
		desc.mIndices      = (unsigned int *)wo.mIndices;
		desc.mDepth        = depth;
		desc.mCpercent     = cpercent;
		desc.mPpercent     = ppercent;
		desc.mMaxVertices  = maxv;
		desc.mSkinWidth    = skinWidth;

		MyConvexDecomposition	convexDecomposition(outputFile);
		desc.mCallback = &convexDecomposition;
		
		

		//convexDecomposition.performConvexDecomposition(desc);

		ConvexBuilder cb(desc.mCallback);
		int ret = cb.process(desc);
		
		if (outputFile)
			fclose(outputFile);


	}

	CollisionDispatcher* dispatcher = new	CollisionDispatcher();


	SimdVector3 worldAabbMin(-10000,-10000,-10000);
	SimdVector3 worldAabbMax(10000,10000,10000);

	OverlappingPairCache* broadphase = new AxisSweep3(worldAabbMin,worldAabbMax);
	//OverlappingPairCache* broadphase = new SimpleBroadphase();

	physicsEnvironmentPtr = new CcdPhysicsEnvironment(dispatcher,broadphase);
	physicsEnvironmentPtr->setDeactivationTime(2.f);

	physicsEnvironmentPtr->setGravity(0,-10,0);
	PHY_ShapeProps shapeProps;

	shapeProps.m_do_anisotropic = false;
	shapeProps.m_do_fh = false;
	shapeProps.m_do_rot_fh = false;
	shapeProps.m_friction_scaling[0] = 1.;
	shapeProps.m_friction_scaling[1] = 1.;
	shapeProps.m_friction_scaling[2] = 1.;

	shapeProps.m_inertia = 1.f;
	shapeProps.m_lin_drag = 0.2f;
	shapeProps.m_ang_drag = 0.1f;
	shapeProps.m_mass = 10.0f;

	PHY_MaterialProps materialProps;
	materialProps.m_friction = 10.5f;
	materialProps.m_restitution = 0.0f;

	CcdConstructionInfo ccdObjectCi;
	ccdObjectCi.m_friction = 0.5f;

	ccdObjectCi.m_linearDamping = shapeProps.m_lin_drag;
	ccdObjectCi.m_angularDamping = shapeProps.m_ang_drag;

	SimdTransform tr;
	tr.setIdentity();



	for (i=0;i<numObjects;i++)
	{
		shapeProps.m_shape = shapePtr[shapeIndex[i]];
		shapeProps.m_shape->SetMargin(0.05f);



		bool isDyna = i>0;
		//if (i==1)
		//	isDyna=false;

		if (0)//i==1)
		{
			SimdQuaternion orn(0,0,0.1*SIMD_HALF_PI);
			ms[i].setWorldOrientation(orn.x(),orn.y(),orn.z(),orn[3]);
		}


		if (i>0)
		{

			switch (i)
			{
			case 1:
				{
					ms[i].setWorldPosition(0,10,0);
					//for testing, rotate the ground cube so the stack has to recover a bit

					break;
				}
			case 2:
				{
					ms[i].setWorldPosition(0,8,2);
					break;
				}
			default:
				ms[i].setWorldPosition(0,i*CUBE_HALF_EXTENTS*2 - CUBE_HALF_EXTENTS,0);
			}

			float quatIma0,quatIma1,quatIma2,quatReal;
			SimdQuaternion quat;
			SimdVector3 axis(0,0,1);
			SimdScalar angle=0.5f;

			quat.setRotation(axis,angle);

			ms[i].setWorldOrientation(quat.getX(),quat.getY(),quat.getZ(),quat[3]);



		} else
		{
			ms[i].setWorldPosition(0,-10+EXTRA_HEIGHT,0);

		}

		ccdObjectCi.m_MotionState = &ms[i];
		ccdObjectCi.m_gravity = SimdVector3(0,0,0);
		ccdObjectCi.m_localInertiaTensor =SimdVector3(0,0,0);
		if (!isDyna)
		{
			shapeProps.m_mass = 0.f;
			ccdObjectCi.m_mass = shapeProps.m_mass;
			ccdObjectCi.m_collisionFlags = CollisionObject::isStatic;
		}
		else
		{
			shapeProps.m_mass = 1.f;
			ccdObjectCi.m_mass = shapeProps.m_mass;
			ccdObjectCi.m_collisionFlags = 0;
		}


		SimdVector3 localInertia;
		if (shapePtr[shapeIndex[i]]->GetShapeType() == EMPTY_SHAPE_PROXYTYPE)
		{
			//take inertia from first shape
			shapePtr[1]->CalculateLocalInertia(shapeProps.m_mass,localInertia);
		} else
		{
			shapePtr[shapeIndex[i]]->CalculateLocalInertia(shapeProps.m_mass,localInertia);
		}
		ccdObjectCi.m_localInertiaTensor = localInertia;

		ccdObjectCi.m_collisionShape = shapePtr[shapeIndex[i]];


		physObjects[i]= new CcdPhysicsController( ccdObjectCi);

		// Only do CCD if  motion in one timestep (1.f/60.f) exceeds CUBE_HALF_EXTENTS
		physObjects[i]->GetRigidBody()->m_ccdSquareMotionTreshold = CUBE_HALF_EXTENTS;
		
		//Experimental: better estimation of CCD Time of Impact:
		//physObjects[i]->GetRigidBody()->m_ccdSweptShereRadius = 0.5*CUBE_HALF_EXTENTS;

		physicsEnvironmentPtr->addCcdPhysicsController( physObjects[i]);

		if (i==1)
		{
			//physObjects[i]->SetAngularVelocity(0,0,-2,true);
		}

		physicsEnvironmentPtr->setDebugDrawer(&debugDrawer);

	}


	//create a constraint
	if (createConstraint)
	{
		//physObjects[i]->SetAngularVelocity(0,0,-2,true);
		int constraintId;

		float pivotX=CUBE_HALF_EXTENTS,
			pivotY=-CUBE_HALF_EXTENTS,
			pivotZ=CUBE_HALF_EXTENTS;

		float axisX=1,axisY=0,axisZ=0;



		HingeConstraint* hinge = 0;

		SimdVector3 pivotInA(CUBE_HALF_EXTENTS,-CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS);
		SimdVector3 pivotInB(-CUBE_HALF_EXTENTS,-CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS);
		SimdVector3 axisInA(0,1,0);
		SimdVector3 axisInB(0,-1,0);

		RigidBody* rb0 = physObjects[1]->GetRigidBody();
		RigidBody* rb1 = physObjects[2]->GetRigidBody();

		hinge = new HingeConstraint(
			*rb0,
			*rb1,pivotInA,pivotInB,axisInA,axisInB);

		physicsEnvironmentPtr->m_constraints.push_back(hinge);

		hinge->SetUserConstraintId(100);
		hinge->SetUserConstraintType(PHY_LINEHINGE_CONSTRAINT);

	}




	clientResetScene();

	setCameraDistance(26.f);

	return glutmain(argc, argv,640,480,"Bullet Physics Demo. http://www.continuousphysics.com/Bullet/phpBB2/");
}
コード例 #4
0
ファイル: TestHingeTorque.cpp プロジェクト: 20-sim/bullet3
void TestHingeTorque::initPhysics()
{
	int upAxis = 1;
	m_guiHelper->setUpAxis(upAxis);

	createEmptyDynamicsWorld();
	m_dynamicsWorld->getSolverInfo().m_splitImpulse = false;
	
    m_dynamicsWorld->setGravity(btVector3(0,0,-10));
    
	m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld);
	int mode = 	btIDebugDraw::DBG_DrawWireframe
				+btIDebugDraw::DBG_DrawConstraints
				+btIDebugDraw::DBG_DrawConstraintLimits;
	m_dynamicsWorld->getDebugDrawer()->setDebugMode(mode);


	{ // create a door using hinge constraint attached to the world
        
        int numLinks = 2;
        bool spherical = false;					//set it ot false -to use 1DoF hinges instead of 3DoF sphericals
        bool canSleep = false;
        bool selfCollide = false;
        btVector3 linkHalfExtents(0.05, 0.37, 0.1);
        btVector3 baseHalfExtents(0.05, 0.37, 0.1);

        btBoxShape* baseBox = new btBoxShape(baseHalfExtents);
        btVector3 basePosition = btVector3(-0.4f, 3.f, 0.f);
        btTransform baseWorldTrans;
        baseWorldTrans.setIdentity();
        baseWorldTrans.setOrigin(basePosition);
        
        //mbC->forceMultiDof();							//if !spherical, you can comment this line to check the 1DoF algorithm
        //init the base
        btVector3 baseInertiaDiag(0.f, 0.f, 0.f);
        float baseMass = 0.f;
        float linkMass = 1.f;
        
        btRigidBody* base = createRigidBody(baseMass,baseWorldTrans,baseBox);
        m_dynamicsWorld->removeRigidBody(base);
        base->setDamping(0,0);
        m_dynamicsWorld->addRigidBody(base,collisionFilterGroup,collisionFilterMask);
        btBoxShape* linkBox1 = new btBoxShape(linkHalfExtents);
		btSphereShape* linkSphere = new btSphereShape(radius);
		
        btRigidBody* prevBody = base;
        
        for (int i=0;i<numLinks;i++)
        {
            btTransform linkTrans;
            linkTrans = baseWorldTrans;
            
            linkTrans.setOrigin(basePosition-btVector3(0,linkHalfExtents[1]*2.f*(i+1),0));
            
			btCollisionShape* colOb = 0;
			
			if (i==0)
			{
				colOb = linkBox1;
			} else 
			{
				colOb = linkSphere;
			}
            btRigidBody* linkBody = createRigidBody(linkMass,linkTrans,colOb);
            m_dynamicsWorld->removeRigidBody(linkBody);
            m_dynamicsWorld->addRigidBody(linkBody,collisionFilterGroup,collisionFilterMask);
            linkBody->setDamping(0,0);
			btTypedConstraint* con = 0;
			
			if (i==0)
			{
				//create a hinge constraint
				btVector3 pivotInA(0,-linkHalfExtents[1],0);
				btVector3 pivotInB(0,linkHalfExtents[1],0);
				btVector3 axisInA(1,0,0);
				btVector3 axisInB(1,0,0);
				bool useReferenceA = true;
				btHingeConstraint* hinge = new btHingeConstraint(*prevBody,*linkBody,
																 pivotInA,pivotInB,
																 axisInA,axisInB,useReferenceA);
				con = hinge;
			} else
			{
				
				btTransform pivotInA(btQuaternion::getIdentity(),btVector3(0, -radius, 0));						//par body's COM to cur body's COM offset
				btTransform pivotInB(btQuaternion::getIdentity(),btVector3(0, radius, 0));							//cur body's COM to cur body's PIV offset
				btGeneric6DofSpring2Constraint* fixed = new btGeneric6DofSpring2Constraint(*prevBody, *linkBody,
																						   pivotInA,pivotInB);
				fixed->setLinearLowerLimit(btVector3(0,0,0));
				fixed->setLinearUpperLimit(btVector3(0,0,0));
				fixed->setAngularLowerLimit(btVector3(0,0,0));
				fixed->setAngularUpperLimit(btVector3(0,0,0));
				
				con = fixed;

			}
			btAssert(con);
			if (con)
			{
				btJointFeedback* fb = new btJointFeedback();
				m_jointFeedback.push_back(fb);
				con->setJointFeedback(fb);

				m_dynamicsWorld->addConstraint(con,true);
			}
			prevBody = linkBody;
            
        }
       
	}
	
	if (1)
	{
		btVector3 groundHalfExtents(1,1,0.2);
		groundHalfExtents[upAxis]=1.f;
		btBoxShape* box = new btBoxShape(groundHalfExtents);
		box->initializePolyhedralFeatures();
		
		btTransform start; start.setIdentity();
		btVector3 groundOrigin(-0.4f, 3.f, 0.f);
		btVector3 basePosition = btVector3(-0.4f, 3.f, 0.f);
		btQuaternion groundOrn(btVector3(0,1,0),0.25*SIMD_PI);
		
		groundOrigin[upAxis] -=.5;
		groundOrigin[2]-=0.6;
		start.setOrigin(groundOrigin);
	//	start.setRotation(groundOrn);
		btRigidBody* body =  createRigidBody(0,start,box);
		body->setFriction(0);
		
	}
	m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld);
}