开发者

Verlet Integration is blowing up my physics engine

I'm building a physics engine and i had some sort of "pseudo-verlet" thing going and i wanted to upgrade it to "real" verlet. So i found an article and set to work. After i added what i think is a good approximation, the engine doesn't work anymore. Can someone help me understand what i'm doing wrong?

My main physics body class's update, apply force, and apply impulse systems:

public void Update(float timestepLength)
{
    if (!this._isStatic)
    {
        Vector2 velocity =  Vector2.Subtract(_position, _lastPosition);
        Vector2 nextPos = _position + (_position - _lastPosition) + _acceleration * (timestepLength * timestepLength);
        _lastPosition = _position;
        _position = nextPos;
        _acceleration = Vector2.Zero;
    }
}

public void ApplyForce(Vector2 accelerationValue)
{
    if (!this._isStatic)
        _acceleration +=开发者_运维百科 (accelerationValue) * _mass;
}
public void ApplyImpulse(Vector2 impulse)
{
    if (!this._isStatic)
        _acceleration +=-1 * impulse;
}

Edit: I've fixed it and it works like a charm, but i have two questions about the following code:

  • Is the impulse application code correct, and if not what should it be?
  • How do i change the position property so that setting it preserves the current velocity of the body?

Here is the code:

public Vector2 Position
{
    get { return _position; }
    set { _position = value;}
}
public void Update(float timestepLength)
{
    if (!this._isStatic)
    {
        Vector2 velocity =  Vector2.Subtract(_position, _lastPosition);
        Vector2 velocityChange = Vector2.Subtract(velocity, Vector2.Subtract(_lastPosition, _twoStepsAgoPosition));
        Vector2 nextPos = _position + (_position - _lastPosition) + _acceleration * (timestepLength * timestepLength);
        _twoStepsAgoPosition = _lastPosition;
        _lastPosition = _position;
        _position = nextPos;
        _acceleration = Vector2.Multiply(velocityChange, timestepLength);
    }
}

public void ApplyForce(Vector2 force)
{
    if (!this._isStatic)
        _lastPosition -= force;
}
public void ApplyImpulse(Vector2 impulse)
{
    if (!this._isStatic)
        _acceleration +=-1 * impulse;
}


as a reference to others... the verlet paper you are probably refering to is this: advanced character physics made by the team who created hitman and was one of the first to have ragdoll based physics

anyhow... the original code they used was:

 void ParticleSystem::Verlet() {
       for(int i=0; i<NUM_PARTICLES; i++) {
             Vector3& x = m_x[i];
             Vector3 temp = x;
             Vector3& oldx = m_oldx[i];
             Vector3& a = m_a[i];
             x += x-oldx+a*fTimeStep*fTimeStep;
             oldx = temp;
       }
 }

and you are right that your code does a similar thing.

The one thing which always blew up my simulations was the use of a too big timestep. Also, with this verlet integration, make sure that the timestep you use is constant throughout the game. (e.g 30 frames/sec for instance (so timestep is 1/30)) and doesn't fluctuate. If it does you should use the time corrected verlet integration which accounts for this

EDIT:

answer to question2: to move your position (without changing velocity/acceleration) just update the position to the new position, and then as an extra step add the delta of this movment(so newPosition-oldPosition) to the oldposs, so this gets updated accordingly.

answer to question1: Impulse is the force applied to an object over a period of time. So your solution is not correct. The impulse would be that over X timesteps(or frames), you call your applyForce function with a fixed force.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜