Search Unity

Kill all right velocity

Discussion in 'Physics' started by MathewHI, Mar 18, 2019.

  1. MathewHI

    MathewHI

    Joined:
    Mar 29, 2016
    Posts:
    501
    Is there a way to kill all right velocity with forces without setting the velocity manually? I can do it by setting the velocity directly but it affects the simulation as Unity states in the manual. I tried to do it with forces but its not working, I thought this should work:

    float lateralAcceleration = RightVelocity().magnitude;

    Vector3 lateralDownforce = RightVelocity().normalized * lateralAcceleration;

    rb.AddForce(-lateralDownforce);


    // function to return right velocity only.
    Vector3 RightVelocity()
    {

    return transform.right * Vector3.Dot(rb.velocity, transform.right);

    }
     
  2. MathewHI

    MathewHI

    Joined:
    Mar 29, 2016
    Posts:
    501
    Actually I did a little more research and discovered how velocity is added. I think if the addForce line is changed to this:

    rb.AddForce(-lateralDownforce * RightVelocity().magnitude * (50 * rb.mass));

    that seems to be working.
    If anyone knows for sure can you confirm that this is a correct way of doing it? I would appreciate it.
     
  3. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
  4. sebj

    sebj

    Joined:
    Dec 4, 2013
    Posts:
    70
    AddForce has a mode flag that allows you to apply delta-v directly:

    Code (CSharp):
    1. rb.AddForce(-Vector3.Dot(rb.velocity,rb.transform.right), ForceMode.VelocityChange)
    In theory this way you don't need to know anything like the mass, integration method, etc.

    However, I have found even the call:

    Code (CSharp):
    1. rb.AddForce(-rb.velocity, ForceMode.VelocityChange)
    Does not actually *completely* cancel the velocity*. I don't know why (perhaps its adding the drag to it before applying or something?) but I'll post back if I figure it out.

    *as a minimal working example, create a plane with a slight incline, put a cube on it, give a physics material with no friction, then make a script that applys the above and watch the cube slide ever so slowly down the plane...
     
  5. MathewHI

    MathewHI

    Joined:
    Mar 29, 2016
    Posts:
    501
    I was able to kill my right velocity but I tried your code just to see if I could condense it to one line and I'm getting an error
    cannot convert from float to UnityEngine.Vector3
     
  6. MathewHI

    MathewHI

    Joined:
    Mar 29, 2016
    Posts:
    501
    oh there should be a transform.right * in front of the dot product. Thanks for the help.
     
  7. sebj

    sebj

    Joined:
    Dec 4, 2013
    Posts:
    70
    You're welcome!

    I thought about this some more and identified where the error comes from as well. The rb.Velocity member describes the velocity as a result of the position change over the last frame (not the velocity for the current frame being simulated), so, if the next frame is

    x+1 = x + vdt + adt*dt

    cancelling the velocity will make v zero, but won't affect any accelerations incurred during the frame... such as the acceleration due to gravity.

    So, in addition to cancelling velocity, its necessary to counteract any forces in the direction of interest.

    PhysX does not provide an api to get these for any particular rigid body, so you need to estimate them yourself from what you know about the scene.

    In my code, I cancel the velocity as above, and in addition cancel gravity:

    Code (CSharp):
    1.        
    2. var g_acceleration = Vector3.Dot(Physics.gravity, right) * right;
    3. var g_force = g_acceleration * (rigidBody.mass / wheelsInContact);
    4. rigidBody.AddForce(-g_force, ForceMode.Force);
    5.  
    Obviously with appropriate limits to avoid, e.g. a car climbing a vertical face or something!
     
    MathewHI and SparrowGS like this.
  8. MathewHI

    MathewHI

    Joined:
    Mar 29, 2016
    Posts:
    501
    You must be making a racing game too.
     
  9. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    Just me wondering, why do you wanna do it with forces?

    you could also get the velocity as a local vector, make x = 0 and convert it back to world space and assign it back.

    Code (CSharp):
    1. Vector3 vel = transform.InverseTransformVector(rb.velocity);
    2. vel.x = 0.0f;
    3. rb.velocity = transform.TransformVector(vel);
    *untested.
     
  10. MathewHI

    MathewHI

    Joined:
    Mar 29, 2016
    Posts:
    501
    That's exactly what I did. It works but it effects the simulation somehow as Unity states, mainly from what I can tell is the gravity. I found a way to "not mess with gravity" but I can tell it still is not the same when I mess with the velocity directly. For example when my car goes airborne it might float for a while and spin and then come back down. If I just use forces it appears as if gravity is fully simulated as intended.