Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

getting impact FORCE, not just velocity?

Discussion in 'Editor & General Support' started by Tom163, May 26, 2009.

  1. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    Is it possible to get the impact force of a collision, instead of just the relative velocity, or do I have to dig up my physics books and do all the calculations myself?

    I figure there must be a way, since Unity already uses force to determine if joints break, but the Collision class only gives me velocity, not force.
     
    tribio likes this.
  2. Lucas Meijer_old

    Lucas Meijer_old

    Joined:
    Apr 5, 2008
    Posts:
    436
    Hey,

    It's hard to help going on this question. Are you talking about explosions as in RigidBody.AddExplosionForce() ? Or something else?

    What is it you're actually trying to do?

    Bye, Lucas
     
  3. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    No, I'm talking about collisions between rigidbodies or rigidbodies and colliders. Aka "player moves into wall", "crate falls on player" or "moving crate crashes into crate standing still".

    The physics already does force calculations, otherwise it could not properly simulate a light crate bouncing into a heavy crate.

    It just seems that information is never disclosed? Definitely not in the collision data.
     
  4. jonas-echterhoff

    jonas-echterhoff

    Unity Technologies

    Joined:
    Aug 18, 2005
    Posts:
    1,666
    As far as my understanding of physics goes, there is no such concept as a collision force, just a collision impulse. That is because force is always applied over an interval of time, whereas a theoretical collision would just be a point of time. The rules you'll find in your physics book (or wikipedia, if you don't have books handy), will probably not deal with forces either, but just give you the resulting velocities for two bodies after a collision.

    If you just want a measurement of how strong the hit was (like, for example for damage calculations), the dot product of collision normal and collision velocity (ie the velocity of the two bodies relative to each other), times the mass of the other collider should give you useful values.
     
  5. magwo

    magwo

    Joined:
    May 20, 2009
    Posts:
    402
  6. zelk

    zelk

    Joined:
    Mar 13, 2009
    Posts:
    246
    Actually, there are other forces involved that exist but cannot be reached, from what I understand. That is, normal forces between the object and the ground.

    In my project, I need to find out the normal force between the tire and the ground, to be able to create a correct tire friction model. However, I have no idea right now how to get it. The physical engine must know this (I guess) to be able to do the math... but it cannot be reached. If the vehicle is standing still or moving on a flat ground, there are no vertical velocity change, BUT, there is definetly a force present that makes sure the vehicle do not fall into the ground.

    Does anybody have other ideas how to get this information or calculate it? I'm a bit stuck for the moment...

    Right now, I am thinking about simulating it by checking how the vehicle body is moving, if the tire is touching the ground and the status of each ConfigurableJoint. But, I would like to get better results that this simulation.

    /Ricky
     
  7. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Unless the physics has to be very accurate (so you can break objects that you run over, say) then good results can usually be achieved with raycasts. If you send a raycast down from a suitable suspension anchor point, you can use it to measure the distance to ground. Assuming the wheel itself is incompressible, you can use this distance to calculate the compression of the spring, and hence the force pushing down on the road. This technique certainly has its limitations, but it generally gives quite an impressive result (this is basically how Unity's wheel colliders work, for example).
     
  8. zelk

    zelk

    Joined:
    Mar 13, 2009
    Posts:
    246
    Yes, the raycast method is reasonable but as you say, not perfect. I would like to be able to drive on unstable bridges etc. but still, it could work good enough for now... but I have created my own model instead of the PhysX Wheel Collider because it is not good enough for more than very simple vehicle games... so the raycast is my last chance.

    I have physical wheels with ConfigurableJoints as suspension... and a physical material totally without friction... so if I turn off my friction model calculations, the vehicle slips around as if on ice in all directions in the landscape. Then, my friction model handles lateral friction and acceleration, breaks etc. Also about to finish up a very flexible drive line (e.g. multiple engines, multiple diffrentials etc.)... that's why a raycast to get the normal forces is a bit booring... when everything else is so physically correct.

    If anybody knows of an even more accurace idea for getting normal forces, please write. :)

    /Ricky
     
  9. rom

    rom

    Joined:
    Jul 2, 2006
    Posts:
    265
    Code (csharp):
    1.  
    2.     public static float KineticEnergy(Rigidbody rb){
    3.         // mass in kg, velocity in meters per second, result is joules
    4.         return 0.5f*rb.mass*Mathf.Pow(rb.velocity.magnitude,2);
    5.     }
    6.  
     
  10. SilentWarrior

    SilentWarrior

    Joined:
    Aug 3, 2010
    Posts:
    107
    Hello, I have almost the same problem as the original poster.

    In my case, I want to get the force generated by a collision so that I can explode the a projectile that hits a surface or another rigidbody, why?

    In my game, projectiles can bounce off the armor of other tanks. So, in order to get a realistic behavior, I would want the projectiles to explode past a fixed threshold of force generated, this is because different tanks have different types of armor, for example, lateral armor can be as simple as a straight block of metal paralel to the Y axis like so :

    <-- means direction of projectile
    O==== means projectile in motion
    and the other ascii is supposed to picture the armor design

    Heavy and Light tanks :
    Plain (will make it bounce off without dissipating force first, full headon impact)
    | <-- O====
    It can also be deflective (make it bounce up, thus dissipating some force and projectile will bounce away from tank) :
    \ <-- O====
    Bit more complex deflective (same effect as before)
    ) <-- O====
    Explosive (will explode on impact with a force applied in the opposite direction thus dissipating and destroying the projectile)
    |::: -<-- O====

    Light armor vehicles like jeeps have a very weak armor, thus, shells can hit them and not blow up, destroying them by simply the force of the impact.


    The force of the impact would be used to calculate if the shell is to bounce or explode on impact and what type of explosion (effect) it would cause.


    PS: I hope i am not mistaken, but, I think the G-force is what I mean by the force generated by an impact. (at least is what they use on TV programs and movies as a unit of messurement)

    PS2: effect is meant to emulate something like this : http://www.youtube.com/watch?v=t459NbF5Vek

    Thanks in advance
    Joao Carlos
     
  11. zelk

    zelk

    Joined:
    Mar 13, 2009
    Posts:
    246
    You should be able to use the velocity of your two colliding objects before and after the collision to calculate this.
     
  12. SilentWarrior

    SilentWarrior

    Joined:
    Aug 3, 2010
    Posts:
    107
    Is there any onBeforeColision? There is a OnCollisionEnter, but that happens once the collision has taken place.

    Also, I am using the impact force like this:
    Code (csharp):
    1.     float impactforce = collision.impactForceSum.x+collision.impactForceSum.y+collision.impactForceSum.z;
    2.         if (explodeOnImpact || impactforce>70 || impactforce<-70/* || collision.transform.name != "Terrain"*/){
    3.             explode (contact.point, rotation);
    4.         }
    But I get very mixed results, such as negative numbers and collisions that visually seem very strong but arent detected as such, and others that are very shallow in angle and are detected as big collisions. I would like a generic impact G-force type value that I could work with (with g-force like approximation i could read information about the actual weapons and get some proper info into the game, ajusting after that until it seems realistic), any ideas?
     
  13. Rapzid

    Rapzid

    Joined:
    Apr 25, 2009
    Posts:
    123
    I would just like to bring attention to this again. This is working as expected for me:

    Code (csharp):
    1. Vector3.Dot(col.contacts[0].normal,col.relativeVelocity) * rigidbody.mass
    I would also like to say that I'm not very impressed this information is unavailable through the physx API. I'm not very impressed with physX at all TBH.
     
    Last edited: Dec 30, 2011
  14. markhula

    markhula

    Joined:
    Sep 3, 2011
    Posts:
    630
    Hi all,

    Yep I have the same issue.
    Rapzid ; your suggestion doesn't work for me; not sure why (sometimes I just get zero)
    I have a hammer you can raise and then 'release' to hit an object; I need to know the 'force' to determine how much damage is applied to the hit object. I could 'cheat' as the hammer is kinematic so as you raise it higher I could (in theory?) increase it's mass.
    Not sure how reliable this would be - don't need realistic but some way of measuring the impact

    cheers
     
  15. Nutella

    Nutella

    Joined:
    Feb 1, 2013
    Posts:
    1
    Hi guys,

    this thread has been placed long ago in 2010 and the thread creator may have already solved in.

    but i'll put my working implementation just in case somebody looks this up.

    void OnCollisionEnter(Collision collision){
    //on collision with something, start a coroutine
    StartCoroutine("OnImpulse");
    }

    IEnumerator OnImpulse(){
    Vector3 initialVelocity,newVelocity;
    //get velocity
    initialVelocity = transform.rigidbody.velocity;

    //wait for new updates, by trial and error, 3 frames seems to get me the correct effect.
    yield return null;
    yield return null;
    yield return null;

    //get new velocity
    newVelocity = transform.rigidbody.velocity;

    //impulse = magnitude of change
    Vector3 result = initialVelocity - newVelocity;

    Debug.Log ("Impulse taken: " + result.magnitude);
    if(result.magnitude > minForceToBreak){
    Destroy(gameObject);
    }

    }

    Let me explain. Impulse force on an object is determined by the instantaneous change in velocity.

    which in this case i have estimated by measuring change in velocity over 3 frames as what i have done. the reason for 3 frames is by trial and error as it seems to net me the best stable result in my case. As sometimes when determined over 1 frame, it kinda misses the computation.

    Good luck and all the best guys!
     
    Mikael-H, Okido and grandtheftaural like this.
  16. grandtheftaural

    grandtheftaural

    Joined:
    Dec 11, 2014
    Posts:
    1
    Hey @Nutella, thanks for posting this script last year! It works well, I've been playing with it quite a bit. If I end up doing any interesting modifications to it, I will post here. Thanks again! Cheers.
     
  17. Delforce

    Delforce

    Joined:
    Jun 3, 2015
    Posts:
    23
    grandtheftaural, you mentioned that you've done interesting modifications to the script. Any chance you can post it as you mention you would?
     
  18. CakeMedia

    CakeMedia

    Joined:
    Sep 26, 2013
    Posts:
    2
    Since no one has answered yet, I'll leave a scrip that gives you the impact force of two colliders:
    Code (CSharp):
    1. Vector3.Magnitude(GetComponent<Rigidbody>.velocity);
    It goes into "OnCollisionEnter", obviously.
     
  19. Nition

    Nition

    Joined:
    Jul 4, 2012
    Posts:
    781
    Er, that just gets the current velocity vector magnitude of the object that's being hit.
     
  20. Astiolo

    Astiolo

    Joined:
    Dec 18, 2014
    Posts:
    27
  21. Nition

    Nition

    Joined:
    Jul 4, 2012
    Posts:
    781
    The previous posts in this thread were made before Collision.impulse existed (it was first exposed in Unity 5.2). Good to know about for people coming to this old thread now though.
     
    TheGameLearner likes this.
  22. SpaceManDan

    SpaceManDan

    Joined:
    Aug 3, 2013
    Posts:
    15
    @Astiolo

    You nailed it man. collision.impulse.
     
  23. TooManySugar

    TooManySugar

    Joined:
    Aug 2, 2015
    Posts:
    864
    This worked perfectly. Its 2016 but using 4.6.9.

    void OnCollisionEnter (Collision collider)
    {


    if ( KineticEnergy (collider.rigidbody) >= breakEnergy){//energia minima para que se rompa

    Debug.Log ("oobject broken");
    }

    If collision energy is greater than break energy then I add kolliders so I can trash street furniture as I runover them with a tank. Thanks!
     
  24. samifruit514

    samifruit514

    Joined:
    Mar 27, 2015
    Posts:
    30
    Collision2D.impulse is not available yet (not even in 5.4 beta) :(

    @Nutella: Your method is interesting but shouldn't we use WaitForFixedUpdate instead of yielding update frames? Im not sure how this could be done...
     
  25. TMPxyz

    TMPxyz

    Joined:
    Jul 20, 2012
    Posts:
    766
    I'm kinda confused by the Collision.impulse here.

    I've made two cubes (A & B) to go against each other, and output the collision.impulse in each one's OnCollisionEnter().

    I suppose A & B would output impulse vector in opposite direction, but they're the same.
     
  26. OculusFan

    OculusFan

    Joined:
    Nov 6, 2014
    Posts:
    3
    I'd like to learn more about Impulse as well. Why are the input vectors the same on both OnCollisionEnters? And I know this is a very beginner question but how do I compare the two Vector3 Impulse results to determine which is greater?

    update:trying to see if the magnitude of the vector is what I need to compare the two.
    update: I guess it is pretty obvious why the impulse would be the same given the first law of Newtonian physics.


    So that makes it hard to say exactly what I want. I want to determine what object hits the other in the way that most impacts its velocity. The idea here is that the "Cube" that hits the other cube the hardest remains in control (by allowing that cube to apply drag) but the other cube slides out of control. I guess that has to do with an earlier reply that suggested using the velocity and the normals but I still haven't figured out how to do that. I wish it was easier to find more info about this.

    update: I guess I should use relativeVelocity? and then multiply by the mass to get an idea of who hits harder if they are both moving directly toward another? I'm not sure how relativeVelocity is defined but I'm basing it on this video.


    update: Nope, it looks like relativeVelocity is the same for both objects as well. Hmm. I'll try something else.

    update: It looks like I want to compare mass times velocity in the rigidbody. Which I guess is momentum? It won't take into account the angle of the collision but I guess for my purpose and skill level it will be good enough.


    update: Well that kind of works but something is off. It looks like the collision occurs some time after the point of impact within the physics engine. I think someone else in this thread was addressing that issue. Hopefully, I can make use of that.

    update: I tried to add an extra trigger around the cube slightly larger than the cube to get the velocity of the cubes before impact, but for some reason that doesn't work.

    update: I tried getting the velocity in FixedUpdate and then I assign that value to another value in OnTriggerEnter. That seems to work. I notice that the value is double. I guess because a collision spreads the velocity into the next object? I'm definitely going to be studying physics on top of everything else I'm learning.
     
    Last edited: Dec 10, 2016
  27. VindictPL

    VindictPL

    Joined:
    Apr 14, 2015
    Posts:
    1
    I had similar problem and after trying all solutions I have found on the internet I discovered that while Collision2D still doesn't have "Impulse" property, as Collision does, ContactPoint2D has normalImpulse property, so to calculate impulse one could do something like this

    Code (CSharp):
    1. void OnCollisionEnter2D(Collision2D c) {
    2. float impulse=0f;
    3.         foreach (ContactPoint2D cp in c.contacts) {
    4.                 impulse += cp.normalImpulse;
    5.         }
    6. }
     
  28. Ultroman

    Ultroman

    Joined:
    Mar 10, 2014
    Posts:
    110
    This is awesome, but I just wanted to chime in and say that we can substitute the .magnitude call (which would save us a squareroot call, since I believe magnitude is only calculated when referenced, but I could be mistaken), by instead doing:
    Code (CSharp):
    1.     public static float KineticEnergy(Rigidbody rb){
    2.         // mass in kg, velocity in meters per second, result is joules
    3.         return 0.5f*rb.mass*rb.velocity.sqrMagnitude;
    4.     }
     
    SparrowGS likes this.
  29. TheAutoGamer

    TheAutoGamer

    Joined:
    Sep 28, 2020
    Posts:
    2
    I am so confused.
     
  30. Only4gamers

    Only4gamers

    Joined:
    Nov 8, 2019
    Posts:
    327
    Can someone please explain how to get Impact force using Collision.impulse?
     
    orjansolli, Vincent454 and Gunz4hire like this.
  31. orjansolli

    orjansolli

    Joined:
    May 3, 2021
    Posts:
    1
    After some experimentation I find the impulse direction extreamly confusing. Sometimes it is positive in a given direction and if you swap places it's negative. It's the same for both collided objects so it can't be relative to the handler of collition. If one of the objects is kinematic, it flips the sign again.
    Also it doesn't seeme to consider friction force either.
    Maybe I could use the impulse magnitude and multiply by the normalized relative velocity?
     
  32. Obj3ct

    Obj3ct

    Joined:
    Nov 13, 2021
    Posts:
    1
    lol I am looking at this post 12 years later
     
    zeimhall, JeanMestti, jukibom and 2 others like this.
  33. EternalMe

    EternalMe

    Joined:
    Sep 12, 2014
    Posts:
    183
  34. JeanMestti

    JeanMestti

    Joined:
    May 15, 2016
    Posts:
    1
    Hi guys, I just wanted to update this thread, in my case I'm using a vehicle to run over zombies, and depending on the
    collision impact, I apply damage to them, using collision.relativeVelocity it will give the first velocity impact on x,y and z
    we multiply the 3 and divide the 3 to get an average ,hitting them fast or slow will return small or high value.

    private void OnCollision(Collision collision)
    {
    Vector3 collisionVelocity = collision.relativeVelocity;
    float force = Mathf.Abs(collisionVelocity.x) + Mathf.Abs(collisionVelocity.y) + Mathf.Abs(collisionVelocity.z) * 3 / 3;
    print(force);
    }

    I hope it helped
     
    Last edited: Oct 7, 2022
  35. Fatom70

    Fatom70

    Joined:
    Mar 29, 2019
    Posts:
    1
    Don't work for me... I need to calculate the speed of a knife for a VR game
     
  36. John_Leorid

    John_Leorid

    Joined:
    Nov 5, 2012
    Posts:
    646
    The code is wrong.
    Code (CSharp):
    1. float force = Mathf.Abs(collisionVelocity.x) + Mathf.Abs(collisionVelocity.y) + Mathf.Abs(collisionVelocity.z) * 3 / 3;
    is the same as

    Code (CSharp):
    1. float force = Mathf.Abs(collisionVelocity.x) + Mathf.Abs(collisionVelocity.y) + (Mathf.Abs(collisionVelocity.z) * 1);
    What you probably wanted is:

    Code (CSharp):
    1. float force = (Mathf.Abs(collisionVelocity.x) + Mathf.Abs(collisionVelocity.y) + Mathf.Abs(collisionVelocity.z)) / 3;
    2.  
    3. // or with nicer formatting:
    4. float force = 0;
    5. force += Mathf.Abs(collisionVelocity.x);
    6. force += Mathf.Abs(collisionVelocity.y);
    7. force += Mathf.Abs(collisionVelocity.z);
    8. force /= 3;
    and that's basically the same as

    Code (CSharp):
    1. force = collisionVelocity.magnitude;
    Not really the same but will also result in high values for high velocities and low values for low velocities.
    Formular for this is
    Mathf.Sqrt(x²+y²+z²)
    so you also have the addition of all values in there. And because they are squared, they are also all positive
    (-1² = 1)
    .
     
  37. Freezy88

    Freezy88

    Joined:
    Apr 12, 2023
    Posts:
    1
    Hey, folks!
    As far there is still no equivalent of "Collision.impulse" for Collision2D, I suggest my solution for 2D projects:
    Code (CSharp):
    1.     private static float GetImpulse(Collision2D collision)
    2.     {
    3.         var impulse = 0f;
    4.         for (int i = collision.contactCount - 1; i >= 0; i--)
    5.         {
    6.             var contact = collision.GetContact(i);
    7.             impulse += new Vector2(contact.normalImpulse, contact.tangentImpulse).magnitude;
    8.         }
    9.         return impulse;
    10.     }