示例#1
0
BigRigDemo::BigRigDemo(hkDemoEnvironment* env) : CarDemo(env, false)
{
    // Create the vehicles

        //
        // Create tractor shape.
        //
        hkpListShape* tractorShape = HK_NULL;
        {
            hkReal xSize = 1.9f;
            hkReal xSizeFrontTop = 0.7f;
            hkReal xSizeFrontMid = 1.6f;
            hkReal ySize = 0.9f;
            hkReal ySizeMid = ySize - 0.7f;
            hkReal zSize = 1.0f;
            
            //hkReal xBumper = 1.9f;
            //hkReal yBumper = 0.35f;
            //hkReal zBumper = 1.0f;
            
            hkVector4 halfExtents(1.0f, 0.35f, 1.0f);
            
            // 16 = 4 (size of "each float group", 3 for x,y,z, 1 for padding) * 4 (size of float).
            int stride = sizeof(float) * 4;
            
            {
                int numVertices = 10;
                
                float vertices[] = { 
                    xSizeFrontTop, ySize, zSize, 0.0f,	// v0
                        xSizeFrontTop, ySize, -zSize, 0.0f,	// v1
                        xSize, -ySize, zSize, 0.0f,			// v2
                        xSize, -ySize, -zSize, 0.0f,		// v3
                        -xSize, ySize, zSize, 0.0f,			// v4
                        -xSize, ySize, -zSize, 0.0f,		// v5
                        -xSize, -ySize, zSize, 0.0f,		// v6
                        -xSize, -ySize, -zSize, 0.0f,		// v7
                        xSizeFrontMid, ySizeMid, zSize, 0.0f,	// v8
                        xSizeFrontMid, ySizeMid, -zSize, 0.0f,	// v9
                };
                
                hkpBoxShape* boxShape = new hkpBoxShape(halfExtents, 0.05f );

				hkTransform transform;
                transform.setIdentity();
                transform.setTranslation(hkVector4(-2.5f, -0.55f, 0.0f));
                
                hkpConvexTransformShape* transformShape = new hkpConvexTransformShape(boxShape, transform);
				boxShape->removeReference();
                
				hkpConvexVerticesShape* convexShape;
				{
					hkStridedVertices stridedVerts;
					{
						stridedVerts.m_numVertices = numVertices;
						stridedVerts.m_striding = stride;
						stridedVerts.m_vertices = vertices;
					}

					convexShape = new hkpConvexVerticesShape(stridedVerts);
				}
                
                hkArray<hkpShape*> shapeArray;
                shapeArray.pushBack(transformShape);
                shapeArray.pushBack(convexShape);
                
                tractorShape = new hkpListShape(shapeArray.begin(), shapeArray.getSize());
				transformShape->removeReference();
				convexShape->removeReference();
            }
        }
        
        //
        // Create trailer shape.
        //
        hkpListShape* trailerShape = HK_NULL;
        {
            hkVector4 halfExtents1(5.0f, 1.5f, 1.0f); // Box
            hkVector4 halfExtents2(1.0f, 1.0f, 1.0f); // Tongue
            
            hkTransform transform;
            transform.setIdentity();
            
            {						
                hkpBoxShape* boxShape1 = new hkpBoxShape(halfExtents1, 0.05f );
                hkpBoxShape* boxShape2 = new hkpBoxShape(halfExtents2, 0.05f );
                
                transform.setTranslation(hkVector4(6.0f, 0.5f, 0.0f));
				hkpConvexTransformShape* transformShape = new hkpConvexTransformShape(boxShape2, transform);
				boxShape2->removeReference();
                
                hkArray<hkpShape*> shapeArray;
                shapeArray.pushBack(boxShape1);
                shapeArray.pushBack(transformShape);
                
                trailerShape = new hkpListShape(shapeArray.begin(), shapeArray.getSize());
				boxShape1->removeReference();
				transformShape->removeReference();
            }
        }
        
        // Create the tractor vehicles
        {
		m_world->lock();
		{
			HK_ASSERT(0x526edf5d, m_world->getCollisionFilter() && m_world->getCollisionFilter()->m_type == hkpCollisionFilter::HK_FILTER_GROUP);
			hkpGroupFilter* groupFilter = static_cast<hkpGroupFilter*>(const_cast<hkpCollisionFilter*>(m_world->getCollisionFilter()));
			m_vehicles.clear();
            for (int vehicleId = 0; vehicleId < m_numVehicles; vehicleId++)
            {
				int vehicleGroup = groupFilter->getNewSystemGroup();
                //
                // Create the tractor.
                //
                {
                    //
                    // Create the tractor body.
                    //
                    hkpRigidBody* tractorRigidBody;
                    {
                        hkpRigidBodyCinfo tractorInfo;
                        tractorInfo.m_shape = tractorShape;
                        tractorInfo.m_friction = 0.8f;
                        tractorInfo.m_motionType = hkpMotion::MOTION_BOX_INERTIA;
						tractorInfo.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo(0, vehicleGroup );

						// Position chassis on the ground.
                        tractorInfo.m_position.set(0.0f, -3.0f, (vehicleId + 1) * 9.0f);
                        //tractorInfo.m_angularDamping = 0.5f;

						// No need to set the inertia tensor, as this will be set automatically by the vehicle setup
						tractorInfo.m_mass = 15000.0f;
						tractorInfo.m_inertiaTensor.setDiagonal( 1.f, 1.f, 1.f );
						tractorInfo.m_centerOfMass.set( -1.0f, -0.8f, 0.0f);
                                              
                        tractorRigidBody = new hkpRigidBody(tractorInfo);
                    }

					m_vehicles.expandOne();
					TractorSetup tsetup;
                    createTractorVehicle( tsetup, tractorRigidBody, m_vehicles.getSize()-1);
                    tractorRigidBody->removeReference();
                }

				//
                // Create the trailer body.
                //
				{
                    hkpRigidBody* trailerRigidBody;
                    {
                        hkpRigidBodyCinfo trailerInfo;
                        trailerInfo.m_shape = trailerShape;
                        trailerInfo.m_friction = 0.8f;
                        trailerInfo.m_motionType = hkpMotion::MOTION_BOX_INERTIA;
                        trailerInfo.m_position.set(-9.0f, -3.0f, (1 + vehicleId) * 9.0f);
						trailerInfo.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo(0, vehicleGroup );

						// No need to set the inertia tensor, as this will be set automatically by the vehicle setup
                        trailerInfo.m_mass = 10000.0f;
						trailerInfo.m_inertiaTensor.setDiagonal( 1.f, 1.f, 1.f );

						// Trailers are generally bottom-heavy to improve stability.
						// Move the centre of mass lower but keep it within the chassis limits.
						trailerInfo.m_centerOfMass.set(-1.0f, -1.0f, 0.0f);
                                              
                        trailerRigidBody = new hkpRigidBody(trailerInfo);
                    }
                    
					m_vehicles.expandOne();
					TrailerSetup tsetup;
					createTrailerVehicle( tsetup, trailerRigidBody, m_vehicles.getSize()-1);

					HK_SET_OBJECT_COLOR((hkUlong)trailerRigidBody->getCollidable(), 0x80ff8080);
                    
                    trailerRigidBody->removeReference();
                }
            }
            
            tractorShape->removeReference();
            trailerShape->removeReference();
        }
		
	//
	//	Create the wheels
	//
		createDisplayWheels(0.5f, 0.2f);


    // Attach Tractors and Trailers
        for (int vehicleId = 0; vehicleId < m_vehicles.getSize(); vehicleId+=2)
        {
            hkpRigidBody* tractor = m_vehicles[vehicleId].m_vehicle->getChassis();
            hkpRigidBody* trailer = m_vehicles[vehicleId + 1 ].m_vehicle->getChassis();


			//
			// Use a hinge constraint to connect the tractor to the trailer
			//
			if (0)
	        {
				//
			    // Set the pivot
				//
		        hkVector4 axis(0.0f, 1.0f, 0.0f);
				hkVector4 point1(-3.5f, 0.4f, 0.0f);
				hkVector4 point2(6.0f, -0.4f, 0.0f);

			        // Create constraint
				hkpHingeConstraintData* hc = new hkpHingeConstraintData(); 
		        hc->setInBodySpace(point1, point2, axis, axis); 
		        m_world->createAndAddConstraintInstance( tractor, trailer, hc )->removeReference();
		        hc->removeReference();  
	        }
			
			//
			// Use a ball-and-socket constraint to connect the tractor to the trailer
			//
			else if (0)
			{
				hkVector4 point1(-3.5f, 0.4f, 0.0f);
				hkVector4 point2(6.0f, -0.4f, 0.0f);

				// Create the constraint
				hkpBallAndSocketConstraintData* bs = new hkpBallAndSocketConstraintData(); 
				bs->setInBodySpace(point1, point2);
				m_world->createAndAddConstraintInstance( tractor, trailer, bs )->removeReference();
				bs->removeReference();  
			}

			//
			// Use a ragdoll constraint to connect the tractor to the trailer
			//
			else if(1)
			{
				hkReal planeMin =  HK_REAL_PI * -0.45f;
				hkReal planeMax =  HK_REAL_PI * 0.45f;
				hkReal twistMin =  HK_REAL_PI * -0.005f;
				hkReal twistMax =  HK_REAL_PI *  0.005f;
				hkReal coneMin  =  HK_REAL_PI * -0.55f;
				hkReal coneMax = HK_REAL_PI * 0.55f;

				hkpRagdollConstraintData* rdc = new hkpRagdollConstraintData();
				rdc->setPlaneMinAngularLimit(planeMin);
				rdc->setPlaneMaxAngularLimit(planeMax);
				rdc->setTwistMinAngularLimit(twistMin);
				rdc->setTwistMaxAngularLimit(twistMax);

				hkVector4 twistAxisA(1.0f, 0.0f, 0.0f);
				hkVector4 planeAxisA(0.0f, 0.0f, 1.0f);
				hkVector4 twistAxisB(1.0f, 0.0f, 0.0f);
				hkVector4 planeAxisB(0.0f, 0.0f, 1.0f);
				hkVector4 point1(-2.3f, -0.7f, 0.0f);
				hkVector4 point2( 7.2f, -1.3f, 0.0f);

				rdc->setInBodySpace(point1, point2, planeAxisA, planeAxisB, twistAxisA, twistAxisB);
				rdc->setAsymmetricConeAngle(coneMin, coneMax);
				m_world->createAndAddConstraintInstance(tractor, trailer, rdc)->removeReference();
				rdc->removeReference();
			}
        }
		m_world->unlock();
    }
    
    //
    // Create the camera.
    //
    {
		hkp1dAngularFollowCamCinfo cinfo;

		cinfo.m_yawSignCorrection = 1.0f; 
		cinfo.m_upDirWS.set(0.0f, 1.0f, 0.0f); 
		cinfo.m_rigidBodyForwardDir.set(1.0f, 0.0f, 0.0f); 

		cinfo.m_set[0].m_velocity = 10.0f;
		cinfo.m_set[1].m_velocity = 50.0f;
		cinfo.m_set[0].m_speedInfluenceOnCameraDirection = 1.0f;
		cinfo.m_set[1].m_speedInfluenceOnCameraDirection = 1.0f;
		cinfo.m_set[0].m_angularRelaxation = 3.5f;
		cinfo.m_set[1].m_angularRelaxation = 4.5f;

		// The two camera positions ("slow" and "fast" rest positions) are both the same here,
		// -6 units behind the chassis, and 2 units above it. Again, this is dependent on 
		// m_chassisCoordinateSystem.
		cinfo.m_set[0].m_positionUS.set( -27.0f, 8.0f, 0.0f); 
		cinfo.m_set[1].m_positionUS.set( -27.0f, 8.0f, 0.0f); 

		cinfo.m_set[0].m_lookAtUS.set ( 2.0f, 0.0f, 0.0f );
		cinfo.m_set[1].m_lookAtUS.set ( 2.0f, 0.0f, 0.0f );

		cinfo.m_set[0].m_fov = 70.0f;
		cinfo.m_set[1].m_fov = 70.0f;

		m_camera.reinitialize( cinfo );
    }
}
// The scabbard is a single constraint which should have multiple degrees of freedom, but will suffer from the following 
// artifacts if implemented using a single ball-and-socket constraint:
// 1. Undesired motion (excessive, potentially implausible, or just not artisitically desired) due to the simplification 
//    to a single point of attachment.
// 2. Excessive energy, or undersired enrgy preservation when the character comes to rest.
// 3. A potential performance impact if collisions are used to prevent interpenetration with the character.
// To address these we use a ragdoll constraint instead which allows full control to restict angular degrees of freedom of the
// underlying ball-and-socket, and we use angular damping to make sure the scabbard comes to rest quickly.
// We can then disable all collision between the scabbard and the hip, leaving all other collisions valid.
void HK_CALL CharacterAttachmentsHelpers::addScabbard(hkpWorld* world, 
												const hkaRagdollInstance* ragdollInstance,
												const hkQsTransform& currentTransform,
												const char* startBoneName, 
												hkpGroupFilter* filter,
												const ConstraintStabilityTricks& tricks )
{
	// We will use a tricks to increase stability:
	const hkReal angularDamping = 4.0f;


	// Get the relevant RBs to which we attach this belt.
	hkpRigidBody* torso = HK_NULL;
	{
		int torsoIndex = hkaSkeletonUtils::findBoneWithName( *ragdollInstance->m_skeleton, startBoneName);
		HK_ASSERT2( 0, torsoIndex >= 0, "Couldn't find " << startBoneName << " in ragdoll" );
		torso = ragdollInstance->getRigidBodyOfBone( torsoIndex );
	}

	hkpRigidBody* scabbard;
	{
		hkVector4 boxHalfExtents( 0.02f, 0.05f, 0.3f);

		// Create body 
		hkpRigidBodyCinfo info;
		info.m_shape = new hkpBoxShape( boxHalfExtents, 0.01f );

		// We are going to add a single body which does not collide with the bone to which it is attached in the ragdoll so we 
		// will put in the same group and disable collision using subgroups. 
		hkUint32 torsoFilterInfo = torso->getCollidable()->getCollisionFilterInfo();
		info.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo(
			1, 
			2,
			31, // New subgroup - larger than any subgroup in the ragdoll
			hkpGroupFilter::getSubSystemIdFromFilterInfo(torsoFilterInfo) // Don't collide with torso subgroup
			);

		// Note that we use a scaled mass here to artificially damp the movement
		const hkReal mass = 1.0f;
		hkpInertiaTensorComputer::setShapeVolumeMassProperties( info.m_shape, mass, info );
		info.m_mass = mass;

		// Note that we use an increased angular damping to further artificially damp the movement
		if( tricks.m_useDamping ) 
		{
			info.m_angularDamping = angularDamping;
		}

		// Place roughly beside the character model space - we'll let a short simulation run settle the constraint properly.
		info.m_position.set( 0.2f, 0.0f, -0.2f );	

		// Move into world space behind character
		info.m_position.setTransformedPos(currentTransform, info.m_position);

		scabbard = new hkpRigidBody( info );
		info.m_shape->removeReference();

		world->addEntity( scabbard );
		scabbard->removeReference();
	}

	//
	// Create constraint (to attach and also restrict motion)
	// 
	hkVector4 pivotA, pivotB;
	{
		// Scabbard
		pivotA.set(-0.02f, 0.0f, 0.3f);

		// Torso
		pivotB.set(0.0f, 0.0f, 0.2f);
	}

	hkpConstraintData* cd = HK_NULL;

	if( tricks.m_useLimits ) 
	{
		hkReal planeMin =  -HK_REAL_PI * 0.5f;
		hkReal planeMax =  HK_REAL_PI * 0.05f;
		hkReal twistMin =  HK_REAL_PI * -0.04f;
		hkReal twistMax =  HK_REAL_PI *  0.04f;
		hkReal coneMin  =  HK_REAL_PI * 0.3f;

		hkpRagdollConstraintData* rdcd = new hkpRagdollConstraintData();

		rdcd->setConeAngularLimit(coneMin);
		rdcd->setPlaneMinAngularLimit(planeMin);
		rdcd->setPlaneMaxAngularLimit(planeMax);
		rdcd->setTwistMinAngularLimit(twistMin);
		rdcd->setTwistMaxAngularLimit(twistMax);

		// Scabbard
		hkVector4 twistAxisA(0.0f, 0.0f, 1.0f);
		hkVector4 planeAxisA(1.0f, 0.0f, 0.0f);

		// Torso
		hkVector4 twistAxisB(1.0f, 0.0f, 0.0f);
		hkVector4 planeAxisB(0.0f, 0.0f, 1.0f);

		rdcd->setInBodySpace(pivotA, pivotB, planeAxisA, planeAxisB, twistAxisA, twistAxisB);

		cd = rdcd;
	}
	else
	{
		// Just use a ball-and-socket (no angular limits)
		hkpBallAndSocketConstraintData* bscd = new hkpBallAndSocketConstraintData();

		bscd->setInBodySpace(pivotA, pivotB);

		cd = bscd;
	}

	//
	//	Create and add the constraint
	//
	{
		hkpConstraintInstance* constraint = new hkpConstraintInstance(scabbard, torso, cd );
		world->addConstraint(constraint);
		constraint->removeReference();
	}	
	cd->removeReference();
}