NVIDIAGameWorks / PhysX

NVIDIA PhysX SDK
Other
3.11k stars 793 forks source link

How to calculate "damage", or "collision force" #565

Open mlp1802 opened 2 years ago

mlp1802 commented 2 years ago

Is it possible to get information on how much "damage", or force, is applied to each object during a collision? I saw that it's possible to get the "impulse" but I'm not sure if that is the right way to go. The alternative is to roll a homegrown solution, but that seems counter productive as it would seem that the physics engine already can provide this information.

BBBBBbruce commented 2 years ago

Hello, I am using the impulse for my FEM simulation, it works fine for me. For the delta_t I just used the frame rate(say 1/60 seconds)

mlp1802 commented 2 years ago

Hello, I am using the impulse for my FEM simulation, it works fine for me. For the delta_t I just used the frame rate(say 1/60 seconds)

Thanks!

mlp1802 commented 2 years ago

Hello, I am using the impulse for my FEM simulation, it works fine for me. For the delta_t I just used the frame rate(say 1/60 seconds)

Why is delta needed?

BBBBBbruce commented 2 years ago

I dont you what you actually want, but I saw you said force specifically, so I imagine you need impulse = force delta_t. I saw some resources that said PhysX using momentum conservation which is `impulse = m (velocity_after_collision - velocity_before_collision)`. I think if you could define 'damage' in terms of energy, you could ignore the delta_t.

mlp1802 commented 2 years ago

I dont you what you actually want, but I saw you said force specifically, so I imagine you need impulse = force delta_t. I saw some resources that said PhysX using momentum conservation which is `impulse = m (velocity_after_collision - velocity_before_collision)`. I think if you could define 'damage' in terms of energy, you could ignore the delta_t.

If I'm just using impulse as is (I get an array of two impulses), I get some strange result..when things are barely gracing they sometimes produce close to as high numbers as in head on collision.

Just so we're on the same page, I'm using PxContactPair.contactImpulses

BBBBBbruce commented 2 years ago

Would you mind elaborating a bit more? Like what are you expecting and what are you actually having?

Just so we're on the same page, I'm using PxContactPair.contactImpulses

Also, I didn't use PxContactPair.contactImpulses directly, have you checked the example below? It uses PxContactPairPoint. I didn't spend that long time reasoning which is better or why it uses Contactpairpoint, but it works for me. https://github.com/NVIDIAGameWorks/PhysX/blob/c3d5537bdebd6f5cd82fcaf87474b838fe6fd5fa/physx/snippets/snippetcontactmodification/SnippetContactModification.cpp#L209

mlp1802 commented 2 years ago

Would you mind elaborating a bit more? Like what are you expecting and what are you actually having?

Just so we're on the same page, I'm using PxContactPair.contactImpulses

Also, I didn't use PxContactPair.contactImpulses directly, have you checked the example below? It uses PxContactPairPoint. I didn't spend that long time reasoning which is better or why it uses Contactpairpoint, but it works for me.

https://github.com/NVIDIAGameWorks/PhysX/blob/c3d5537bdebd6f5cd82fcaf87474b838fe6fd5fa/physx/snippets/snippetcontactmodification/SnippetContactModification.cpp#L209

I'm making a fighting game, and I have to know how hard the fighters hit each other. Yes I saw that you could get per contact point as well but I'm not sure what the difference is. It might be that contactImpulses are just those summed.

BBBBBbruce commented 2 years ago

I mean like what kind of impulses are you expecting to see? and what are you actually get?

mlp1802 commented 2 years ago

I don't think I did even half of what I see in that example, and I'm not sure I understand it yet. But that should point me in the right direction, thanks!

mlp1802 commented 2 years ago

I mean like what kind of impulses are you expecting to see? and what are you actually get?

I'm expecting low impulses when fighters are just tapping each other, and high for haymakers. There is a difference but it's smaller than I expected.

mlp1802 commented 2 years ago

From what I could read, impulses are not really suited for this..it might appear so because the values are somewhat close to what you'd expect. Well until they are not. Sometimes values are incredible high, or low, for no apparent reason which will break game play. My understanding is that impulses are simply the force that is generated to keep objects apart. That can be used for various effects, but not for the purpose of reading the "collision force". It is a bit strange that PhysX (and no other engine I've worked with) doesn't provide this essential information.

kstorey-nvidia commented 2 years ago

The impulse reported is the impulsive force that was applied by the solver to satisfy the constraint. If a body is resting on the ground being accelerated by gravity, the impulse will be equal and opposing to the gravitational force. Gravity is an acceleration, while the impulse is a direct change in velocity, but you can divide the impulse by dt to convert into an equivalent force over that time-step. The numbers being reported are genuinely what the solver has applied, and those are based on the contact properties and masses/inertias of the colliding bodies.

Are you using fixed or variable time-stepping? Are you getting very large penetration depths from time-to-time? Any of these could lead to quite chaotic results from the simulation because PhysX has to add in biases to correct penetrations. Unusually large penetration depths can cause large impulses to correct these penetrations. Similarly, variable time-stepping can do this as well because there are almost always some penetrations (errors) in the simulation unless you are running a very large number of solver iterations or simulating something trivially simple. The bias used to correct errors is computed based on the penetration and the time-step size, so a penetration of 1cm at a time-step of 1/60 will be corrected with a velocity of 60cm/s, which would be achieved with an acceleration of 36m/s^2. However, a penetration of 1cm at a time-step of 1/240 will be corrected with a velocity that is 4x larger (2.4m/s velocity and an acceleration of 576m/s^2). You can see how variable time-stepping can cause quite noisy force/impulse reporting.

You can work around this with a few options.

(1) You can assign "maxDepenetrationVelocity" to your bodies. This clamps the exit velocities, at the cost of making the penetrations persist for a few frames (overlapping objects slowly move apart instead of instantaneously separate). (2) You can increase solver iteration counts (position iterations and velocity iterations). The net result of this should be that you get fewer penetrations and less energy caused by them. (3) You can enable CCD (either speculative or swept CCD - if you are using jointed bodies, I'd suggest speculative CCD). This will minimize the chances of missed collisions and penetrations (4) You can adjust the maxBiasCoefficient in PxSceneDesc::maxBiasCoefficient. This clamps the coefficient used to compute the bias terms. We use the min of (maxBiasCoefficient, 1/dt) to compute the scaling factor used to convert penetrations into constraint bias terms.

Hope some of these help

Kier

mlp1802 commented 2 years ago

Thanks for your answer, that is a huge help. This functionality is so crucial to my game that I'd almost have to give up without it. I needed confirmation that impulse can indeed be used for calculating the "collision force". I thought it wasn't 100% clear from the documentation. 1) I use articulations, I'm not sure that would make a difference. 2) Reported collision values are 90% of the time in the range of 0-120 or so. Then suddenly I get values in the thousands. 3) The game uses a fixed time step. 4) I've already tried to increase solver iteration count, there was no noticeable difference.

I will try to tweak the other parameters that you mentioned (and report the result back here) and in worst case, I can always limit the damage manually. Thanks again!

mlp1802 commented 2 years ago

After setting "maxDepenetrationVelocity" to 0.01 I have not experienced any excess values. Enabling CCD didn't do anything though. I guess the problem is solved, thank you to everyone who responded.

kstorey-nvidia commented 2 years ago

I'm glad that adjusting maxDepenetrationVelocity helped. However, I'd suggest not going as low as 0.01. I'm assuming this is in metres. Values in the range 1-10m/s seem to work fairly well with 60hz simulations and regular 9.8 gravity. There will always be some unavoidable small errors in the simulation, so permitting the solver to introduce a small amount of velocity to correct errors is important. Limiting the velocity to 0.01 means that the solver can only correct 0.166mm of error per frame. If you have a stack or pile of objects, such a small bias term in the constraint will likely lead to the objects slowly drifting into each other instead of maintaining non-penetration.

mlp1802 commented 2 years ago

I set it to 0.1 instead, since at 0.01 my character would sometimes start sliding through the floor. I'm not sure what PhysX parameters actually means in terms of real world numbers..for example, if I make a sphere and set it to radius 0.5, I don't know what that 0.5 is. My way so far has been to simply try out different values until it looks right.

kstorey-nvidia commented 2 years ago

The units involved are up to you. Some simulations work in SI units (meters, meters/second etc.), some work in cm units and some may choose to work in Imperial units.

There are some parameters that depend on distance and velocity units, which you can either adjust or have PhysX automatically fill in reasonable values by setting up appropriate values in PxTolerancesScale for distance and speed.