结论1:简单模拟下 Box2D性能在多刚体上 比PhysX高很多,刚体数量比较少的情况下 PhysX 性能高很多
测试1:
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 <GetLinearVelocity().Length()<GetMass() <
// 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)
{
automCpuDispatcher = 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;
}
输出分别是
调整为10个刚体, 模拟100W次 输出结果为
TODO