void hctConvertToPhantomActionFilter::process( hkRootLevelContainer& data ) { // Find and hkxScene and a hkPhysics Data objects in the root level container hkxScene* scenePtr = reinterpret_cast<hkxScene*>( data.findObjectByType( hkxSceneClass.getName() ) ); if (scenePtr == HK_NULL || (scenePtr->m_rootNode == HK_NULL) ) { HK_WARN_ALWAYS(0xabbaa5f0, "No scene data (or scene data root hkxNode) found. Can't continue."); return; } hkpPhysicsData* physicsPtr = reinterpret_cast<hkpPhysicsData*>( data.findObjectByType( hkpPhysicsDataClass.getName() ) ); if (physicsPtr == HK_NULL) { HK_WARN_ALWAYS(0xabbaa3d0, "No physics data found, you need to use Create Rigid Bodies before this filter or have bodies already in the input data."); return; } // Keep track of how many phantoms we created so we can reported int numConverted = 0; // Search for rigid bodies in the scene for (int psi=0; psi<physicsPtr->getPhysicsSystems().getSize(); psi++) { const hkpPhysicsSystem* psystem = physicsPtr->getPhysicsSystems()[psi]; for (int rbi=0; rbi<psystem->getRigidBodies().getSize(); rbi++) { hkpRigidBody* rbody = psystem->getRigidBodies()[rbi]; const char* rbName = rbody->getName(); // Require an associated node in the scene hkxNode* rbNode = (rbName)? scenePtr->findNodeByName(rbName): HK_NULL; if( !rbNode ) { continue; } // Require an 'hkPhantomAction' attribute group const hkxAttributeGroup* attrGroup = rbNode->findAttributeGroupByName("hkPhantomAction"); if (!attrGroup) { continue; } // Create our phantom shape MyPhantomShape* myPhantomShape = new MyPhantomShape(); { // Set action type (required) const char* actionTypeStr = HK_NULL; attrGroup->getStringValue( "action", true, actionTypeStr ); if( actionTypeStr ) { if( hkString::strCasecmp( actionTypeStr, "wind" ) == 0 ) { myPhantomShape->m_actionType = MyPhantomShape::ACTION_WIND; } else if( hkString::strCasecmp( actionTypeStr, "attract" ) == 0 ) { myPhantomShape->m_actionType = MyPhantomShape::ACTION_ATTRACT; } else if( hkString::strCasecmp( actionTypeStr, "deflect" ) == 0 ) { myPhantomShape->m_actionType = MyPhantomShape::ACTION_DEFLECT; } else { HK_WARN_ALWAYS(0xabbad3b4, "Unknow action type ("<<actionTypeStr<<")."); } } else { HK_WARN_ALWAYS(0xabba9834, "Can't fine \"action\" attribute"); } // Set other attributes (optional) attrGroup->getVectorValue( "direction", false, myPhantomShape->m_direction ); attrGroup->getFloatValue( "strength", false, myPhantomShape->m_strength ); // Useful warnings if ((myPhantomShape->m_actionType == MyPhantomShape::ACTION_WIND) && (myPhantomShape->m_direction.lengthSquared3()==0.0f)) { HK_WARN_ALWAYS(0xabbadf82, "Wind direction is invalid - action will have no effect"); } if (myPhantomShape->m_strength==0.0f) { HK_WARN_ALWAYS(0xabbacc83, "Strength is 0 - action will have no effect"); } } // Set the phantom as a new bounding shape for the body { const hkpShape* oldShape = rbody->getCollidable()->getShape(); hkpBvShape* bvShape = new hkpBvShape( oldShape, myPhantomShape ); myPhantomShape->removeReference(); rbody->setShape( bvShape ); bvShape->removeReference(); } // Remove meshes if the user chose to do so if (m_options.m_removeMeshes && (hkString::strCmp(rbNode->m_object.getClass()->getName(), "hkxMesh")==0) ) { rbNode->m_object = HK_NULL; } HK_REPORT("Converted rigid body \""<<rbName<<"\" to phantom action"); numConverted++; } } // Give a warning if the filter didn't do anything useful if (numConverted==0) { HK_WARN_ALWAYS(0xabba7632, "No rigid bodies converted to phantom action."); } else { HK_REPORT("Converted "<<numConverted<<" rigid bodies."); } }
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(); }