PhysX和Box2D 性能对比
结论1:简单模拟下 刚体数量比较多的情况下 PhysX 性能高很多,反之Box2D性能高很多
测试1:
//box2d int main(int argc, char** argv) { B2_NOT_USED(argc); B2_NOT_USED(argv); // Define the gravity vector. b2Vec2 gravity(0.0f, -9.8f); // Construct a world object, which will hold and simulate the rigid bodies. b2World world(gravity); // Define the ground body. //b2BodyDef groundBodyDef; //groundBodyDef.position.Set(0.0f, -10.0f); // Call the body factory which allocates memory for the ground body // from a pool and creates the ground box shape (also from a pool). // The body is also added to the world. // b2Body* groundBody = world.CreateBody(&groundBodyDef); // Define the ground box shape. //b2PolygonShape groundBox; // The extents are the half-widths of the box. // groundBox.SetAsBox(50.0f, 10.0f); // Add the ground fixture to the ground body. //groundBody->CreateFixture(&groundBox, 0.0f); // Set the box density to be non-zero, so it will be dynamic. // fixtureDef.density = 1.0f; // Override the default friction. //fixtureDef.friction = 0.3f; b2Body* body;// = world.CreateBody(&bodyDef); // Add the shape to the body. // body->CreateFixture(&fixtureDef); for (int i = 0; i < 100; i++) { // b2Body* body = world.CreateBody(&bodyDef); // Add the shape to the body. //body->CreateFixture(&fixtureDef); } for (int i = 0; i < 250; i++) { // Define the dynamic body. We set its position and call the body factory. b2BodyDef bodyDef; bodyDef.type = b2_dynamicBody; bodyDef.position.Set(0.0f, 0.0f); // Define another box shape for our dynamic body. b2PolygonShape dynamicBox; dynamicBox.SetAsBox(1.0f, 1.0f); // Define the dynamic body fixture. b2FixtureDef fixtureDef; fixtureDef.shape = &dynamicBox; bodyDef.type = b2_dynamicBody; body = world.CreateBody(&bodyDef); bodyDef.position.Set(1.0f, 1.0f*i); // Add the shape to the body. body->CreateFixture(&fixtureDef); //body->ApplyForceToCenter(b2Vec2(10.0f, 0.0f),true); } // Prepare for simulation. Typically we use a time step of 1/60 of a // second (60Hz) and 10 iterations. This provides a high quality simulation // in most game scenarios. float32 timeStep = 1.0f / 30.0f; int32 velocityIterations = 2; int32 positionIterations = 2; /* b2RayCastOutput output ; b2RayCastInput input; input.maxFraction = 12.0f; input.p1 = body->GetPosition(); input.p2 = body->GetPosition(); input.p2.x += 1.0f;*/ int t = time(nullptr); printf("start simulate\n"); // This is our little game loop. for (int32 i = 0; i < 100; ++i) { // Instruct the world to perform a single step of simulation. // It is generally best to keep the time step and iterations fixed. world.Step(0.016f, 8, 2); // Now print the position and angle of the body. // b2Vec2 position = body->GetPosition(); //float32 angle = body->GetAngle(); //printf("%4.2f %4.2f %4.2f\n", position.x, position.y, angle); } cout << time(nullptr) - t <<" "<< body->GetLinearVelocity().Length()<<" "<< body->GetMass() <<" "<< world.GetBodyCount() << endl; // When the world destructor is called, all bodies and joints are freed. This can // create orphaned pointers, so be careful about your world management. system("pause"); return 0; }
//physx int main() { PxDefaultAllocator gDefaultAllocatorCallback; static PxSampleAllocator* gAllocator = new PxSampleAllocator; //Recording memory allocations is necessary if you want to //use the memory facilities in PVD effectively. Since PVD isn't necessarily connected //right away, we add a mechanism that records all outstanding memory allocations and //forwards them to PVD when it does connect. //This certainly has a performance and memory profile effect and thus should be used //only in non-production builds. bool recordMemoryAllocations = true; #ifdef RENDERER_ANDROID const bool useCustomTrackingAllocator = false; #else const bool useCustomTrackingAllocator = true; #endif PxAllocatorCallback* allocator = &gDefaultAllocatorCallback; auto mFoundation = PxCreateFoundation(PX_FOUNDATION_VERSION, *allocator, getSampleErrorCallback()); PxTolerancesScale scale; auto mPvd = physx::PxCreatePvd(*mFoundation); auto mPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *mFoundation, scale, recordMemoryAllocations, mPvd); if (!mPhysics) { } if (!PxInitExtensions(*mPhysics, mPvd)) { } PxCookingParams params(scale); params.meshWeldTolerance = 0.001f; params.meshPreprocessParams = PxMeshPreprocessingFlags(PxMeshPreprocessingFlag::eWELD_VERTICES); params.buildGPUData = true; //Enable GRB data being produced in cooking. // setup default material... auto mMaterial = mPhysics->createMaterial(0.5f, 0.5f, 0.1f); PxSceneDesc sceneDesc(mPhysics->getTolerancesScale()); sceneDesc.filterShader = PxDefaultSimulationFilterShader; if (!sceneDesc.cpuDispatcher) { auto mCpuDispatcher = PxDefaultCpuDispatcherCreate(0); sceneDesc.cpuDispatcher = mCpuDispatcher; } sceneDesc.gravity = PxVec3(0.0f, -9.81f, 0.0f); // sceneDesc.flags |= PxSceneFlag::eENABLE_GPU_DYNAMICS; sceneDesc.flags |= PxSceneFlag::eENABLE_PCM; //sceneDesc.flags |= PxSceneFlag::eENABLE_AVERAGE_POINT; sceneDesc.flags |= PxSceneFlag::eENABLE_STABILIZATION; //sceneDesc.flags |= PxSceneFlag::eADAPTIVE_FORCE; sceneDesc.flags |= PxSceneFlag::eENABLE_ACTIVETRANSFORMS; sceneDesc.flags |= PxSceneFlag::eSUPPRESS_EAGER_SCENE_QUERY_REFIT; //sceneDesc.flags |= PxSceneFlag::eDISABLE_CONTACT_CACHE; //sceneDesc.broadPhaseType = PxBroadPhaseType::eGPU; sceneDesc.gpuMaxNumPartitions = 8; // sceneDesc.flags |= PxSceneFlag::eREQUIRE_RW_LOCK; PxScene* scene = mPhysics->createScene(sceneDesc); PxRigidDynamic* box; for (int i = 0; i < 250; i++) { box = PxCreateDynamic(*mPhysics, PxTransform(PxVec3(0.0f, 0.0f, 0.0f)), PxBoxGeometry(PxVec3(1.0, 1.0 *i, 1.0)), *mMaterial, 0.5); box->setMass(0.0); // box->setAngularDamping(100); scene->addActor(*box); box->addForce(PxVec3(10.0f, 0.0f, 0.0f)); } auto tim = time(nullptr); for (int i = 0; i < 100; i++) { scene->simulate(0.016f); scene->fetchResults(true); //while (!scene->fetchResults(false)) { } } cout << time(nullptr) - tim << " " << box->getLinearVelocity().magnitude() << endl; // scene->addActor(*box); system("pause"); /* gSampleCommandLine = new SampleCommandLine(GetCommandLineA()); mainInitialize(); mainLoop(); mainTerminate();*/ return 0; }
调整为500个刚体 模拟10W次 输出结果为
10个刚体 模拟100W次
2个刚体 模拟100W次
TODO