void PlatformsCharacterRbDemo::cameraHandling() { const hkReal height = .7f; hkVector4 forward; forward.set(1,0,0); forward.setRotatedDir( m_currentOrient, forward ); hkVector4 from, to; to = m_characterRigidBody->getPosition(); to.addMul4(height, UP ); hkVector4 dir; dir.setMul4( height, UP ); dir.addMul4( -8.f, forward); from.setAdd4(to, dir); // Make object in line of sight transparent { // Cast down to landscape to get an accurate position hkpWorldRayCastInput raycastIn; // Reverse direction for collision detection raycastIn.m_from = to; raycastIn.m_to = from; raycastIn.m_filterInfo = hkpGroupFilter::calcFilterInfo(0); hkpAllRayHitCollector collector; m_world->castRay( raycastIn, collector); hkLocalArray<hkUlong> transp(5); // Loop over all collected objects for(int i=0; i < collector.getHits().getSize();i++) { hkpWorldRayCastOutput raycastOut = collector.getHits()[i]; transp.pushBack(hkUlong(raycastOut.m_rootCollidable)); } // loop over display ids for(int i=0; i < m_objectIds.getSize();i++) { if(transp.indexOf(m_objectIds[i]) != -1) { HK_SET_OBJECT_COLOR(m_objectIds[i], TRANSPARENT_GREY); } else { HK_SET_OBJECT_COLOR(m_objectIds[i],NORMAL_GRAY); } } } setupDefaultCameras(m_env, from , to, UP, 1.0f); }
void CollisionFilterViewerUtil::activate(const hkpRigidBody* rb, const hkpWorld* world) { if( rb != HK_NULL ) { m_isActive = true; if(m_bodiesColored.getSize() == 0) { // Print out filter info { hkUint32 filterInfo = rb->getCollidable()->getCollisionFilterInfo(); hkcout << "Body has filter info " << filterInfo << " which means layer " << hkpGroupFilter::getLayerFromFilterInfo(filterInfo) << " system group " << hkpGroupFilter::getSystemGroupFromFilterInfo(filterInfo) << " subsystem group " << hkpGroupFilter::getSubSystemIdFromFilterInfo(filterInfo) << " subsystem group nocollide " << hkpGroupFilter::getSubSystemDontCollideWithFromFilterInfo(filterInfo) << "\n"; } // Color the delected body red HK_SET_OBJECT_COLOR((hkUlong)rb->getCollidable(), hkColor::rgbFromChars(255, 0, 0)); // Store original color m_bodiesColored.pushBack(rb); m_colors.pushBack( rb->isFixed() ? DEFAULT_FIXED_OBJECT_COLOR : DEFAULT_OBJECT_COLOR ); // Now find all bodies colliding with this and colour orange, otherwise green hkpPhysicsSystem* system; system = world->getWorldAsOneSystem(); for(int i = 0; i < system->getRigidBodies().getSize(); i++) { hkpRigidBody* rb2 = system->getRigidBodies()[i]; if( rb == rb2) continue; if( world->getCollisionFilter()->isCollisionEnabled( *rb->getCollidable(), *rb2->getCollidable()) ) { // Color orange HK_SET_OBJECT_COLOR((hkUlong)rb2->getCollidable(), hkColor::rgbFromChars(255, 128, 0)); } else { // Color Green HK_SET_OBJECT_COLOR((hkUlong)rb2->getCollidable(), hkColor::rgbFromChars(0, 255, 0)); } m_bodiesColored.pushBack(rb2); m_colors.pushBack( rb2->isFixed() ? DEFAULT_FIXED_OBJECT_COLOR : DEFAULT_OBJECT_COLOR ); } system->removeReference(); } } }
void SlidingWorldDemo::addBodiesNewlyInsideSimulationAreaToSimulation() { m_world->lock(); hkpBroadPhase* bp = m_world->getBroadPhase(); hkAabb broadphaseAabb; bp->getExtents( broadphaseAabb.m_min, broadphaseAabb.m_max); for (int i = 0; i < m_boxes.getSize(); i++) { hkpRigidBody* rb = m_boxes[i]; // If we're not in simulation, check if we're now inside the simulation area/broadphase if( rb->getWorld() == HK_NULL ) { // In general you'd have some world object management code here. In our case, we'll just check if the current // aabb of the body would be fully contained inside the new broadphase location. hkAabb rbAabb; rb->getCollidable()->getShape()->getAabb(rb->getTransform(), 0, rbAabb); if (broadphaseAabb.contains(rbAabb)) { m_world->addEntity( rb ); // Color them slightly green so they are clearly marked as newly added HK_SET_OBJECT_COLOR(hkUlong(rb->getCollidable()), hkColor::rgbFromChars(200, 255, 200)); } } } m_world->unlock(); }
void WorldLinearCastMultithreadedDemo::buildQueryObects( hkArray<hkpShape*>& shapes, hkArray<QueryObject>& objects ) { hkpShapeDisplayBuilder::hkpShapeDisplayBuilderEnvironment env; hkpShapeDisplayBuilder builder(env); for (int i = 0; i < shapes.getSize(); i++) { QueryObject qo; qo.m_transform = new hkTransform(); qo.m_transform->setIdentity(); qo.m_collidable = new hkpCollidable( shapes[i], qo.m_transform ); objects.pushBack( qo ); hkArray<hkDisplayGeometry*> displayGeometries; builder.buildDisplayGeometries( shapes[i], displayGeometries ); hkDebugDisplay::getInstance().addGeometry( displayGeometries, hkTransform::getIdentity(), (hkUlong)qo.m_collidable, 0, 0 ); while( displayGeometries.getSize() ) { delete displayGeometries[0]; displayGeometries.removeAt(0); } // Set green color HK_SET_OBJECT_COLOR((hkUlong)qo.m_collidable, hkColor::rgbFromChars(0,255,0,120)); } }
// hkpPhantom interface implementation virtual void phantomEnterEvent( const hkpCollidable* collidableA, const hkpCollidable* collidableB, const hkpCollisionInput& env ) { // the color can only be changed once the entity has been added to the world hkpRigidBody* owner = hkGetRigidBody(collidableB); // the "Collidables" here are "faked" so it's necessary to get the owner first in order // to get the "real" collidable! HK_SET_OBJECT_COLOR((hkUlong)owner->getCollidable(), hkColor::rgbFromChars(255, 0, 0)); //HK_SET_OBJECT_COLOR((int)&collidableB, hkColor::rgbFromChars(255, 0, 0)); }
void CollisionFilterViewerUtil::deactivate() { // Recolor all boides to their original color. for(int i = 0; i < m_bodiesColored.getSize(); i++) { HK_SET_OBJECT_COLOR((hkUlong)m_bodiesColored[i]->getCollidable(), m_colors[i]); } // Clear and mark as inactive. m_bodiesColored.clear(); m_colors.clear(); m_isActive = false; }
// // Create a grid of ragdolls // void VehicleManagerDemo::createRagdollGrid( hkpWorld* world, int x_size, int y_size, hkReal xStep, hkReal yStep, hkArray<hkRagdoll*>& ragdollsOut) { int systemGroup = 2; hkReal ragdollHeight = 2.50f; for( int x = 0; x < x_size; x++ ) { for( int y = 0; y < y_size; y++ ) { hkVector4 position; // do a raycast to place the ragdoll { hkpWorldRayCastInput ray; ray.m_from.set( x * xStep, 10, y * yStep ); ray.m_to. set( x * xStep, -10, y * yStep ); hkpWorldRayCastOutput result; world->castRay( ray, result ); position.setInterpolate4( ray.m_from, ray.m_to, result.m_hitFraction ); position(1) += ragdollHeight* 0.5f; } hkQuaternion rotation; rotation.setIdentity(); rotation.setAxisAngle( hkTransform::getIdentity().getColumn(0), HK_REAL_PI * -0.5f ); hkpPhysicsSystem* ragdoll = GameUtils::createRagdoll( ragdollHeight, position, rotation, systemGroup, GameUtils::RPT_CAPSULE ); { for ( int i = 0; i < ragdoll->getRigidBodies().getSize(); i++) { hkpRigidBody* rb = ragdoll->getRigidBodies()[i]; rb->setCollisionFilterInfo( hkpGroupFilter::calcFilterInfo( RAGDOLL_LAYER, systemGroup ) ); } } systemGroup++; world->addPhysicsSystem(ragdoll); { // Give the ragdolls some personality int color = hkColor::getRandomColor(); for (hkInt32 i = 0; i < ragdoll->getRigidBodies().getSize(); i++) { hkpRigidBody* rb = ragdoll->getRigidBodies()[i]; HK_SET_OBJECT_COLOR((hkUlong)rb->getCollidable(), color); } } ragdoll->getRigidBodies()[0]->deactivate(); ragdoll->removeReference(); } } }
// hkpPhantom interface implementation virtual void phantomLeaveEvent( const hkpCollidable* collidableA, const hkpCollidable* collidableB ) { // the color can only be changed once the entity has been added to the world hkpRigidBody* owner = hkGetRigidBody(collidableB); // the "Collidables" here are "faked" so it's necessary to get the owner first in order // to get the "real" collidable! HK_SET_OBJECT_COLOR((hkUlong)owner->getCollidable(), hkColor::rgbFromChars(0, 255, 0)); // If moving out AND falling down, apply impulse to fire it towards "wall" if(owner->getLinearVelocity()(1) < 0.0f) { hkVector4 impulse(-50.0f, 220.0f, 0.0f); owner->applyLinearImpulseAsCriticalOperation(impulse); } }
void WorldLinearCastMultithreadedDemo::displayRootCdBody( hkpWorld* world, const hkpCollidable* collidable, hkpShapeKey key) { hkpShapeCollection::ShapeBuffer shapeBuffer; // Check, whether we have a triangle from the landscape or a single object if ( key == HK_INVALID_SHAPE_KEY ) { // now we have a single object as we are not part of a hkpShapeCollection HK_SET_OBJECT_COLOR((hkUlong)collidable, hkColor::rgbFromChars(160,160,160)); } else { // now we need to get our triangle. // Attention: The next lines make certain assumptions about how the landscape is constructed: // 1. The landscape is a single hkMoppShape with wraps a hkpShapeCollection, which // produces only triangles. // 2. All hkShapeCollections are wrapped with a hkpBvTreeShape HK_ASSERT(0x3e93321f, world->getCollisionDispatcher()->hasAlternateType( collidable->getShape()->getType(), HK_SHAPE_BV_TREE ) ); const hkpBvTreeShape* bvTreeShape = static_cast<const hkpBvTreeShape*>(collidable->getShape()); hkpShapeKey triangleId = key; const hkpShape* childShape = bvTreeShape->getContainer()->getChildShape( triangleId, shapeBuffer ); HK_ASSERT(0x23f67112, childShape->getType() == HK_SHAPE_TRIANGLE ); const hkpTriangleShape* triangle = static_cast<const hkpTriangleShape*>( childShape ); hkVector4 vertex[3]; vertex[0].setTransformedPos(collidable->getTransform(), triangle->getVertex(0)); vertex[1].setTransformedPos(collidable->getTransform(), triangle->getVertex(1)); vertex[2].setTransformedPos(collidable->getTransform(), triangle->getVertex(2)); // Draw the border of the triangle HK_DISPLAY_LINE(vertex[0], vertex[1], hkColor::WHITE); HK_DISPLAY_LINE(vertex[2], vertex[1], hkColor::WHITE); HK_DISPLAY_LINE(vertex[0], vertex[2], hkColor::WHITE); if ( (const void*)childShape != (const void*)shapeBuffer && shapeBuffer[10] == 0 ) { HK_ASSERT(0x20b8765d, 0); } } }
void ShapeQueryDemo::buildCachingPhantoms( hkpWorld* world, hkArray<hkpShape*>& shapes, hkArray<hkpCachingShapePhantom*>& phantoms, hkPseudoRandomGenerator& generator ) { for (int i = 0; i < shapes.getSize(); i++) { // create a random position. This is important, otherwise all the phantoms will start in the // center of the level and will overlap, causing an N squared worst case problem hkTransform t; t.getRotation().setIdentity(); t.getTranslation().set( i * 10.f, 10.f, generator.getRandRange( -20.f, 20.f )); hkpCachingShapePhantom* phantom = new hkpCachingShapePhantom( shapes[i], t ); phantoms.pushBack( phantom ); world->addPhantom( phantom ); // Set red color HK_SET_OBJECT_COLOR((hkUlong)phantom->getCollidable( ), hkColor::rgbFromChars(255,0,0,120)); } }
hkDemo::Result SlidingWorldDemo::stepDemo() { makeFakeInput(); hkBool doShift = false; hkVector4 newCenter; handleKeys(doShift, newCenter); m_world->lock(); if(doShift) { // reset the box colors to a light grey for (int i = 0; i < m_boxes.getSize(); i++) { HK_SET_OBJECT_COLOR(hkUlong(m_boxes[i]->getCollidable()), hkColor::LIGHTGREY); } { //hkVector4 currentCenter = m_centers[((m_ticks / delay) + (numCenters-1)) % numCenters]; //HK_DISPLAY_STAR(currentCenter, 2.5f, 0xFF00FF00); //HK_DISPLAY_LINE(nextCenter, m_currentCenter, 0xFF00FF00); } hkVector4 diff; diff.setSub4(newCenter, m_currentCenter); hkArray<hkpBroadPhaseHandle*> objectsEnteringBroadphaseBorder; hkVector4 effectiveShift; if( g_variants[m_variantId].m_mode == SlidingWorldDemoVariant::RECENTER_BROAD_PHASE_ONLY ) { recenterBroadPhaseVariant(diff, objectsEnteringBroadphaseBorder, effectiveShift); } else // SlidingWorldDemoVariant::SHIFT_COORDINATE_SPACE) { shiftCoordinateSystemVariant(diff, objectsEnteringBroadphaseBorder, effectiveShift); } removeDuplicatesFromArray(objectsEnteringBroadphaseBorder); // Some bodies may have to be removed from simulation, some may need to be added. { removeBodiesLeavingBroadphaseFromSimulation(objectsEnteringBroadphaseBorder); addBodiesNewlyInsideSimulationAreaToSimulation(); } m_currentCenter = newCenter; } // draw the grid in cyan { hkVector4 minOffset; minOffset.set(-5, 1, -5); hkVector4 maxOffset; maxOffset.set(5,1,5); hkVector4 min, max; for (int i = -2; i <= 2; i++) for (int j = -2; j <= 2; j++) { min.set((hkReal)10*i, 0, (hkReal)10*j); max = min; min.add4(minOffset); max.add4(maxOffset); drawAabb(min, max, hkColor::CYAN ); } } // draw the broadphase extents in red displayCurrentBroadPhaseAabb(m_world, hkColor::RED ); // draw locations of all 'unsimulated' bodies drawUnsimulatedBodies(); if( m_currentMode == AUTOMATIC_SHIFT) { m_ticks++; } m_world->unlock(); return hkDefaultPhysicsDemo::stepDemo(); }
PhantomEventsDemo::PhantomEventsDemo( hkDemoEnvironment* env ) : hkDefaultPhysicsDemo(env, DEMO_FLAGS_NO_SERIALIZE) { // // Setup the camera // { hkVector4 from(13.0f, 10.0f, 13.0f); hkVector4 to (0.0f, 0.0f, 0.0f); hkVector4 up (0.0f, 1.0f, 0.0f); setupDefaultCameras( env, from, to, up ); } // // Create the world // { hkpWorldCinfo info; info.setupSolverInfo(hkpWorldCinfo::SOLVER_TYPE_4ITERS_MEDIUM); info.setBroadPhaseWorldSize( 100.0f ); info.m_enableDeactivation = false; m_world = new hkpWorld( info ); m_world->lock(); setupGraphics(); } // // Register the collision agents // { hkpAgentRegisterUtil::registerAllAgents( m_world->getCollisionDispatcher() ); } // In this demo we have three different objects; the wall, the sphere and a phantom volume. Both the wall, which is simply a box, // and the sphere are created in the usual manner using a hkpRigidBodyCinfo 'blueprint' and are added to the world. // // Create the wall box // { hkpRigidBodyCinfo info; hkVector4 fixedBoxSize( 0.5f, 5.0f , 5.0f ); hkpBoxShape* fixedBoxShape = new hkpBoxShape( fixedBoxSize , 0 ); info.m_shape = fixedBoxShape; info.m_motionType = hkpMotion::MOTION_FIXED; info.m_position.set(-2.0f, 0.0f ,0.0f); // Add some bounce. info.m_restitution = 0.9f; // Create fixed box hkpRigidBody* floor = new hkpRigidBody(info); m_world->addEntity(floor); floor->removeReference(); fixedBoxShape->removeReference(); } // // Create a moving sphere // { hkReal radius = 0.5f; hkpConvexShape* sphereShape = new hkpSphereShape(radius); // To illustrate using the shape, create a rigid body. hkpRigidBodyCinfo sphereInfo; sphereInfo.m_shape = sphereShape; sphereInfo.m_position.set(2.0f, 0.0f, 0.0f); sphereInfo.m_restitution = 0.9f; sphereInfo.m_motionType = hkpMotion::MOTION_SPHERE_INERTIA; // If we need to compute mass properties, we'll do this using the hkpInertiaTensorComputer. if (sphereInfo.m_motionType != hkpMotion::MOTION_FIXED) { sphereInfo.m_mass = 10.0f; hkpMassProperties massProperties; hkpInertiaTensorComputer::computeSphereVolumeMassProperties(radius, sphereInfo.m_mass, massProperties); sphereInfo.m_inertiaTensor = massProperties.m_inertiaTensor; sphereInfo.m_centerOfMass = massProperties.m_centerOfMass; sphereInfo.m_mass = massProperties.m_mass; } // Create a rigid body (using the template above) hkpRigidBody* sphereRigidBody = new hkpRigidBody(sphereInfo); // Remove reference since the body now "owns" the Shape sphereShape->removeReference(); // Finally add body so we can see it, and remove reference since the world now "owns" it. m_world->addEntity(sphereRigidBody); sphereRigidBody->removeReference(); } // Given below is the construction code for the phantom volume: // // Create a PHANTOM floor // { hkpRigidBodyCinfo boxInfo; hkVector4 boxSize( 4.0f, 1.5f , 2.0f ); hkpShape* boxShape = new hkpBoxShape( boxSize , 0 ); boxInfo.m_motionType = hkpMotion::MOTION_FIXED; boxInfo.m_position.set(2.0f, -4.0f, 0.0f); MyPhantomShape* myPhantomShape = new MyPhantomShape(); hkpBvShape* bvShape = new hkpBvShape( boxShape, myPhantomShape ); boxShape->removeReference(); myPhantomShape->removeReference(); boxInfo.m_shape = bvShape; hkpRigidBody* boxRigidBody = new hkpRigidBody( boxInfo ); bvShape->removeReference(); m_world->addEntity( boxRigidBody ); // the color can only be changed after the entity has been added to the world HK_SET_OBJECT_COLOR((hkUlong)boxRigidBody->getCollidable(), hkColor::rgbFromChars(255, 255, 255, 50)); boxRigidBody->removeReference(); } // The phantom volume is created using a hkpBvShape using a hkpBoxShape as the bounding volume and a // hkpPhantomCallbackShape as the child shape. The volume is set to be fixed in space and coloured with a slight alpha blend. // // Once the simulation starts the ball drops into the phantom volume, upon notification of this event we colour the ball // RED and wait for an exit event. As soon as this event is raised we colour the ball GREEN and apply an impulse upwards // back towards the wall and the simulation repeats. m_world->unlock(); }
CharacterDemo::CharacterDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env) { // // Setup the camera // { hkVector4 from( 0.0f, 20.0f, -80.0f); hkVector4 to ( 0.0f, 0.0f, 0.0f); hkVector4 up ( 0.0f, 1.0f, 0.0f); setupDefaultCameras( env, from, to, up ); // disable back face culling setGraphicsState(HKG_ENABLED_CULLFACE, false); // don't really want shadows as makes it too dark forceShadowState(false); setupLights(m_env); // so that the extra lights are added // float lightDir[] = { 0, -0.5f, -1 }; // setSoleDirectionLight(m_env, lightDir, 0xffffffff ); } // // Create the world // { hkpWorldCinfo info; info.setBroadPhaseWorldSize( 350.0f ); info.m_gravity.set(0,0,-9.8f); info.m_collisionTolerance = 0.1f; m_world = new hkpWorld( info ); m_world->lock(); hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); setupGraphics(); } // Load the level { hkVector4 tkScaleFactor(.32f,.32f,.32f); hkString fullname("Resources/Physics/Tk/CharacterController/"); // We load our test case level. //fullname += "testcases.tk"; fullname += "level.tk"; hkpShape* moppShape = GameUtils::loadTK2MOPP(fullname.cString(),tkScaleFactor, -1.0f); HK_ASSERT2(0x64232cc0, moppShape,"TK file failed to load to MOPP in GameUtils::loadTK2MOPP."); hkpRigidBodyCinfo ci; ci.m_shape = moppShape; ci.m_motionType = hkpMotion::MOTION_FIXED; ci.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo( 0, 1 ); hkpRigidBody* entity = new hkpRigidBody(ci); moppShape->removeReference(); m_world->addEntity(entity); entity->removeReference(); } // Add a ladder hkVector4 baseSize( 1.0f, 0.5f, 3.6f); { hkpRigidBodyCinfo rci; rci.m_shape = new hkpBoxShape( baseSize ); rci.m_position.set(3.4f, 8.f, 2); rci.m_motionType = hkpMotion::MOTION_FIXED; hkpRigidBody* ladder = new hkpRigidBody(rci); rci.m_shape->removeReference(); m_world->addEntity(ladder)->removeReference(); // Add a property so we can identify this as a ladder hkpPropertyValue val(1); ladder->addProperty(HK_OBJECT_IS_LADDER, val); // Color the ladder so we can see it clearly HK_SET_OBJECT_COLOR((hkUlong)ladder->getCollidable(), 0x7f1f3f1f); } // // Create a character proxy object // { // Construct a shape hkVector4 vertexA(0,0, 0.4f); hkVector4 vertexB(0,0,-0.4f); // Create a capsule to represent the character standing m_standShape = new hkpCapsuleShape(vertexA, vertexB, .6f); // Create a capsule to represent the character crouching // Note that we create the smaller capsule with the base at the same position as the larger capsule. // This means we can simply swap the shapes without having to reposition the character proxy, // and if the character is standing on the ground, it will still be on the ground. vertexA.setZero4(); m_crouchShape = new hkpCapsuleShape(vertexA, vertexB, .6f); // Construct a Shape Phantom m_phantom = new hkpSimpleShapePhantom( m_standShape, hkTransform::getIdentity(), hkpGroupFilter::calcFilterInfo(0,2) ); // Add the phantom to the world m_world->addPhantom(m_phantom); m_phantom->removeReference(); // Construct a character proxy hkpCharacterProxyCinfo cpci; cpci.m_position.set(-9.1f, 35, .4f); cpci.m_staticFriction = 0.0f; cpci.m_dynamicFriction = 1.0f; cpci.m_up.setNeg4( m_world->getGravity() ); cpci.m_up.normalize3(); cpci.m_userPlanes = 4; cpci.m_maxSlope = HK_REAL_PI / 3.f; cpci.m_shapePhantom = m_phantom; m_characterProxy = new hkpCharacterProxy( cpci ); } // // Add in a custom friction model // { hkVector4 up( 0.f, 0.f, 1.f ); m_listener = new MyCharacterListener(); m_characterProxy->addCharacterProxyListener(m_listener); } // // Create the Character state machine and context // { hkpCharacterState* state; hkpCharacterStateManager* manager = new hkpCharacterStateManager(); state = new hkpCharacterStateOnGround(); manager->registerState( state, HK_CHARACTER_ON_GROUND); state->removeReference(); state = new hkpCharacterStateInAir(); manager->registerState( state, HK_CHARACTER_IN_AIR); state->removeReference(); state = new hkpCharacterStateJumping(); manager->registerState( state, HK_CHARACTER_JUMPING); state->removeReference(); state = new hkpCharacterStateClimbing(); manager->registerState( state, HK_CHARACTER_CLIMBING); state->removeReference(); m_characterContext = new hkpCharacterContext(manager, HK_CHARACTER_ON_GROUND); manager->removeReference(); } // Current camera angle about up m_currentAngle = HK_REAL_PI * 0.5f; m_world->unlock(); }
void AabbQueryDemo::queryAabbST() { HK_TIME_CODE_BLOCK("queryAabbST", HK_NULL); hkAabb aabb; // Grab a body from the world, and compute it's AABB + some padding const hkpCollidable* queryCollidable; { queryCollidable = m_collidables[m_collIdx]; hkpRigidBody* rb = hkGetRigidBody(queryCollidable); queryCollidable->getShape()->getAabb(rb->getTransform(), 20.0f, aabb); } // // For performance timings, we query the same AABB multiple times and overwrite the results. // When using this, make sure to use different output arrays! // hkArray<hkPrimitiveId> kdhitsRecurs, kdhitsIter; hkArray<hkpBroadPhaseHandlePair> sapHits; { HK_TIME_CODE_BLOCK("KdQueryRecursiveST", HK_NULL); for (int i=0; i<numQueries; i++) { kdhitsRecurs.clear(); hkKdTreeAabbQueryUtils::queryAabbRecursive(m_world->m_kdTreeManager->getTree(), aabb, kdhitsRecurs); } } { HK_TIME_CODE_BLOCK("KdQueryIterativeST", HK_NULL); for (int i=0; i<numQueries; i++) { kdhitsIter.clear(); hkKdTreeAabbQueryUtils::queryAabbIterative(m_world->m_kdTreeManager->getTree(), aabb, kdhitsIter); } } // Visualize the results HK_DISPLAY_BOUNDING_BOX(aabb, hkColor::YELLOW); for (int i=0; i<kdhitsIter.getSize(); i++) { HK_SET_OBJECT_COLOR(kdhitsIter[i], hkColor::YELLOW); } HK_SET_OBJECT_COLOR((hkUlong)queryCollidable, hkColor::RED); // Call the corresponding hkp3AxisSweep method for comparison { HK_TIME_CODE_BLOCK("BroadphaseQueryAabb", HK_NULL); for (int i=0; i<numQueries; i++) { sapHits.clear(); m_world->getBroadPhase()->querySingleAabb( aabb, sapHits ); } } { hkBool iterOk = compareHitArrays(aabb, kdhitsIter.begin(), kdhitsIter.getSize(), sapHits); hkBool recursOk = compareHitArrays(aabb, kdhitsRecurs.begin(), kdhitsRecurs.getSize(), sapHits); if( !(iterOk && recursOk) ) { m_env->m_textDisplay->outputText("ST Hit lits differed!", 20, 150, (hkUint32) hkColor::RED); } } }
void AabbQueryDemo::queryAabbMT() { HK_TIMER_BEGIN_LIST("queryAabbMT", "setup"); hkAabb aabb; // Grab a body from the world, and compute it's AABB + some padding const hkpCollidable* queryCollidable; { queryCollidable = m_collidables[m_collIdx]; hkpRigidBody* rb = hkGetRigidBody(queryCollidable); queryCollidable->getShape()->getAabb(rb->getTransform(), 20.0f, aabb); } hkArray<hkpKdTreeAabbCommand> commands; commands.setSize(numQueries); // // For performance timings, we query the same AABB multiple times and overwrite the results. // When using this, make sure to use different output arrays! // hkArray<hkPrimitiveId> output; output.setSize(50); // // Set up the commands for the job // for (int i=0; i<commands.getSize(); i++) { hkpKdTreeAabbCommand& command = commands[i]; command.m_aabb = aabb; command.m_results = output.begin(); command.m_resultsCapacity = output.getSize(); command.m_numResultsOut = 0; } // // Setup the job // hkArray<hkpRayCastQueryJobHeader> header(1); hkpKdTreeAabbJob aabbJob(header.begin(), commands.begin(), commands.getSize(), &m_semaphore); aabbJob.m_numTrees = 1; aabbJob.m_trees[0] = m_world->m_kdTreeManager->getTree(); m_jobQueue->addJob( *reinterpret_cast<hkJobQueue::JobQueueEntry*>(&aabbJob), hkJobQueue::JOB_HIGH_PRIORITY ); HK_TIMER_SPLIT_LIST("process"); m_jobThreadPool->processAllJobs( m_jobQueue ); m_jobThreadPool->waitForCompletion(); m_semaphore.acquire(); HK_TIMER_END_LIST(); // // Run the same query on the broadphase for comparison purposes // hkArray<hkpBroadPhaseHandlePair> sapHits; { HK_TIME_CODE_BLOCK("BroadphaseQueryAabb", HK_NULL); for (int i=0; i<numQueries; i++) { sapHits.clear(); m_world->getBroadPhase()->querySingleAabb( aabb, sapHits ); } } // // Check results and draw // for (int i=0; i<commands.getSize(); i++) { hkpKdTreeAabbCommand& command = commands[i]; hkBool jobOk = compareHitArrays(command.m_aabb, command.m_results, command.m_numResultsOut, sapHits); for (int j=0; j<command.m_numResultsOut; j++) { HK_SET_OBJECT_COLOR(command.m_results[j], hkColor::YELLOW); } HK_SET_OBJECT_COLOR((hkUlong)queryCollidable, hkColor::LIME); if( !jobOk ) { m_env->m_textDisplay->outputText("MT Hit lits differed!", 20, 250, (hkUint32) hkColor::RED); } } }
LowFrequencyCharactersDemo::LowFrequencyCharactersDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env) { // // Setup the camera // { hkVector4 from( 0.0f, 20.0f, -80.0f); hkVector4 to ( 0.0f, 0.0f, 0.0f); hkVector4 up ( 0.0f, 1.0f, 0.0f); setupDefaultCameras( env, from, to, up ); forceShadowState(false); } // // Create the world // { hkpWorldCinfo info; info.setBroadPhaseWorldSize( 350.0f ); info.m_gravity.set(0, -9.8f, 0); info.m_collisionTolerance = 0.1f; m_world = new hkpWorld( info ); m_world->lock(); hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); setupGraphics(); } // // Create a terrain // TerrainHeightFieldShape* heightFieldShape; { hkpSampledHeightFieldBaseCinfo ci; ci.m_xRes = 64; ci.m_zRes = 64; ci.m_scale.set(4,1,4); // // Fill in a data array // m_data = hkAllocate<hkReal>(ci.m_xRes * ci.m_zRes, HK_MEMORY_CLASS_DEMO); for (int x = 0; x < ci.m_xRes; x++) { for (int z = 0; z < ci.m_xRes; z++) { hkReal dx,dz,height = 0; int octave = 1; // Add togther a few sine and cose waves for (int i=0; i< 3; i++) { dx = hkReal(x * octave) / ci.m_xRes; dz = hkReal(z * octave) / ci.m_zRes; height += (5 - (i * 2)) * hkMath::cos(dx * HK_REAL_PI) * hkMath::sin(dz * HK_REAL_PI); octave *= 4; } m_data[x*ci.m_zRes + z] = height; } } heightFieldShape = new TerrainHeightFieldShape( ci , m_data ); // // Create a fixed rigid body // { hkpRigidBodyCinfo rci; rci.m_motionType = hkpMotion::MOTION_FIXED; rci.m_position.setMul4( -0.5f, heightFieldShape->m_extents ); // center the heightfield rci.m_shape = heightFieldShape; rci.m_friction = 0.05f; hkpRigidBody* body = new hkpRigidBody( rci ); m_world->addEntity(body)->removeReference(); } heightFieldShape->removeReference(); } // // Create a character proxy object // { m_numBoxes = 0; m_numCapsules = 0; m_numSpheres = 0; // We'll store the simulation frequency in this hkpPropertyValue val; // Construct shape phantoms for the characters hkPseudoRandomGenerator random(123); for (int i=0; i < NUM_CHARACTERS; i++) { // Create a random shape to represent the character hkpConvexShape* shape = HK_NULL; { hkReal scale = random.getRandReal01() * 0.25f + 0.75f; //Set the simulation frequency val.setInt( random.getRand32() % 3 ); switch (val.getInt()) { case 0: { hkVector4 top(0, scale * 0.4f, 0); hkVector4 bottom(0, -scale * 0.4f, 0); shape = new hkpCapsuleShape(top, bottom, scale * 0.6f); m_numCapsules++; } break; case 1: { hkVector4 size(scale * 0.5f, scale , scale * 0.5f); shape = new hkpBoxShape(size); m_numBoxes++; } break; default: { shape = new hkpSphereShape(scale); m_numSpheres++; } break; } } hkpShapePhantom* phantom = new hkpSimpleShapePhantom( shape, hkTransform::getIdentity() ); shape->removeReference(); // Add the phantom to the world m_world->addPhantom(phantom); phantom->removeReference(); HK_SET_OBJECT_COLOR( (hkUlong)phantom->getCollidable(), 0x7fffffff & hkColor::getRandomColor() ); // Construct a character proxy hkpCharacterProxyCinfo cpci; random.getRandomVector11( cpci.m_position ); cpci.m_position.mul4(32); cpci.m_position(1) = 10; cpci.m_up.setNeg4( m_world->getGravity() ); cpci.m_up.normalize3(); cpci.m_shapePhantom = phantom; m_characterProxy[i] = new hkpCharacterProxy( cpci ); // Player is simulated at full frequency if (i==0) { val.setInt(0); } // Add the schedule property phantom->addProperty(HK_SCHEDULE_FREQUENCY, val); } } // // Create the Character state machine and context // hkpCharacterStateManager* manager; { hkpCharacterState* state; manager = new hkpCharacterStateManager(); state = new hkpCharacterStateOnGround(); manager->registerState( state, HK_CHARACTER_ON_GROUND); state->removeReference(); state = new hkpCharacterStateInAir(); manager->registerState( state, HK_CHARACTER_IN_AIR); state->removeReference(); state = new hkpCharacterStateJumping(); manager->registerState( state, HK_CHARACTER_JUMPING); state->removeReference(); state = new hkpCharacterStateClimbing(); manager->registerState( state, HK_CHARACTER_CLIMBING); state->removeReference(); } // Create a context for each character { for (int i=0; i < NUM_CHARACTERS; i++) { m_characterContext[i] = new hkpCharacterContext(manager, HK_CHARACTER_ON_GROUND); } manager->removeReference(); } // Current camera angle about up m_currentAngle = 0.0f; //Initialised the round robin counter m_tick = 0; m_world->unlock(); }
PlatformsCharacterRbDemo::PlatformsCharacterRbDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env) { // Setup the graphics { // Disable back face culling setGraphicsState(HKG_ENABLED_CULLFACE, false); // don't really want shadows as makes it too dark forceShadowState(false); setupLights(m_env); // so that the extra lights are added // allow color change on precreated objects m_env->m_displayHandler->setAllowColorChangeOnPrecreated(true); } // Create the world { hkpWorldCinfo info; info.setBroadPhaseWorldSize( 350.0f ); info.m_gravity.set(0,0,-9.8f); info.m_collisionTolerance = 0.01f; m_world = new hkpWorld( info ); m_world->lock(); hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); setupGraphics(); } // Load the level { m_loader = new hkLoader(); hkString assetFile = hkAssetManagementUtil::getFilePath("Resources/Physics/levels/test_platform.hkx"); hkRootLevelContainer* container = m_loader->load( assetFile.cString() ); HK_ASSERT2(0x27343437, container != HK_NULL , "Could not load asset"); hkxScene* scene = reinterpret_cast<hkxScene*>( container->findObjectByType( hkxSceneClass.getName() )); HK_ASSERT2(0x27343635, scene, "No scene loaded"); env->m_sceneConverter->convert( scene, hkgAssetConverter::CONVERT_ALL ); hkpPhysicsData* physics = reinterpret_cast<hkpPhysicsData*>( container->findObjectByType( hkpPhysicsDataClass.getName() )); HK_ASSERT2(0x27343635, physics, "No physics loaded"); // Physics if (physics) { const hkArray<hkpPhysicsSystem*>& psys = physics->getPhysicsSystems(); // Tie the two together for (int i=0; i<psys.getSize(); i++) { hkpPhysicsSystem* system = psys[i]; // Change the layer of the rigid bodies for (int rb=0; rb < system->getRigidBodies().getSize(); rb++) { const hkUlong id = hkUlong(system->getRigidBodies()[rb]->getCollidable()); HK_SET_OBJECT_COLOR(id,NORMAL_GRAY); m_objectIds.pushBack(id); } // Associate the display and physics (by name) if (scene) { addPrecreatedDisplayObjectsByName( psys[i]->getRigidBodies(), scene ); } // add the lot to the world m_world->addPhysicsSystem(system); } } } // Add horizontal keyframed platform { hkpShape* platform = new hkpBoxShape(hkVector4(1.5,2.5,0.25)); hkpRigidBodyCinfo rbci; rbci.m_shape = platform; rbci.m_motionType = hkpMotion::MOTION_KEYFRAMED; rbci.m_position.set(2.5f, 0.0f, 0.25f); rbci.m_friction = 1.0f; rbci.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo(hkpGroupFilter::calcFilterInfo(1)); m_horPlatform = new hkpRigidBody(rbci); platform->removeReference(); m_world->addEntity(m_horPlatform); m_horPlatform->removeReference(); } // Add vertical keyframed platform { hkpShape* platform = new hkpBoxShape(hkVector4(1.5,2.5,0.25)); hkpRigidBodyCinfo rbci; rbci.m_shape = platform; rbci.m_motionType = hkpMotion::MOTION_KEYFRAMED; rbci.m_position.set(-3.5f, 0.0f, 3.25f); rbci.m_friction = 1.0f; rbci.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo(hkpGroupFilter::calcFilterInfo(1)); m_verPlatform = new hkpRigidBody(rbci); platform->removeReference(); m_world->addEntity(m_verPlatform); m_verPlatform->removeReference(); } // Create a character rigid body { // Create a capsule to represent the character standing hkVector4 vertexA(0,0, 0.4f); hkVector4 vertexB(0,0,-0.4f); m_standShape = new hkpCapsuleShape(vertexA, vertexB, .6f); // Construct a character rigid body hkpCharacterRigidBodyCinfo info; info.m_mass = 100.0f; info.m_shape = m_standShape; info.m_maxForce = 1000.0f; info.m_up = UP; info.m_position.set(0.0f, 5.0f, 1.5f); info.m_maxSlope = HK_REAL_PI/2.0f; m_characterRigidBody = new hkpCharacterRigidBody( info ); m_world->addEntity( m_characterRigidBody->getRigidBody() ); } // Create the character state machine { hkpCharacterState* state; hkpCharacterStateManager* manager = new hkpCharacterStateManager(); state = new hkpCharacterStateOnGround(); manager->registerState( state, HK_CHARACTER_ON_GROUND); state->removeReference(); state = new hkpCharacterStateInAir(); manager->registerState( state, HK_CHARACTER_IN_AIR); state->removeReference(); state = new hkpCharacterStateJumping(); manager->registerState( state, HK_CHARACTER_JUMPING); state->removeReference(); state = new hkpCharacterStateClimbing(); manager->registerState( state, HK_CHARACTER_CLIMBING); state->removeReference(); m_characterContext = new hkpCharacterContext(manager, HK_CHARACTER_ON_GROUND); m_characterContext->setCharacterType(hkpCharacterContext::HK_CHARACTER_RIGIDBODY); manager->removeReference(); } // Set colors of platforms HK_SET_OBJECT_COLOR(hkUlong(m_verPlatform->getCollidable()),hkColor::BLUE); HK_SET_OBJECT_COLOR(hkUlong(m_horPlatform->getCollidable()),hkColor::GREEN); // Set global time m_time = 0.0f; // Initialize hkpSurfaceInfo for previous ground m_previousGround = new hkpSurfaceInfo(); m_framesInAir = 0; // Current camera angle about up m_currentAngle = HK_REAL_PI * 0.5f; m_world->unlock(); }
TruckDemo::TruckDemo(hkDemoEnvironment* env) : CarDemo(env, false, 4, 1) { m_world->lock(); { // // Create vehicle's chassis shape. // hkpConvexVerticesShape* chassisShape = 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; // 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 }; // // SHAPE CONSTRUCTION. // { hkStridedVertices stridedVerts; { stridedVerts.m_numVertices = numVertices; stridedVerts.m_striding = stride; stridedVerts.m_vertices = vertices; } chassisShape = new hkpConvexVerticesShape(stridedVerts); } } } createDisplayWheels(0.5f, 0.3f); for (int vehicleId = 0; vehicleId < m_numVehicles; vehicleId++) { // // Create the vehicle. // { // // Create the chassis body. // hkpRigidBody* chassisRigidBody; { hkpRigidBodyCinfo chassisInfo; chassisInfo.m_mass = 5000.0f; chassisInfo.m_shape = chassisShape; chassisInfo.m_friction = 0.8f; chassisInfo.m_motionType = hkpMotion::MOTION_BOX_INERTIA; // Position chassis on the ground. chassisInfo.m_position.set(-10.0f, -4.5f, vehicleId * 5.0f); hkpInertiaTensorComputer::setShapeVolumeMassProperties(chassisInfo.m_shape, chassisInfo.m_mass, chassisInfo); chassisRigidBody = new hkpRigidBody(chassisInfo); } TruckSetup tsetup; m_vehicles[vehicleId].m_vehicle = createVehicle( tsetup, chassisRigidBody); m_vehicles[vehicleId].m_lastRPM = 0.0f; HK_SET_OBJECT_COLOR((hkUlong)chassisRigidBody->getCollidable(), 0x80ff8080); // This hkpAction flips the car upright if it turns over. if (vehicleId == 0) { hkVector4 rotationAxis(1.0f, 0.0f, 0.0f); hkVector4 upAxis(0.0f, 1.0f, 0.0f); hkReal strength = 8.0f; m_reorientAction = new hkpReorientAction(chassisRigidBody, rotationAxis, upAxis, strength); } chassisRigidBody->removeReference(); } } chassisShape->removeReference(); } // // Create the camera. // { VehicleApiUtils::createCamera( m_camera ); } m_world->unlock(); }
ThreeWaySqueezeDemo::ThreeWaySqueezeDemo(hkDemoEnvironment* env): hkDefaultPhysicsDemo(env) { // Disable warning hkError::getInstance().setEnabled(0xf0de4356, false); // 'Your m_contactRestingVelocity seems to be too small' // // Setup the camera // { hkVector4 from(0.0f, 10.0f, 10.0f); hkVector4 to (0.0f, 0.0f, 0.0f); hkVector4 up (0.0f, 1.0f, 0.0f); setupDefaultCameras( env, from, to, up ); } // // Create the world // { hkpWorldCinfo info; info.setupSolverInfo( hkpWorldCinfo::SOLVER_TYPE_4ITERS_MEDIUM ); info.setBroadPhaseWorldSize( 350.0f ); info.m_gravity.set(0,-40,0); info.m_collisionTolerance = 0.1f; info.m_numToisTillAllowedPenetrationToi = 1.1f; m_world = new hkpWorld( info ); m_world->lock(); hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); setupGraphics(); } { hkpCollisionFilter* cf = new My3WCollisionFilter(); m_world->setCollisionFilter(cf); cf->removeReference(); } // Build a Base hkVector4 baseSize( 50.0f, 1.0f, 50.0f); { hkpRigidBodyCinfo rci; rci.m_shape = new hkpBoxShape( baseSize ); rci.m_position.set(0.0f, -0.5f, 0.0f); rci.m_motionType = hkpMotion::MOTION_FIXED; // Create a rigid body (using the template above). hkpRigidBody* base = new hkpRigidBody(rci); // Remove reference since the body now "owns" the Shape. rci.m_shape->removeReference(); // Finally add body so we can see it, and remove reference since the world now "owns" it. m_world->addEntity( base )->removeReference(); } // Create a circle of keyframed objects // Each of the objects is given a different increasing priority // We set the priority as a property on the object and extract this i nthe callback. hkVector4 blockerSize(1,3,5); hkpShape* blocker = new hkpBoxShape( blockerSize ); { //hkPseudoRandomGenerator ran(100); for (int b = 0; b < NUM_OBJECTS; b++ ) { hkVector4 up(0,1,0); hkReal angle = hkReal(b) / NUM_OBJECTS * HK_REAL_PI * 2; hkpRigidBodyCinfo rci; rci.m_position.set(5,0,0); rci.m_rotation.setAxisAngle( up, angle ); rci.m_position.setRotatedDir( rci.m_rotation, rci.m_position ); rci.m_shape = blocker; // If we set this to true, the body is fixed, and no mass properties need to be computed. rci.m_motionType = hkpMotion::MOTION_KEYFRAMED; if (b < 1) { rci.m_qualityType = HK_COLLIDABLE_QUALITY_KEYFRAMED; } else { rci.m_qualityType = HK_COLLIDABLE_QUALITY_FIXED; } m_objects[b] = new hkpRigidBody( rci ); m_world->addEntity( m_objects[b] ); m_objects[b]->removeReference(); int color = rci.m_qualityType == HK_COLLIDABLE_QUALITY_FIXED ? hkColor::rgbFromFloats(1.0f, 0.0f, 0.0f, 1.0f) : hkColor::rgbFromFloats(0.0f, 1.0f, 0.0f, 1.0f) ; HK_SET_OBJECT_COLOR((hkUlong)m_objects[b]->getCollidable(), color ); } } blocker->removeReference(); // // Crate middle sphere // { hkpShape* shape = new hkpSphereShape(1.5f); hkpRigidBodyCinfo rbInfo; rbInfo.m_shape = shape; rbInfo.m_qualityType = HK_COLLIDABLE_QUALITY_CRITICAL; hkpRigidBody* body = new hkpRigidBody(rbInfo); m_world->addEntity(body); body->removeReference(); shape->removeReference(); } m_prevObj = 0; // Zero current time at start m_currentTime = 0.0f; m_world->unlock(); }
BallAndSocketRopeDemo::BallAndSocketRopeDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env, DEMO_FLAGS_NO_SERIALIZE) { const BallAndSocketRopeVariant& variant = g_variants[env->m_variantId]; // // Setup the camera // { hkVector4 from(0.0f, -10.0f, 6.0f); hkVector4 to (0.0f, 0.0f, 1.0f); hkVector4 up (0.0f, 0.0f, 1.0f); setupDefaultCameras( env, from, to, up, 0.1f, 500.0f ); } // // Create the world // { hkpWorldCinfo info; info.setBroadPhaseWorldSize( 1000.0f ); info.m_gravity.set(0.0f, 0.0f, -9.81f); m_world = new hkpWorld( info ); m_world->lock(); m_world->m_wantDeactivation = false; setupGraphics(); // // Create a group filter to avoid intra-collision for the rope // { hkpGroupFilter* filter = new hkpGroupFilter(); m_world->setCollisionFilter( filter ); filter->removeReference(); } } hkpAgentRegisterUtil::registerAllAgents( m_world->getCollisionDispatcher() ); // // Create debris // { int numDebris = 40; hkPseudoRandomGenerator generator(0xF14); hkpRigidBodyCinfo info; hkVector4 top; top.set(0.0f, 0.0f, 0.50f); hkVector4 bottom; bottom.set(0.f, 0.f, -0.50f); info.m_shape = new hkpCapsuleShape( top, bottom, 0.3f ); hkpInertiaTensorComputer::setShapeVolumeMassProperties( info.m_shape, 5.0f, info ); for (int d = 0; d < numDebris; d++) { hkReal xPos = generator.getRandRange(-10.0f, 10.0f); hkReal yPos = generator.getRandRange(-10.0f, 10.0f); hkBool isDynamic = (generator.getRand32() % 4) != 0; info.m_position.set( xPos, yPos, isDynamic ? 0.8f : 0.5f ); info.m_motionType = isDynamic ? hkpMotion::MOTION_DYNAMIC : hkpMotion::MOTION_FIXED; hkpRigidBody* debris = new hkpRigidBody(info); m_world->addEntity(debris); debris->removeReference(); } info.m_shape->removeReference(); } // // Create ground box // { hkpRigidBodyCinfo info; info.m_motionType = hkpMotion::MOTION_FIXED; info.m_shape = new hkpBoxShape( hkVector4(100.0f, 100.0f, 0.1f) ); info.m_position(2) = - 0.1f; hkpRigidBody* ground = new hkpRigidBody(info); info.m_shape->removeReference(); m_world->addEntity(ground); ground->removeReference(); HK_SET_OBJECT_COLOR( hkUlong(ground->getCollidable()), 0xff339933); } // // Create fixed peg over the ground // { hkpRigidBodyCinfo info; info.m_motionType = hkpMotion::MOTION_FIXED; info.m_shape = new hkpCapsuleShape( hkVector4(0.0f, 1.0f, 0.0f), hkVector4( 0,-1.0f, 0), 0.3f ); info.m_position.set(0.0f, 0.0f, 3.0f); hkpRigidBody* peg = new hkpRigidBody(info); info.m_shape->removeReference(); m_world->addEntity(peg); peg->removeReference(); } // // Create chain // { hkReal elemHalfSize = 0.075f; hkpShape* sphereShape = new hkpSphereShape(0.3f); hkpShape* capsuleShape = new hkpCapsuleShape( hkVector4(elemHalfSize, 0.0f, 0.0f), hkVector4(-elemHalfSize, 0.0f, 0.0f), 0.03f ); hkpRigidBodyCinfo info; info.m_linearDamping = 0.0f; info.m_angularDamping = 0.3f; info.m_friction = 0.0f; //info.m_qualityType = HK_COLLIDABLE_QUALITY_MOVING; info.m_motionType = hkpMotion::MOTION_SPHERE_INERTIA; info.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo(1, 1); { hkArray<hkpRigidBody*> entities; for (int b = 0; b < variant.m_numBodies; b++) { info.m_position.set(elemHalfSize * 2.0f * (b - hkReal(variant.m_numBodies-1) / 2.0f), 0.0f, 4.0f); hkReal mass; hkReal inertiaMultiplier; if (0 == b || variant.m_numBodies-1 == b) { info.m_shape = sphereShape; mass = 10.0f; inertiaMultiplier = 1.0f; } else { info.m_shape = capsuleShape; mass = 1.0f; inertiaMultiplier = 50.0f; } hkpInertiaTensorComputer::setShapeVolumeMassProperties(info.m_shape, inertiaMultiplier * mass, info); info.m_mass = mass; { hkpRigidBody* body = new hkpRigidBody(info); m_world->addEntity(body); entities.pushBack(body); } } { // connect all the bodies hkpConstraintChainInstance* chainInstance; { hkpBallSocketChainData* chainData = new hkpBallSocketChainData(); chainInstance = new hkpConstraintChainInstance( chainData ); chainInstance->addEntity( entities[0] ); for (int e = 1; e < entities.getSize(); e++) { chainData->addConstraintInfoInBodySpace( hkVector4(elemHalfSize, 0.0f, 0.0f), hkVector4( -elemHalfSize, 0.0f, 0.0f) ); chainInstance->addEntity( entities[e] ); } chainData->removeReference(); } m_world->addConstraint(chainInstance); chainInstance->removeReference(); } for (int i = 0; i < entities.getSize(); i++) { entities[i]->removeReference(); } } sphereShape->removeReference(); capsuleShape->removeReference(); } m_world->unlock(); }
hkDemo::Result ShapeQueryDemo::stepDemo() { m_world->lock(); // Reset all object colors { for (int i = 0; i < m_fixedSmallBodies.getSize(); i++) { HK_SET_OBJECT_COLOR((hkUlong)m_fixedSmallBodies[i]->getCollidable(), hkColor::rgbFromChars(70,70,70)); } } // // Perform queries for the selected variant // switch (m_variantId) { // Raycast case 0: { HK_MONITOR_PUSH_DIR("hkpWorld::rayCastWithCollector"); worldRayCast( m_world, m_time, true ); HK_MONITOR_POP_DIR(); HK_MONITOR_PUSH_DIR("hkpWorld::rayCast"); worldRayCast( m_world, m_time, false ); HK_MONITOR_POP_DIR(); } { HK_MONITOR_PUSH_DIR("hkpPhantom::rayCastWithCollector"); phantomRayCast( m_world, m_time, m_rayCastPhantoms, true ); HK_MONITOR_POP_DIR(); HK_MONITOR_PUSH_DIR("hkpPhantom::rayCast"); phantomRayCast( m_world, m_time, m_rayCastPhantoms, false ); HK_MONITOR_POP_DIR(); } break; // Linear cast case 1: { HK_MONITOR_PUSH_DIR("linearCast (world)"); worldLinearCast( m_world, m_time, m_queryObjects ); HK_MONITOR_POP_DIR(); } { HK_MONITOR_PUSH_DIR("linearCast (simplePhantom)"); phantomLinearCast<hkpSimpleShapePhantom>( this, m_simplePhantoms, HK_REAL_PI*0.16f ); HK_MONITOR_POP_DIR(); } { HK_MONITOR_PUSH_DIR("linearCast (cachingPhantom)"); phantomLinearCast<hkpCachingShapePhantom>( this, m_cachingPhantoms, HK_REAL_PI*0.33f ); HK_MONITOR_POP_DIR(); } break; // Closest point case 2: { HK_MONITOR_PUSH_DIR("getClosestPoints (world)"); worldGetClosestPoints( m_world, m_time, m_queryObjects ); HK_MONITOR_POP_DIR(); } { HK_MONITOR_PUSH_DIR("getClosestPoints (simplePhantom)"); phantomGetClosestPoints<hkpSimpleShapePhantom>( this, m_simplePhantoms, HK_REAL_PI*0.16f ); HK_MONITOR_POP_DIR(); } { HK_MONITOR_PUSH_DIR("getClosestPoints (cachingPhantom)"); phantomGetClosestPoints<hkpCachingShapePhantom>( this, m_cachingPhantoms, HK_REAL_PI*0.33f ); HK_MONITOR_POP_DIR(); } break; // Penetrations case 3: { HK_MONITOR_PUSH_DIR("getPenetrations (world)"); worldGetPenetrations( m_world, m_time, m_queryObjects ); HK_MONITOR_POP_DIR(); } { HK_MONITOR_PUSH_DIR("getPenetrations (simplePhantom)"); phantomGetPenetrations<hkpSimpleShapePhantom>(this, m_simplePhantoms, HK_REAL_PI*0.16f ); HK_MONITOR_POP_DIR(); } { HK_MONITOR_PUSH_DIR("getPenetrations (cachingPhantom)"); phantomGetPenetrations<hkpCachingShapePhantom>(this, m_cachingPhantoms, HK_REAL_PI*0.33f ); HK_MONITOR_POP_DIR(); } break; // Unknown variant default: HK_ASSERT2(0xf7420c20, false, "Unknown shape query variant"); break; } // Legend if (m_variantId != 0) { const int h = m_env->m_window->getHeight(); m_env->m_textDisplay->outputText("Green: World queries", 20, h-70, (hkUint32)hkColor::GREEN, 1); m_env->m_textDisplay->outputText("Blue: Simple phantom queries", 20, h-50, (hkUint32)hkColor::BLUE, 1); m_env->m_textDisplay->outputText("Red: Caching phantom queries", 20, h-30, (hkUint32)hkColor::RED, 1); } m_time += 0.005f; m_world->unlock(); return hkDefaultPhysicsDemo::stepDemo(); }
hkDemo::Result WorldLinearCastMultithreadedDemo::stepDemo() { if (m_jobThreadPool->getNumThreads() == 0) { HK_WARN(0x34561f23, "This demo does not run with only one thread"); return DEMO_STOP; } // const WorldLinearCastMultithreadedDemoVariant& variant = g_WorldLinearCastMultithreadedDemoVariants[m_variantId]; m_world->lock(); // Reset all object colors { for (int i = 0; i < m_rocksOnTheFloor.getSize(); i++) { HK_SET_OBJECT_COLOR((hkUlong)m_rocksOnTheFloor[i]->getCollidable(), hkColor::rgbFromChars(70,70,70)); } } // For this cast we use a hkpClosestCdPointCollector to gather the results: hkpClosestCdPointCollector collectors[10]; // Since we're not too concerned with perfect accuracy, we can set the early out // distance to give the algorithm a chance to exit more quickly: m_world->getCollisionInput()->m_config->m_iterativeLinearCastEarlyOutDistance = 0.1f; m_world->unlock(); // Cast direction & length. hkVector4 castVector( 0.0f, -30.0f, 0.0f ); int numQueryObjects = m_queryObjects.getSize(); // // Setup the output array where the resulting collision points will be returned. // hkpRootCdPoint* collisionPoints = hkAllocateChunk<hkpRootCdPoint>(numQueryObjects, HK_MEMORY_CLASS_DEMO); // // Setup commands: one command for each query object. // hkArray<hkpWorldLinearCastCommand> commands; { for ( int i = 0; i < numQueryObjects; i++ ) { QueryObject& queryObject = m_queryObjects[i]; // // Let QueryObjects move in circles. // hkVector4 position; { hkReal t = m_time + HK_REAL_PI * 2 * i / m_queryObjects.getSize(); position.set( hkMath::sin( t ) * 10.0f, 10.0f, hkMath::cos( t ) * 10.0f ); } queryObject.m_transform->setTranslation(position); hkpWorldLinearCastCommand& command = commands.expandOne(); { // Init input data. { command.m_input.m_to . setAdd4( position, castVector ); command.m_input.m_maxExtraPenetration = HK_REAL_EPSILON; command.m_input.m_startPointTolerance = HK_REAL_EPSILON; command.m_collidable = queryObject.m_collidable; } // Init output data. { command.m_results = &collisionPoints[i]; command.m_resultsCapacity = 1; command.m_numResultsOut = 0; } } } } // // Create the job header. // hkpCollisionQueryJobHeader* jobHeader; { jobHeader = hkAllocateChunk<hkpCollisionQueryJobHeader>(1, HK_MEMORY_CLASS_DEMO); } // // Setup hkpWorldLinearCastJob. // m_world->markForRead(); hkpWorldLinearCastJob worldLinearCastJob(m_world->getCollisionInput(), jobHeader, commands.begin(), commands.getSize(), m_world->m_broadPhase, &m_semaphore); m_world->unmarkForRead(); // // Put the job on the queue, kick-off the PPU/SPU threads and wait for everything to finish. // { m_world->lockReadOnly(); // // Put the raycast job on the job queue. // worldLinearCastJob.setRunsOnSpuOrPpu(); m_jobQueue->addJob( worldLinearCastJob, hkJobQueue::JOB_LOW_PRIORITY ); m_jobThreadPool->processAllJobs( m_jobQueue ); m_jobThreadPool->waitForCompletion(); // // Wait for the one single job we started to finish. // m_semaphore.acquire(); m_world->unlockReadOnly(); } // // Display results. // { m_world->lock(); { for (int i = 0; i < commands.getSize(); i++) { QueryObject& queryObject = m_queryObjects[i]; hkpWorldLinearCastCommand& command = commands[i]; if ( command.m_numResultsOut > 0 ) { // move our position to the hit and draw a line along the cast direction hkVector4& pos = queryObject.m_transform->getTranslation(); hkVector4 to; to.setAdd4( pos, castVector ); hkVector4 newPos; newPos.setInterpolate4( pos, to, command.m_results->m_contact.getDistance() ); HK_DISPLAY_LINE(pos, newPos, hkColor::GREEN); // Update our QO queryObject.m_transform->setTranslation( newPos ); hkDebugDisplay::getInstance().updateGeometry( queryObject.m_collidable->getTransform(), (hkUlong)queryObject.m_collidable, 0); // call a function to display the details displayRootCdPoint( m_world, *command.m_results ); } else { // only draw a line along the cast direction hkVector4& pos = queryObject.m_transform->getTranslation(); hkVector4 to; to.setAdd4( pos, castVector ); HK_DISPLAY_LINE(pos, to, hkColor::GREEN); // Update our QO hkVector4 nirvana(10000.0f, 10000.0f, 10000.0f); queryObject.m_transform->setTranslation( nirvana ); hkDebugDisplay::getInstance().updateGeometry( queryObject.m_collidable->getTransform(), (hkUlong)queryObject.m_collidable, 0); } } } m_world->unlock(); } // // Free temporarily allocated memory. // hkDeallocateChunk( jobHeader, 1, HK_MEMORY_CLASS_DEMO ); hkDeallocateChunk(collisionPoints, numQueryObjects, HK_MEMORY_CLASS_DEMO); m_time += 0.005f; return hkDefaultPhysicsDemo::stepDemo(); }
virtual void entityActivatedCallback(hkpEntity* entity) { HK_SET_OBJECT_COLOR( hkUlong(entity->getCollidable()), 0xff55ff55 ); }
UserRayHitCollectorDemo::UserRayHitCollectorDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env), m_time(0.0f) { // // Setup the camera. // { hkVector4 from(-8.0f, 25.0f, 20.0f); hkVector4 to (0.0f, 0.0f, 0.0f); hkVector4 up (0.0f, 1.0f, 0.0f); setupDefaultCameras(env, from, to, up); } // // Create the world. // { hkpWorldCinfo info; info.setBroadPhaseWorldSize( 100.0f ); m_world = new hkpWorld(info); m_world->lock(); setupGraphics(); } // // Create a row of colored rigid bodies // { hkVector4 halfExtents(.5f, .5f, .5f ); hkpShape* shape = new hkpBoxShape( halfExtents , 0 ); int colors[4] = { hkColor::RED, hkColor::GREEN, hkColor::BLUE, hkColor::YELLOW }; for (int i = 0; i < 4; i++ ) { hkpRigidBodyCinfo ci; ci.m_motionType = hkpMotion::MOTION_FIXED; ci.m_shape = shape; ci.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo(i+1); ci.m_position.set( i * 3.0f, 0.f, 0.0f); hkpRigidBody* body = new hkpRigidBody( ci ); body->addProperty( COLOR_PROPERTY_ID, colors[i] ); m_world->addEntity(body); body->removeReference(); // show the objects in nice transparent colors colors[i] &= ~hkColor::rgbFromChars( 0, 0, 0 ); colors[i] |= hkColor::rgbFromChars( 0, 0, 0, 120 ); HK_SET_OBJECT_COLOR((hkUlong)body->getCollidable(), colors[i]); } shape->removeReference(); } m_world->unlock(); }
CrashTestDummiesDemo::CrashTestDummiesDemo(hkDemoEnvironment* env): hkDefaultPhysicsDemo( env ) { // Disable warnings: hkError::getInstance().setEnabled(0xafe97523, false); //'This utility is intended primarily for Havok demo use. If you wish to step the world asynchronously,...' // XXX remove once async stepping fixed hkpWorld::IgnoreForceMultithreadedSimulation ignoreForceMultithreaded; enableDisplayingToiInformation(true); m_ragdoll = HK_NULL; // // Create the world // { hkpWorldCinfo info; info.m_gravity.set( 0.0f, 0.0f, -10.0f ); //info.m_enableDeactivation = false; info.m_simulationType = hkpWorldCinfo::SIMULATION_TYPE_CONTINUOUS; //info.m_simulationType = hkpWorldCinfo::SIMULATION_TYPE_BACKSTEP_SIMPLE; m_world = new hkpWorld( info ); m_world->lock(); // Register ALL agents (though some may not be necessary) hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); } // // Collision Filter // { m_filter = new hkpGroupFilter(); hkpGroupFilterSetup::setupGroupFilter( m_filter ); m_world->setCollisionFilter(m_filter); } // // Setup the camera // { hkVector4 from(0.0f, 8.0f, 3.0f); hkVector4 to(0.0f, 0.0f, 1.0f); hkVector4 up(0.0f, 0.0f, 1.0f); setupDefaultCameras( env, from, to, up, 1.f, 1000.0f ); setupGraphics(); } m_car = createSimpleCarHull(); m_world->addEntity( m_car )->removeReference(); HK_SET_OBJECT_COLOR(hkUlong(m_car->getCollidable()), hkColor::rgbFromChars(255, 255, 255, 50)); fitRagdollsIn(hkVector4::getZero()); //hkVector4 pos(3.0f, 1.0f, 0.8f); //putBoxesIn( pos ); //putBoxesIn(hkVector4(4.1f, 1.0f, 0.8f)); createGroundBox(); createFastObject(); m_world->unlock(); }
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 ); } }
PlanetGravityDemo::PlanetGravityDemo( hkDemoEnvironment* env ) : hkDefaultPhysicsDemo(env) { hkString filename; // We have a different binary file depending on the compiler and platform filename.printf( "Resources/Physics/Levels/planetgravity_L%d%d%d%d.hkx", hkStructureLayout::HostLayoutRules.m_bytesInPointer, hkStructureLayout::HostLayoutRules.m_littleEndian ? 1 : 0, hkStructureLayout::HostLayoutRules.m_reusePaddingOptimization? 1 : 0, hkStructureLayout::HostLayoutRules.m_emptyBaseClassOptimization? 1 : 0 ); hkIstream infile( filename.cString() ); HK_ASSERT( 0x215d080c, infile.isOk() ); hkpWorld::IgnoreForceMultithreadedSimulation ignoreForceMultithreaded; // Disable warning: 'm_contactRestingVelocity not set, setting it to REAL_MAX, so that the new collision restitution code will be disabled' hkError::getInstance().setEnabled( 0xf03243ed, false ); // Load the startup scene { m_worldUp.set( 0.0f, 0.0f, 1.0f ); m_characterForward.set( 1.0f, 0.0f, 0.0f ); // Initialize hkpSurfaceInfo for storing the old ground info m_previousGround = new hkpSurfaceInfo(); m_framesInAir = 0; m_cameraForward.set( 1.0f, 0.0f, 0.0f ); m_cameraUp = m_cameraForward; m_cameraPosition.set( 20.0f, 1.0f, 35.0f ); m_detachedCamera = false; // Load the world. m_world = loadWorld( filename.cString(), &m_physicsData, &m_loadedData ); m_world->markForWrite(); setupDefaultCameras( env, m_cameraPosition, m_characterRigidBody->getPosition(), m_worldUp ); // Setup graphics setupGraphics(); forceShadowState(false); // Disable shadows setupSkyBox(env); { removeLights( m_env ); float v[] = { 0.941f, 0.941f, 0.784f }; m_flashLight = hkgLight::create(); m_flashLight->setType( HKG_LIGHT_DIRECTIONAL ); m_flashLight->setDiffuse( v ); v[0] = 0; v[1] = 1; v[2] = -0.5; m_flashLight->setDirection( v ); v[0] = 0; v[1] = -1000; v[2] = 0; m_flashLight->setPosition( v ); m_flashLight->setDesiredEnabledState( true ); env->m_displayWorld->getLightManager()->addLight( m_flashLight ); env->m_displayWorld->getLightManager()->computeActiveSet( HKG_VEC3_ZERO ); } // Set up the collision filter { hkpGroupFilter* filter = new hkpGroupFilter(); filter->disableCollisionsBetween(1, 1); m_world->setCollisionFilter(filter); filter->removeReference(); } // Go through all loaded rigid bodies for( int i = 0; i < m_physicsData->getPhysicsSystems().getSize(); i++ ) { const hkArray<hkpRigidBody*>& bodies = m_physicsData->getPhysicsSystems()[i]->getRigidBodies(); for( int j = 0; j < bodies.getSize(); j++ ) { hkString rbName( bodies[j]->getName() ); // If the rb is a planet (name is "planet*") if( rbName.beginsWith( "planet" ) ) { // If the body is a representation of a gravitational field (name: "*GravField"), // remove it from the simulation. if( rbName.endsWith( "GravField" ) ) { m_world->removeEntity( bodies[j] ); } // Otherwise, it's actually a planet. else { hkAabb currentAabb; const hkpCollidable* hullCollidable = HK_NULL; // Find the planet's gravity field hkpRigidBody* planetRigidBody = bodies[j]; hkString gravFieldRbName; gravFieldRbName.printf( "%sGravField", rbName.cString() ); hkpRigidBody* gravFieldRigidBody = m_physicsData->findRigidBodyByName( gravFieldRbName.cString() ); // If there's a GravField rigid body, then grab its collidable to be used for gravity calculation. if( gravFieldRigidBody ) { hullCollidable = gravFieldRigidBody->getCollidable(); gravFieldRigidBody->getCollidable()->getShape()->getAabb( gravFieldRigidBody->getTransform(), 0.0f, currentAabb ); } else { planetRigidBody->getCollidable()->getShape()->getAabb( planetRigidBody->getTransform(), 0.0f, currentAabb ); } // Scale up the planet's gravity field's AABB so it goes beyond the planet hkVector4 extents; extents.setSub4( currentAabb.m_max, currentAabb.m_min ); hkInt32 majorAxis = extents.getMajorAxis(); hkReal maxExtent = extents( majorAxis ); maxExtent *= 0.4f; // Scale the AABB's extents hkVector4 extension; extension.setAll( maxExtent ); currentAabb.m_max.add4( extension ); currentAabb.m_min.sub4( extension ); // Attach a gravity phantom to the planet so it can catch objects which come close SimpleGravityPhantom* gravityAabbPhantom = new SimpleGravityPhantom( planetRigidBody, currentAabb, hullCollidable ); m_world->addPhantom( gravityAabbPhantom ); gravityAabbPhantom->removeReference(); // Add a tracking action to the phantom so it follows the planet. This allows support for non-fixed motion type planets if (planetRigidBody->getMotion()->getType() != hkpMotion::MOTION_FIXED) { PhantomTrackAction* trackAction = new PhantomTrackAction( planetRigidBody, gravityAabbPhantom ); m_world->addAction( trackAction ); trackAction->removeReference(); } } } // if the rigid body is a launchpad (name: "launchPadSource*") else if( rbName.beginsWith("launchPadSource" ) ) { hkString targetName; // Find launchpad "target" (used to calculate trajectory when launching) targetName.printf( "launchPadTarget%s", rbName.substr( hkString::strLen("launchPadSource") ).cString() ); hkpRigidBody* target = m_physicsData->findRigidBodyByName( targetName.cString() ); HK_ASSERT2( 0x0, target, "All launchPadSource rigid bodies must have associated launchPadTargets." ); // Add a collision listener to the launchpad so it can apply forces to colliding rbs LaunchPadListener* launchPadListener = new LaunchPadListener( target->getPosition() ); bodies[j]->addCollisionListener( launchPadListener ); bodies[j]->setMotionType( hkpMotion::MOTION_FIXED ); HK_SET_OBJECT_COLOR( reinterpret_cast<hkUlong>( bodies[j]->getCollidable() ), hkColor::RED ); m_world->removeEntity( target ); } // A "basic" launchpad just applies a force in the direction of the collision normal else if( rbName.beginsWith( "launchPadBasic" ) ) { LaunchPadListener* launchPadListener = new LaunchPadListener( bodies[j]->getMass() ); bodies[j]->addCollisionListener( launchPadListener ); bodies[j]->setMotionType( hkpMotion::MOTION_FIXED ); HK_SET_OBJECT_COLOR( reinterpret_cast<hkUlong>( bodies[j]->getCollidable() ), hkColor::RED ); } else if( rbName.beginsWith( "teleporterSource" ) ) { hkString targetName; // Find the teleportation destination of the teleporter targetName.printf( "teleporterTarget%s", rbName.substr( hkString::strLen("teleporterSource") ).cString() ); hkpRigidBody* target = m_physicsData->findRigidBodyByName( targetName.cString() ); HK_ASSERT2( 0, target, "All teleporterSource rigid bodies must have associated teleporterTargets." ); // Replace the rb with a callback shape phantom. Colliding rbs will be teleported to the destination. TeleporterPhantomCallbackShape* phantomCallbackShape = new TeleporterPhantomCallbackShape( target->getTransform() ); hkpBvShape* phantom = new hkpBvShape( bodies[j]->getCollidable()->getShape(), phantomCallbackShape ); phantomCallbackShape->removeReference(); bodies[j]->getCollidable()->getShape()->removeReference(); bodies[j]->setShape( phantom ); phantom->removeReference(); m_world->removeEntity( target ); } else if( rbName.beginsWith( "TurretTop" ) ) { // Create a place to store state information for this turret. Turret& turret = m_turrets.expandOne(); turret.constraint = bodies[j]->getConstraint(0); turret.hinge = static_cast<hkpLimitedHingeConstraintData*>( const_cast<hkpConstraintData*>( turret.constraint->getData() ) ); turret.turretRigidBody = bodies[j]; turret.cooldown = 0.0f; // Allow the hinge to spin infinitely and start the motor up turret.hinge->disableLimits(); turret.hinge->setMotorActive( turret.constraint, true ); // Do not allow the turret's simulation island deactivate. // If it does, it will stop spinning. turret.turretRigidBody->setDeactivator( hkpRigidBodyDeactivator::DEACTIVATOR_NEVER ); } // Update collision filter so that needless CollColl3 agents are not created. // For example, turrets and geometry marked as "static" (such as the swing) // should never collide with a planet, nor each other. if( ( rbName.beginsWith( "planet" ) && !rbName.endsWith( "GravField" ) ) || rbName.beginsWith( "Turret" ) || rbName.endsWith( "_static" ) ) { bodies[j]->setCollisionFilterInfo( hkpGroupFilter::calcFilterInfo( 1 ) ); // Destroy or create agents (according to new quality type). This also removes Toi events. m_world->updateCollisionFilterOnEntity(bodies[j], HK_UPDATE_FILTER_ON_ENTITY_FULL_CHECK, HK_UPDATE_COLLECTION_FILTER_PROCESS_SHAPE_COLLECTIONS); } } } m_world->unmarkForWrite(); } }