Sign in to follow this  
N01

PhysX - Scene scaling, object size, timestep and gravity inconsistency.

Recommended Posts

N01    194

Hey, i've started integrating PhysX into my graphical engine recently(purpose is basic collision with level, which is represented by static primitives and some debris, like cans, barrels and bottles reacting at bullets and impact with a player). Currently done is representing the scene with static primitives and using convex hulls for dynamic actors. And at this stage i've noticed PhysX acting not exactly like one would expect. I'll try to describe it as verbose as possible, and i would like to hear some logical explanation and advice.

My initial setup was:

  • Timestep 1/30.0f, called in a separate from rendering thread, which runs at 30 FPS.
  • simulate() and fetchResults() Are called exactly, as in example from official documentation.
  • Gravity: Y = -9.8
  • Material for static actors: 1.0f, 1.0f, 0.5f (static friction, dynamic friction, restitution)
  • Material for dynamic actors: 0.5f, 0.5f, 0.3f
  • Static actors don't have any other parameters. All actors are positioned and scaled correctly, checked it through PVD.

As for dynamic actors:

setMass(PxReal(Objects[f].weight)); //currently 1-30 for different objects
setLinearDamping(PxReal(0.05f));
setAngularDamping(PxReal(0.05f));

i also set setCMassLocalPose to model's relative center(because some models may be not centered correctly).


First of all, i would expect to just set object's mass in kilograms, or at least relative to other objects, with default gravity of -9.8 and timestep of 30. Neither worked. Objects with mass of hundreds or thousands kilograms end up falling through the floor or bouncing crazily. And smaller objects with lower mass were too floaty.

At first, all big\medium-sized objects were freaking out. And by looking at PVD's grid in comparison with my scene, i figured i need to rescale my scene. My level is up to 3000 by 3000 units size. Medium-sized object is 20-30 units, and small object is around 2-4 units of size. So in process passing physical objects to PhysX, i now rescale them and their positions by some factor(now it's 0.05f). And it made things better.

But there are significant problems remaining. First thing i don't get is why scene get's slo-mo, if i decrease time step size. PhysX Tips page says "Few substeps: moon gravity effects", so it's vice-versa.
Actors with bigger mass still act inadequately.
Different scaling factor affects simulation speed. So setting scale to a smaler value, makes everything move more rapidly and with less inertia\bounce. With smaller scene scale, smaller objects act like they have enormous friction or low bounce\angular velocity.

And that leads to the main problem i can't solve yet is that with scene, rescaled by 0.05f smaller objects(like soda can or a pack of cigarettes) act really floaty. They don't react well on collision, they rotate too slowly and don't bounce. I have a scene with a character model, some barrels, a big box and soda can, represented with convex hulls. And environment, represented with boxes, spheres and capsules. I fly around and shoot spheres at them, and look how they react. Medium-sized objects have a mass of 20-30, and small objects have a mass of 5(yeah, i did mention relative mass inconsistency. if i put more appropriate relative weight to smaller objects, they act even floatier and don't react much on a sphere with 100000 density and while falling, they act more like poo).

I just don't want to fiddle with magic numbers. I would like to find some explanation and make it more predictable and consistent.

P.S. PhysX version is 3.2.4 and platform is Windows.
P.S.S. I hope this is an appropriate forum for such questions.

Edited by N01

Share this post


Link to post
Share on other sites
noatom    927

Physx...you might find yourself in trouble....there are not many(almost none) tutorials,or documentations for it.I mean sure,there's the official one,but that's it.So you're kinda on your own... (i'm talking about the current version)

 

BTW i like how your game looks

Edited by noatom

Share this post


Link to post
Share on other sites
j3p    1363

Well, first I'd try leaving all the weird scaling factors untouched and decide exactly the measures of my world. Start with 1 unit = 1m and begin experimenting with some convex hulls no larger than 5 units (unscaled). Too large objects can be deceiving as they may seem to fall in slo-mo. After these "standard sized" actors are behaving correctly, you can start putting more arbitrary actors in. And if physx provides any scaling factors I strongly suggest ignoring them as they can initially cause problems exactly like these.

Share this post


Link to post
Share on other sites
N01    194

if i pass my scene, without re-scaling it to lower size with all the default parameters, it's super slow-mo. and objects with the mass of dozens already start to freak out(penetrating through static actors, bouncing weirdly or falling through completely). smaller objects(up to 5 units) are also slow-mo. that's why i figured problem is my scene's size, but it just doesn't sound right.

 

 

here's how i set object's transformations:

 glmTempMatrix = glm::translate(glm::mat4(), Objects[f].position.toVec3());
 glmTempMatrix = glm::rotate(glmTempMatrix , Objects[f].rotation.x, 1.0f, 0.0f, 0.0f);
 glmTempMatrix = glm::rotate(glmTempMatrix , Objects[f].rotation.y, 0.0f, 1.0f, 0.0f);
 glmTempMatrix = glm::rotate(glmTempMatrix , Objects[f].rotation.z, 0.0f, 0.0f, 1.0f);

 pxTempMatrix = PxMat44(glm::value_ptr(glmTempMatrix));

 convexEntities[dynamicEntityId].mDynamicActor->setGlobalPose(PxTransform(pxTempMatrix));

 //note: not re-scaling factor, jsut a normal objects's scale in a real scene.
 PxMeshScale scale(PxVec3(Objects[f].scale.x, Objects[f].scale.y, Objects[f].scale.z), PxQuat::createIdentity());
 PxShape* aConvexShape = convexEntities[dynamicEntityId].mDynamicActor->createShape(PxConvexMeshGeometry(convexMesh, scale), *mDynamicMaterial);
Edited by N01

Share this post


Link to post
Share on other sites
j3p    1363
That PxMeshScale is probably what you should attempt to get rid of, for now. Scale should be 1.0, and the actor size determined entirely by the convex hull dimensions (at the point where you "cook" it). How big is the convex hull anyway, I mean the approximate distance between two furthest points forming it?
 
At least in earlier versions of physx 3.x, that PxMeshScale didn't fix oversized convex hulls. Did you already try unit spheres (for example), to see if they make any difference in speed? And how's your initialization code?

Share this post


Link to post
Share on other sites
N01    194

 

That PxMeshScale is probably what you should attempt to get rid of, for now. Scale should be 1.0, and the actor size determined entirely by the convex hull dimensions (at the point where you "cook" it). How big is the convex hull anyway, I mean the approximate distance between two furthest points forming it?

ok, tried pre-scaling convex hull(by multiplying vertices), thus removing PxMeshScale. everything acts exactly the same.

to clarify, my convex hulls are based on the model. but this model can be used by different entities, with different scaling. that's it. so i rescale initial convex hull by that entitiy's scale using PxMeshScale, before passing it to the scene, so it fits perfectly. and they look fine in PVD. so data is 100% ok, but i may set some parameters wrong. documentation is not clear on call order and physical parameters of objects and doesn't say much about scale\mass.

 

 

At least in earlier versions of physx 3.x, that PxMeshScale didn't fix oversized convex hulls. Did you already try unit spheres (for example), to see if they make any difference in speed? And how's your initialization code?

 

just tried PxSphereGeometry(1.0f) instead of convex geometry, they're in slow-mo as well, but they don't fall through static stuff(i guess, cause sphere collision is really basic and predictable).

 

my PhysX base scene initialization:

        mFoundation = PxCreateFoundation(
            PX_PHYSICS_VERSION,
            gDefaultAllocatorCallback,
            gDefaultErrorCallback);

        mCooking = PxCreateCooking(PX_PHYSICS_VERSION, *mFoundation, PxCookingParams());

        mPhysics = PxCreatePhysics(
            PX_PHYSICS_VERSION,
            *mFoundation,
            PxTolerancesScale());

        PxInitExtensions(*mPhysics);

        PxSceneDesc sceneDesc(mPhysics->getTolerancesScale());
        sceneDesc.gravity = PxVec3(0.0f, -9.8f, 0.0f);

        if(!sceneDesc.cpuDispatcher)
        {
            PxDefaultCpuDispatcher* mCpuDispatcher = PxDefaultCpuDispatcherCreate(1);
            sceneDesc.cpuDispatcher = mCpuDispatcher;
        }

        if(!sceneDesc.filterShader)
            sceneDesc.filterShader  = gDefaultFilterShader;


        mScene = mPhysics->createScene(sceneDesc);

Timestep:

 

mStepSize = 1.0f / 30.0f;

float deltaTime = clock() - mLastTime;
        mAccumulator  += deltaTime;
        if(mAccumulator < mStepSize)
            return;

        mAccumulator -= mStepSize;

        mScene->simulate(mStepSize);
        mScene->fetchResults(true);

        mLastTime = clock();

running in a separate thread at 30 FPS.

Edited by N01

Share this post


Link to post
Share on other sites
j3p    1363

Hm ok, so that's not the problem then. I recall that scale thing being a source of some problems earlier, but don't know about that anymore. I'm using 3.3 beta 2 myself now.

 

Initialization seems ok. Check filter shaders and possibly compare your code to those (awful) examples in case you're missing something. Are you calling PxRigidBodyExt::setMassAndUpdateInertia for dynamic actors after creating all the shapes? That's also pretty important. You shouldn't need that setMass() at all.

 

I'll post if something comes to mind while coding my own stuff.

Edited by fanwars

Share this post


Link to post
Share on other sites
N01    194

oh, i just used PxRigidDynamic::setMass(...);

i replaced it with PxRigidBodyExt::setMassAndUpdateInertia after createShape(), using the same masses(~25 for medium object and 1-5 for small objects). and now, if i set scene scale factor to 1.0f, objects don't fall through stuff, but everything is still in slow-mo. so maybe i've missed some other parameter?

 

here's how i initialize convex hull actors(beware of temporary\experimental grabage-code):

 


mDynamicMaterial = mPhysics->createMaterial(0.5f, 0.5f, 0.3f);
mStaticMaterial = mPhysics->createMaterial(1.0f, 1.0f, 0.5f);

...

convexEntities[convexEntityId].objectId = f;
convexEntities[convexEntityId].isStatic = Objects[f].isImmovable;

tempVertices.resize(Objects[f].convexHull.size()/3); //convert to PxVec3, eliminate this part in future
for(unsigned v = 0, p = 0; v < Objects[f].convexHull.size() - 1; v += 3, p++) {
    tempVertices[p] = PxVec3(Objects[f].convexHull[v], Objects[f].convexHull[v + 1], Objects[f].convexHull[v + 2]);
}

convexDesc.points.count     = tempVertices.size();
convexDesc.points.stride    = sizeof(PxVec3);
convexDesc.points.data      = &tempVertices[0];
convexDesc.flags            = PxConvexFlag::eCOMPUTE_CONVEX | PxConvexFlag::eINFLATE_CONVEX;//just in case, so it never exceeds 256. mesh reduction algorithms i found, screw up convex hulls for some reason, so i decided to rely on PhysX.

PxToolkit::MemoryOutputStream buf;
if(!mCooking->cookConvexMesh(convexDesc, buf)) {
    LOG << " #Failed to cook convex hull for " << modelStorage[Objects[f].modelId].modelName << endl;
    break;
}

PxToolkit::MemoryInputData input(buf.getData(), buf.getSize());
PxConvexMesh* convexMesh = mPhysics->createConvexMesh(input);

tempMatrix = glm::translate(glm::mat4(), Objects[f].position.toVec3());
tempMatrix = glm::rotate(tempMatrix, Objects[f].rotation.x, 1.0f, 0.0f, 0.0f);
tempMatrix = glm::rotate(tempMatrix, Objects[f].rotation.y, 0.0f, 1.0f, 0.0f);
tempMatrix = glm::rotate(tempMatrix, Objects[f].rotation.z, 0.0f, 0.0f, 1.0f);

pxTempMatrix = PxMat44(glm::value_ptr(tempMatrix));
if(Objects[f].isImmovable == false) {
    convexEntities[convexEntityId].mDynamicActor = mPhysics->createRigidDynamic(PxTransform(PxVec3(0.0)));
    convexEntities[convexEntityId].mDynamicActor->setGlobalPose(PxTransform(pxTempMatrix));
    convexEntities[convexEntityId].mDynamicActor->setLinearDamping(PxReal(0.05f));
    convexEntities[convexEntityId].mDynamicActor->setAngularDamping(PxReal(0.05f));

    convexEntities[convexEntityId].mDynamicActor->setCMassLocalPose(PxTransform(PxVec3(Objects[f].localCenter.x, Objects[f].localCenter.y, Objects[f].localCenter.z)));

    PxMeshScale scale(PxVec3(Objects[f].scale.x,Objects[f].scale.y,Objects[f].scale.z), PxQuat::createIdentity()); //because it's more convenient in my case
    PxShape* aConvexShape = convexEntities[convexEntityId].mDynamicActor->createShape(PxConvexMeshGeometry(convexMesh, scale), *mDynamicMaterial);
    PxRigidBodyExt::setMassAndUpdateInertia(*convexEntities[convexEntityId].mDynamicActor, Objects[f].weight);

    mScene->addActor(*convexEntities[convexEntityId].mDynamicActor);
} else {
    convexEntities[convexEntityId].mStaticActor = mPhysics->createRigidStatic(PxTransform(PxVec3(0.0)));
    convexEntities[convexEntityId].mStaticActor->setGlobalPose(PxTransform(pxTempMatrix));

    PxMeshScale scale(PxVec3(Objects[f].scale.x,Objects[f].scale.y,Objects[f].scale.z), PxQuat::createIdentity());
    PxShape* aConvexShape = convexEntities[convexEntityId].mStaticActor->createShape(PxConvexMeshGeometry(convexMesh, scale), *mStaticMaterial);

    mScene->addActor(*convexEntities[convexEntityId].mStaticActor);
}

P.S. i use PxDefaultSimulationFilterShader.

Edited by N01

Share this post


Link to post
Share on other sites
j3p    1363

If you're sure that slowness isn't just an illusion caused by big objects (after all, even a unit sphere can seem to accelerate pretty slow from distance in empty world) it's most likely a bug in timestepping or anything related. Like I'm not sure if that "mLastTime = clock();" should be there after "return" -> deltaTime grows too big if mAccumulator < mStepSize (mLastTime should be updated in any case). But slo-mo is usually pretty easy to fix if the simulation is otherwise working correctly.

Edited by fanwars

Share this post


Link to post
Share on other sites
N01    194

yeah, the proplem is, most likely, there. i copied this snippet straight from documentation:

virtual bool advance(PxReal dt)
{
    mAccumulator  += dt;
    if(mAccumulator < mStepSize)
        return false;

    mAccumulator -= mStepSize;

    mScene->simulate(mStepSize);
    return true;
}

and it doesn't explain, what "dt" is. but it's certainly not what i passed. because it's float and it should be smaller, than 1.0f/stepSize; but if i remove all these extra-timings and leave only simulate() and fetchResults(), it's still slow-mo. this parameter only makes difference, if i divide it by really high values, like tens of thousands, then physx turns into  a complete slideshow. if i make it's value bigger, it doesn't matter.

 

yes, simulation looks kinda correct, but it's hard to judge bounce and friction in such slow motion.

maybe, i shouldn't call fetchResults(true) immedieately after simulate(). it's not very clear.


Share this post


Link to post
Share on other sites
j3p    1363
I guess the ultimate point of these snippets is to keep the physics timestep fixed while graphics run at higher fps interpolating frame results. There are obviously
better solutions than this piece of code and those will be more relevant at later development stages... Since your graphics run at constant 30fps, you could perhaps replace that code with just simulate(1.0f/30.0f) and fetchResults(true) and keep looking until you find the actual problem. fetchResults can be called right after simulate as long as that first parameter remains true. I suppose it's also possible to "hack" some speed by making that dt > 1/30 (or even better call twice those functions), did you try the direct approach?
Edited by fanwars

Share this post


Link to post
Share on other sites
Kaptein    2224

dt always means delta-time, which is the time spent last frame

so, each time you accumulated more than mStepSize time, you integrate (or simulate if you will)

 

it's hard to say why your scene is slow, since if you provided real time to the function, it would just integrate each and every time forever

you are missing a while loop though

 

while (mAccumulator >= mStepSize)
{
    mAccumulator -= mStepSize;
    mScene->simulate(mStepSize);

}

 

throw that boolean return value to the fishes

 

anyways, the fix might just be to reduce mStepSize and all will be well

Edited by Kaptein

Share this post


Link to post
Share on other sites
N01    194

 

I guess the ultimate point of these snippets is to keep the physics timestep fixed while graphics run at higher fps interpolating frame results. There are obviously
better solutions than this piece of code and those will be more relevant at later development stages... Since your graphics run at constant 30fps, you could perhaps replace that code with just simulate(1.0f/30.0f) and fetchResults(true) and keep looking until you find the actual problem. fetchResults can be called right after simulate as long as that first parameter remains true. I suppose it's also possible to "hack" some speed by making that dt > 1/30 (or even better call twice those functions), did you try the direct approach?

 

 

well, actually, my graphics run at 60 FPS in a separate thread, and logics\physics are at 30 FPS. yes, i've tried simplifying time-step function to just "simulate(1.0f/30.0f) and fetchResults(true)", it didn't make any difference. as i already said, making dt bigger, doesn't really matter. i also tried calling functions multiple times. yes, it does speed things up. in order to get something resembling normal speed, i need to call them 3-4 times.  it works, but it doesn't seem like a proper solution. and it's probably expensive as hell.

 

dt always means delta-time, which is the time spent last frame

so, each time you accumulated more than mStepSize time, you integrate (or simulate if you will)

 

it's hard to say why your scene is slow, since if you provided real time to the function, it would just integrate each and every time forever

you are missing a while loop though

 

while (mAccumulator >= mStepSize)
{
    mAccumulator -= mStepSize;
    mScene->simulate(mStepSize);

}

 

throw that boolean return value to the fishes

 

anyways, the fix might just be to reduce mStepSize and all will be well

 

yep, i knew what dt means, that's why in my code(post #6) it's deltaTime. but i have no idea, how it is calculated properly, to fit timestep.

i've added a while cycle, removing "if" statement. so it looks like that:

void update() {
        float deltaTime = (clock() - mLastTime) * mStepSize;
        mAccumulator  += deltaTime;
        mLastTime = clock();

        while(mAccumulator > mStepSize) {
            mAccumulator -= mStepSize;
            mScene->simulate(mStepSize);
            mScene->fetchResults(true);
        }
}

i moved mLastTime = clock(); before simulation, and now it's super fast(5x speed. speed is normal, if i multiply deltaTime by 0.2f). i can just multiply deltaTime, but i'd like to figure out the reason.

and if i use fetchResults(false), speed is normal.  but calling it with a false argument seems a bit undetermined.

 

*changed last bit of post a lot.

Edited by N01

Share this post


Link to post
Share on other sites
adt7    751
The clock() function gives you the ticks elapsed since the program was launch. PhysX expects its delta times in seconds. Try dividing your clock values by CLOCKS_PER_SEC and working in seconds rather than ticks. Edited by adt7

Share this post


Link to post
Share on other sites
N01    194

ok, CLOCKS_PER_SEC is just 1000 for visual studio, i already tried dividing it by 1000.

if deltaTime = (clock() - mLastTime)/CLOCKS_PER_SEC, it's slow-mo. about 1/4 to 1/5 speed. so it still requires multiplying with magic number.

 

if i additionally multiply it with stepSize, it's super slow-mo. about 1fps.

Share this post


Link to post
Share on other sites
MrRowl    2490

Physx...you might find yourself in trouble....there are not many(almost none) tutorials,or documentations for it

 

I don't quite understand what you mean - in my opinion/experience the documentation is extremely accurate, clear and complete. And the SDK comes with a bunch of samples, as well as tutorial/guides in the documentation. I'm not sure how anyone could ask for more, to be honest.

 

As for solving this problem - I'd recommend using the PhysX Visual Debugger - it's extremely useful generally, and only takes a couple of lines to set up the communication in your code. Then when you simulate, you can inspect pretty much everything, including the scene timestep, gravity, objects etc. If you're unsure whether things are moving as they should, set up a little test scenario in your game where you drop a sphere, and in the debugger check that it falls the correct distance in a given time period - distance = vel * time + 0.5 * gravity * time^2 

 

If you can't figure things out from that, you could even attach the pvd capture to a post here...

Share this post


Link to post
Share on other sites
N01    194
I don't quite understand what you mean - in my opinion/experience the documentation is extremely accurate, clear and complete. And the SDK comes with a bunch of samples, as well as tutorial/guides in the documentation. I'm not sure how anyone could ask for more, to be honest.

 

As for solving this problem - I'd recommend using the PhysX Visual Debugger - it's extremely useful generally, and only takes a couple of lines to set up the communication in your code. Then when you simulate, you can inspect pretty much everything, including the scene timestep, gravity, objects etc. If you're unsure whether things are moving as they should, set up a little test scenario in your game where you drop a sphere, and in the debugger check that it falls the correct distance in a given time period - distance = vel * time + 0.5 * gravity * time^2 

 

If you can't figure things out from that, you could even attach the pvd capture to a post here...

 

 

literally 1st post mentions i'm using PVD. and later i mention that objects in PVD output look fine, parameters are intact. bearing that in mind, how do you think can it lead me to an explanation of the fact that i need to pre-multiply delta-time by some factor to get rid of slow-mo? if you didn't bother to read at least most of the thread and last OP's post, then why do you reply?

 

it works, so i moved on to other things, but i'm still a bit bothered on where does this speed factor comes from.

 

[spoiler]and on documentation\samples quality....

in post #10 there's a snippet from documentation, for time-stepping. it's doesn't function correctly, at least in a normal application with a basic setup. it's taken out of context of their samples framework. and there's no explanation on how it supposed to work. doc only does general time-stepping explanation, but you need to know exactly what API expects you to do.

 

and when it comes to convex hull creation, it uses PxToolkit::MemoryOutputStream and PxToolkit::MemoryInputData. does it explain, wtf are those and wtf is PxToolkit? no. do you need to use them? no. you can use PxDefaultMemoryOutputStream and PxDefaultMemoryInputData. how do you supposed to know that? you supposed to guess, that there are classes, that do exactly the same thing in the library itself and not to link to that useless PxTollkit library exclusively for those two, despite documentation shows you example of doing that.

 

also, searching through documentation by "gpuDispatcher" i failed to find, where exactly it explains, how do you check, if GPU acceleration is available. it does show some intialization routine in a Scene initialization example, but it doesn't explain it. then it does it again in Particles and states as a sufficient initialization code. so i guess, you need to assume that if cudaContextManager is not NULL, you have it running?

 

that's my problem with this documentation. it's a bit non-deterministic and scattered. that's just problems i came up from the top of my head, from my experience. it's not really bad, but it's not well-written, you can't just highlight the stuff you need, because information is really scattered and it has some bugs. it doesn't cover it all. no one would complain if it was complemented with decent samples, but...

 

when you suggest PhysX SDK samples as a source of information, i start to question your sanity. take a look at their hello world. what do you expect to see? i don't know, maybe basic initialization, creation of a basic rigid body and a plane and timestep, proper shutdown. this all could fit into a single, very small and clean cpp file. instead of that, they implemented really poorly written cross-platform framework only for samples, so none of the samples source files contatins anything useful or anything you would expect to see. it's all scattered through a pile of include files, within a confusing mess of classes and functions. most of the time it is really problematic to navigate from a sample code through this framework to find the actual code that is executed and you need to do it constantly, while trying to keep a picture of all that in your head, reconstructing how sample would look, if it wasn't written by lunatic.[/spoiler]

Share this post


Link to post
Share on other sites
MrRowl    2490


literally 1st post mentions i'm using PVD. and later i mention that objects in PVD output look fine, parameters are intact. bearing that in mind, how do you think can it lead me to an explanation of the fact that i need to pre-multiply delta-time by some factor to get rid of slow-mo? if you didn't bother to read at least most of the thread and last OP's post, then why do you reply?

 

I replied because I thought, and think, that my suggestion should help - rather than vaguely say "it looks like it's in slow motion" - do some basic numerical comparisons of simulation against theory. I can't see any mention of you doing that. PVD is useful for that.

 

I missed one sentence where you mention PVD out of 15 detailed posts. I'd say that's not unreasonable (though I agree it's in the original post!). Still doesn't invalidate my suggestion though.

 

It seems like you code by copy and paste, and if A/B doesn't work you just try B/A instead. That doesn't really work for physics stuff, in my experience.

Share this post


Link to post
Share on other sites
N01    194
I replied because I thought, and think, that my suggestion should help - rather than vaguely say "it looks like it's in slow motion" - do some basic numerical comparisons of simulation against theory. I can't see any mention of you doing that. PVD is useful for that.

 

I missed one sentence where you mention PVD out of 15 detailed posts. I'd say that's not unreasonable (though I agree it's in the original post!). Still doesn't invalidate my suggestion though.

 

It seems like you code by copy and paste, and if A/B doesn't work you just try B/A instead. That doesn't really work for physics stuff, in my experience.

 

i mention PVD twice in my 1st post, 1st time as an item in a list. and then in post 6 i mention again, that i do test with PVD. that's why i assumed, that you didn't read this thread at all.

 

copy paste exactly what? the only thing i copy-pasted(and openly stated that) was time-stepping function from documentation. it was in attempts to find a reason for my original problem with objects falling through stuff, by minimizing deviations from basic documentation code. and i couldn't tweak it in a sensible way, because it lacks any description. as soon as i've got some hints on how it should work from someone, who has more experience with PhysX, i fixed it and cleaned it up. you know something more sensible to do?

other sections of code are also based on documentation code with only necessary alternations. i always do it like that, when i gradually figure out something. i see no point in wrapping it up yet, because i tweak it a lot.

 

about simulation numbers. ok, i spawned a unit sphere with a density of 1 at some height, and using PVD i measured that without any deltaTime scaling(so everything is slow-mo), gravity of -9.8f and stepSize of 1/30 it touched the ground in 2.5 seconds, falling 132 units from starting point. well, it's velocity wasn't constant, but i'm not sure how else can you measure it.

Edited by N01

Share this post


Link to post
Share on other sites
MrRowl    2490


about simulation numbers. ok, i spawned a unit sphere with a density of 1 at some height, and using PVD i measured that without any deltaTime scaling(so everything is slow-mo), gravity of -9.8f and stepSize of 1/30 it touched the ground in 2.5 seconds, falling 132 units from starting point. well, it's velocity wasn't constant, but i'm not sure how else can you measure it.

 

Do you mean that in 2.5 seconds (that is: 2.5 seconds of simulation time), your sphere, starting at rest, has fallen 132m? If so, that's much further than expected - you'd expect 0.5 * 9.81 * 2.5 * 2.5 which is about 30.7m. That would suggest your simulation is running faster than normal... so I'm not sure I've interpreted your numbers right.

 

In post 13 your loop multiplies by mStepSize, which is definitely wrong - but then you correct it in post 15. But it's still not quite clear what your latest version looks like.

 

In any case I'd expect this to work:

void update() {
        clock_t c = clock();
        float deltaTime = (c - mLastTime) / CLOCKS_PER_SEC;
        mAccumulator  += deltaTime;
        mLastTime = c;

        while(mAccumulator > mStepSize) {
            mAccumulator -= mStepSize;
            mScene->simulate(mStepSize);
            mScene->fetchResults(true);
        }
        // Ideally call something like sleepInSeconds(mAccumulator) here
}

I've replaced two calls to clock with one. I wonder - with your current code, assuming your scene is really simple, that update loop may spend a lot of time just spinning round, whilst it waits for the accumulator to accumulate, in which case each time it will lose a little bit of time - maybe that's where your slowdown is coming from?

Share this post


Link to post
Share on other sites
N01    194
Do you mean that in 2.5 seconds (that is: 2.5 seconds of simulation time), your sphere, starting at rest, has fallen 132m? If so, that's much further than expected - you'd expect 0.5 * 9.81 * 2.5 * 2.5 which is about 30.7m. That would suggest your simulation is running faster than normal... so I'm not sure I've interpreted your numbers right.

 

In post 13 your loop multiplies by mStepSize, which is definitely wrong - but then you correct it in post 15. But it's still not quite clear what your latest version looks like.

 

In any case I'd expect this to work:

...

I've replaced two calls to clock with one. I wonder - with your current code, assuming your scene is really simple, that update loop may spend a lot of time just spinning round, whilst it waits for the accumulator to accumulate, in which case each time it will lose a little bit of time - maybe that's where your slowdown is coming from?

 

 

resulting numbers also confused me. to clarify, ~2.5 seconds is 149frames/60 FPS in PVD. according to formula, it should've fallen 30 units in 2.5 seconds. but in my scene it's less, than human height. rigid objects shouldn't fall from that height for 2.5 seconds. even what i consider as "slow mo" runs faster. but you measure it in meters, and i do in units and i'm not sure, how do you convert arbitrary scene into metrical system. ...so i guess, scale somehow matters. and also, even when i multiply deltaTime by 5, so in-game physics are close to speed i expect, PVD's recodred clip is still in slow-mo.

 

 

scene is not super basic, but it's not a full scale level. it's just some part of the level done, with some additional testing objects.

running simulation looks like that in semi-pseudocode:

physicsManager::update() {
   float currentTime = clock();
   float deltaTime = (currentTime - mLastTime)/CLOCKS_PER_SEC;
   mAccumulator  += deltaTime;
   mLastTime = currentTime;

   while(mAccumulator > mStepSize) {
         mAccumulator -= mStepSize;
         mScene->simulate(mStepSize);
         mScene->fetchResults(true);
   }

   //update objects
   ...
}

logicAndProcessingThread {
   //do stuff
   ...
   physicsManager.update();
   Sleep(30 - timeTookProcessing); //running at 30FPS
}

renderingThread() {
   //render stuff
   ...
   Sleep(16 - timeTookRendering); //running at 60 FPS
}
Edited by N01

Share this post


Link to post
Share on other sites
MrRowl    2490

physicsManager::update() {
float currentTime = clock();
   float deltaTime = (currentTime - mLastTime)/CLOCKS_PER_SEC;
   mAccumulator  += deltaTime;
   mLastTime = currentTime;

   while(mAccumulator > mStepSize) {
         mAccumulator -= mStepSize;
         mScene->simulate(mStepSize);
         mScene->fetchResults(true);
   }

}

 

OK - I see you changed this after first posting it to replace two calls to clock with one as I suggested. Can you confirm whether it does/doesn't work now?

 

There's still a potential problem that, according to the above code, you're probably storing your absolute time (mLastTime) as a float, as well as converting it to a float immediately after getting it. When the time gets large - which may not take very long since I expect CLOCKS_PER_SEC is pretty huge, then your deltaTime calculation subtracts two huge floats - and the result will get less and less precise. 

Share this post


Link to post
Share on other sites
N01    194

OK - I see you changed this after first posting it to replace two calls to clock with one as I suggested. Can you confirm whether it does/doesn't work now?

 

There's still a potential problem that, according to the above code, you're probably storing your absolute time (mLastTime) as a float, as well as converting it to a float immediately after getting it. When the time gets large - which may not take very long since I expect CLOCKS_PER_SEC is pretty huge, then your deltaTime calculation subtracts two huge floats - and the result will get less and less precise. 

 

no, it didn't affect the behavior.

 

i also tried making currentTime and lastTime clock_t, and updating the function accordingly:

        clock_t currentTime = clock();
        float deltaTime = (currentTime - mLastTime)/float(CLOCKS_PER_SEC);
        mAccumulator  += deltaTime;
        mLastTime = currentTime;

        while(mAccumulator > mStepSize) {
            mAccumulator -= mStepSize;
            mScene->simulate(mStepSize);
            mScene->fetchResults(true);
        }

it acts exactly the same.

Share this post


Link to post
Share on other sites
MrRowl    2490

clock_t currentTime = clock();
        float deltaTime = (currentTime - mLastTime)/float(CLOCKS_PER_SEC);
        mAccumulator  += deltaTime;
        mLastTime = currentTime;

        while(mAccumulator > mStepSize) {
            mAccumulator -= mStepSize;
            mScene->simulate(mStepSize);
            mScene->fetchResults(true);
        }


OK - well this looks right now.

One quick thing to test is whether your game's accumulation of time is correct. So in your loop you can just print out the total time you've passed to PhysX, and as the game runs, check whether it is counting up in seconds (i.e. compare it with a watch):
 

        while(mAccumulator > mStepSize) {
            mAccumulator -= mStepSize;
            mScene->simulate(mStepSize);
            mScene->fetchResults(true);

            static float physXTime = 0.0f;
            physXTime += mStepSize;
            printf("%f\n", physXTime);
            }

If the time printed out is slow, then you need to check the timing code.

 

If the time printed out is fine, then I'm pretty sure PhysX is doing the right thing - just that you have some scaling problems. I'm still not sure from your posts (including #13) how you're determining that the simulation is running slower than expected. If you're looking at the time it takes for a falling object to move the size of a human sized object - you need to be sure that your "human sized object" is really about 2m big. 

 

Since you set gravity to 9.81 m/s that implies your distance unit is metres, and your time unit is seconds. if not - then you need to use a different gravity value.

 

Feel free to upload a pvd capture and I'll take a look...

 

 

Share this post


Link to post
Share on other sites
adt7    751
 
logicAndProcessingThread {
   //do stuff
   ...
   physicsManager.update();
   Sleep(30 - timeTookProcessing); //running at 30FPS
}

renderingThread() {
   //render stuff
   ...
   Sleep(16 - timeTookRendering); //running at 60 FPS
}

Wait, is that actually representative of your actual code? Those calls to sleep (especially in the physics thread) will not be doing you any good.

The accumulation loop you posted is design to run as quickly as possible (i.e. in a while(true) style loop) and fire the Physics events at the correct time. With the setup you have now the simulation will not be being called at the correct frequency due to differences in sleep time and the fact that your time deltas are going to be huge.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this