Hello
I've taken it upon myself to finally start learning how game engines work by making a toy engine myself. I've never done any game programming or anything like that but as an avid gamer and someone with a physics degree I've always wondered how these things are done.
Today I implemented a basic spring force using Hooks Law. I was surprised however when over a short time span, maybe 30s, my default integrator of Velocity Verlet caused the spring's motion to escalate wildly. I tried stepping down to Symplectic Euler and the motion became normal. At first I was thinking there might be a bug in my code, but I can't see one so now I'm wondering if the good people of this forum might help shed some light on this. It does not make any sense to me that Symplectic Euler would be a better integrator than Velocity Verlet. Both are time reversible and symplectic, but Velocity Verlet is second order accurate.
I've been writing up what I learn on a little blog, feel free to check it out to see my current understanding of these methods
Symplectic Euler
Velocity Verlet
Code
Symplectic Euler
void SymplecticEuler::Solve(
const NetForceAccumulator& net_force_accumulator,
const std::vector<std::shared_ptr<PhysicsEntity>> &entity_ptrs,
const std::shared_ptr<PhysicsEntity> entity_ptr)
{
Vector3Gf xi = entity_ptr->GetPosition();
Vector3Gf vi = entity_ptr->GetVelocity();
GLfloat mass = entity_ptr->GetMass();
Vector3Gf F;
F.setZero();
net_force_accumulator.ComputeNetForce(entity_ptrs,entity_ptr,F);
Vector3Gf vf = vi + m_dt*(1/mass)*F;
Vector3Gf xf = xi + m_dt*vf;
entity_ptr->SetNextPosition(xf);
entity_ptr->SetNextVelocity(vf);
};
Velocity Verlet
void Verlet::Solve(
const NetForceAccumulator& net_force_accumulator,
const std::vector<std::shared_ptr<PhysicsEntity>> &entity_ptrs,
const std::shared_ptr<PhysicsEntity> entity_ptr)
{
Vector3Gf xi = entity_ptr->GetPosition();
Vector3Gf vi = entity_ptr->GetVelocity();
GLfloat mass = entity_ptr->GetMass();
Vector3Gf Fi,Ff,ai,xf,af,vf;
Fi.setZero();
net_force_accumulator.ComputeNetForce(entity_ptrs,entity_ptr,Fi);
ai = (1/mass)*Fi;
xf = xi + m_dt*vi + 0.5f*m_dt*m_dt*ai;
entity_ptr->SetPosition(xf); // Load xf into position slot for computing F(x(t+h))
Ff.setZero();
net_force_accumulator.ComputeNetForce(entity_ptrs,entity_ptr,Ff); // Compute F(x(t+h))
af = (1/mass)*Ff;
vf = vi + 0.5f*m_dt*(ai + af);
entity_ptr->SetPosition(xi); // Load xi back into position slot as to not affect force calulations for other entities
entity_ptr->SetNextPosition(xf);
entity_ptr->SetNextVelocity(vf);
};
Spring force
void SpringForceGenerator::AccumulateForce(
const GLfloat k,
const GLfloat l0,
const std::shared_ptr<PhysicsEntity> entity1_ptr,
const std::shared_ptr<PhysicsEntity> entity2_ptr,
Vector3Gf &F) const
{
Vector3Gf x1 = entity1_ptr->GetPosition();
Vector3Gf x2 = entity2_ptr->GetPosition();
Vector3Gf n = x2 - x1;
GLfloat l = n.norm();
n = n/l;
F += k*(l - l0)*n;
}
Thanks!
↧