Attempt number 2 at getting particles to stick to a collector: apply gravitational pull to the collector. The ideal is simple; the closer a particle gets to the collector, the greater the force of gravity acting on the particle towards that collector. In this case, I used the inverse of the distance squared. This produces an “Ideal” orbital pattern as shown below:

D3DXVECTOR3 Collector::GetIdealOrbitalForce(const D3DXVECTOR3& magVector,

const float& magLength)

{

float grav = 1000.0f;

D3DXVECTOR3 force = magVector * grav;

if(magLength > 1)

{

force /= (magLength * magLength);

}

return force;

}

const float& magLength)

{

float grav = 1000.0f;

D3DXVECTOR3 force = magVector * grav;

if(magLength > 1)

{

force /= (magLength * magLength);

}

return force;

}

This ideal orbital pattern has the obvious problem of not actually attracting the particles into the center, and instead just pulling the particles into an orbit around the collector. To give more realistic physical behavior, we would like to model drag the particle encounters by entering the “atmosphere” of the collector. The thickness of the atmosphere was modeled as the inverse of the distance squared. Tweaking the constants a bit yields the following results:

D3DXVECTOR3 Collector::GetOrbitalDecayForce(const D3DXVECTOR3& magVector,

const float& magLength,

const D3DXVECTOR3& curVelocity,

const D3DXVECTOR3& curPos,

const D3DXVECTOR3& collectorPos,

const float& dt)

{

D3DXVECTOR3 force = GetIdealOrbitalForce(magVector, magLength);

D3DXVECTOR3 newVelocity = curVelocity + force * dt;

if (dt > 0)

{

D3DXVECTOR3 newPos = curPos + newVelocity * dt;

D3DXVECTOR3 magVector2 = collectorPos - newPos;

float magLength2 = D3DXVec3Length(&magVector2);

float damping = 4.0f;

D3DXVECTOR3 decayVelocity = ((magVector2 / magLength2) - (magVector / magLength)) / dt * damping;

if(magLength2 > 1)

{

decayVelocity /= (magLength2 * magLength2);

}

force += decayVelocity/dt;

}

return force;

}

const float& magLength,

const D3DXVECTOR3& curVelocity,

const D3DXVECTOR3& curPos,

const D3DXVECTOR3& collectorPos,

const float& dt)

{

D3DXVECTOR3 force = GetIdealOrbitalForce(magVector, magLength);

D3DXVECTOR3 newVelocity = curVelocity + force * dt;

if (dt > 0)

{

D3DXVECTOR3 newPos = curPos + newVelocity * dt;

D3DXVECTOR3 magVector2 = collectorPos - newPos;

float magLength2 = D3DXVec3Length(&magVector2);

float damping = 4.0f;

D3DXVECTOR3 decayVelocity = ((magVector2 / magLength2) - (magVector / magLength)) / dt * damping;

if(magLength2 > 1)

{

decayVelocity /= (magLength2 * magLength2);

}

force += decayVelocity/dt;

}

return force;

}

Adding this behavior with spring physics we get:

This all adds to make a pretty interesting effect. I hadn’t optimized the code which models the orbital decay, so I was curious to see what the limitations of the particle system were after performing the physics computations. The physics for each particle is computed on the host, with the final position stored in the instance buffer for each cube to be drawn on the GPU. I’m interested to see what kind of speedup is achievable by performing the physics on the GPU, but I’ll save that for another day. For now, I was able to achieve 70 FPS on my GTX260 with 20,000 cubes, each with spring physics and orbital decay. Results speak for themselves:

After writing these physics calculations, I’m beginning to believe that a purely physically based solution to get the kind of flight paths I am interested in does not exist. So, the third iteration of this particle system will use a spline hybrid to guide the particles along a path shaped by the physics calculations, but also guaranteeing the particles will reach their destination within a fixed amount of time. Stay tuned!

© 2017 Halogenica | Stumblr by Eleven Themes

## Leave a Comment