Force applied twice on rigid body

Hi all,

I don’t understand how Unity applies forces. After I had trouble on a project with slight offsets between Unity’s results and mines, I decided to make a simple study case to understand where was the problem comming from. What I found is that on the first FixedUpdate, the AddForce seems to be applied twice, and I don’t understand why.

So, my study case is a ball falling down, with mass 1kg, initial speed 0m.s-1 and only affected by gravity with g = 10m.s-2 (no linear/angular drag)

I compare the balls’transform position with analytic ones obtained with y(t) = -0.5 * gt^2

So, now the results :

1 : When applying on the ball’s rigidBody an addforce of (g * mass) every fixedUpdate frame, I have slightly off results. I notice that there is an exact 2 times difference between the Unity and analytic results. Afterwards, the results tend toward each other, but still carrying the slight offset from the first frame.

public LineRenderer _lineRenderer;
[SerializeField] int nPoints = 10;
[SerializeField] float tIncrement = 0.02f;
[SerializeField] float gravityAcceleration = Vector3.Magnitude(Physics.gravity);
Rigidbody _rb;
float _mass;
bool _startFall = false;
bool _falling = false;
void Start()
{
    _rb = GetComponent<Rigidbody>();
    _mass = _rb.mass;
    _lineRenderer.positionCount = nPoints;
    _lineRenderer.SetPosition(0, Vector3.zero);
    for (int i = 1; i < nPoints; i++)
    {
        _lineRenderer.SetPosition(i, Vector3.down * gravityAcceleration * Mathf.Pow(i * tIncrement, 2) * 0.5f);
    }
}
private void FixedUpdate()
{
    if (Input.GetKeyDown(KeyCode.A))
    {
        _falling = !_falling;
    }
    if (_falling)
    {
        Debug.Log("UnityPos = " + this.transform.position.y);
        _rb.AddForce(gravityAcceleration * _mass * Vector3.down);          
    }
    if (!_falling)
    {
        this.transform.position = Vector3.zero;
        _rb.velocity = Vector3.zero;
    }
}

2 : So, I tried applying an addforce of (g * mass) / 2 the first fixedUpdate frame, and (g * mass) on all other frames, I get perfectly identical results between Unity and analytic

 public LineRenderer _lineRenderer;
    [SerializeField] int nPoints = 10;
    [SerializeField] float tIncrement = 0.02f;
    [SerializeField] float gravityAcceleration = Vector3.Magnitude(Physics.gravity);
    Rigidbody _rb;
    float _mass;
    bool _startFall = false;
    bool _falling = false;
    void Start()
    {
        _rb = GetComponent<Rigidbody>();
        _mass = _rb.mass;
        _lineRenderer.positionCount = nPoints;
        _lineRenderer.SetPosition(0, Vector3.zero);
        for (int i = 1; i < nPoints; i++)
        {
            _lineRenderer.SetPosition(i, Vector3.down * gravityAcceleration * Mathf.Pow(i * tIncrement, 2) * 0.5f);
        }
    }
    private void FixedUpdate()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            //Debug.Log("aaa");
            _falling = !_falling;
            if (_falling) { _startFall = true; }
        }
        if (_falling)
        {
            Debug.Log("UnityPos = " + this.transform.position.y);
            if (_startFall)
            {
                Debug.Log("YYY");// to check how many times the force is applied

                _rb.AddForce(gravityAcceleration * _mass * 0.5f * Vector3.down);// weight force divided by 2
                _startFall = false;
            }
            else
            {
                _rb.AddForce(gravityAcceleration * _mass * Vector3.down);
            }            
        }
        if (!_falling)
        {
            this.transform.position = Vector3.zero;
            _rb.velocity = Vector3.zero;
        }
    }

Does anyone have an idea of why only the first frame is “miscalculated” and/or what I am missing?

Ah and i know that a getkeydown in a fixedUpdate is stupid, but in this case it was to be sure that I only apply force once, without juggling between update to get inputs and fixedupdate to apply the forces. By the way I first tried this way and had the same problem, so it doesn’t come from it.

I suspect what you’re seeing is the inaccuracy of the stepped simulation in Unity. The analytic calculation will perfectly reflect the acceleration curve of the object but Unity’s stepped physics simulation will have a stairway curve, with a step for each frame. These inaccuracies should average out over many frames, which seems to be the case. The analytic result and the simulated position is pretty accurate after e.g. 1s. Maybe the doubling has to do with the timestep being 0.02 but I don’t know how a physics step is calculated exactly in Unity.

btw, instead of doing:

_rb.AddForce(gravityAcceleration * _mass * Vector3.down);

you can just do:

_rb.AddForce(gravityAcceleration * Vector3.down, ForceMode.Acceleration);

In the first case, you multiply by the mass and then the physics engine will divide by the mass later. Using ForceMode.Acceleration prevents this and also removes the dependency on the mass.

Hi, thank you for your reply.

I didn’t know the physics engine actually redivided by the mass, thank you

Regarding my problem, I don’t think the difference is due to the step inaccuracy of Unity’s non continous time calculation. For instance I tried with a fixed time step of 0.5s only to find the same results (force “added” twice first frame, and carrying the offset on the rest of the movement, and working perfectly when dividing the added force by 2 on the first frame only).

Furthermore, based on my experimentations, the slight offset does not come from step approximations as you mentioned. I mean, of course there are differences but I am not talking about that small of a difference. Once more, it is more like an offset from the begining wich is carried on all the rest of the movement. What makes me pretty sure of this is that on parabolic trajectories, the ball is ALWAYS bellow the “perfect” line trace. Not by much, but still noticeable and annoying. For instance, for a ball of 1m diameter, the resulting offset 30m further from the launching point is a deviation of like 0.5m from the “perfect” line, but ALWAYS under it. So it can’t be a problem of step averages as otherwise I would experiment having the ball sometimes above the line, or under but not to the same extent…

So, if anybody has an other explanation, I am eager to hear from it, this problem is driving me nuts. I also read about this topic, similar to mine where the “solution” was also to divide the force by 2 first frame, but I am not a huge fan of it :