private List <Dictionary <int, ParticleInteraction> > GenerateParticleInteractions(int particleTypeCount) { var result = new List <Dictionary <int, ParticleInteraction> >(); var particleLifeConfig = (ParticleLifeConfig)spaceConfig; for (int i = 0; i < particleTypeCount; i++) // Loop every particle type { var interactions = new Dictionary <int, ParticleInteraction>(); for (int j = 0; j < particleTypeCount; j++) // For every particle type, it has interaction with every other particle. { var interaction = new ParticleInteraction() { GraphDots = new List <Vector2>() }; for (int k = 0; k < particleLifeConfig.MinimumParticleInteractions.Count; k++) // Generate all graph dots... { var xVal = RNG.RandomFloat(particleLifeConfig.MinimumParticleInteractionDistances[k], particleLifeConfig.MaximumParticleInteractionDistances[k]); var yVal = RNG.RandomFloat(particleLifeConfig.MinimumParticleInteractions[k], particleLifeConfig.MaximumParticleInteractions[k]); interaction.GraphDots.Add(new Vector2(xVal, yVal)); } interactions.Add(j, interaction); // Add to interactions } result.Add(interactions); } return(result); }
// UPDATE STEPS void SatisfyConstraints() { // Using a reverse loop allows us to safely remove constraints from the list for (int interactionIndex = particleInteractions.Count - 1; interactionIndex >= 0; interactionIndex--) { ParticleInteraction interaction = particleInteractions[interactionIndex]; // Only satisfy constraints for enabled interactions if (!simulationManager.GetSpringForce(interaction.interactionType).enabled) { continue; } // If tearing, check how far apart the particles are and maybe remove them from the list if (constants.enableTearing) { float magnitude = (particles[interaction.particle1].Position - particles[interaction.particle2].Position).magnitude; if (magnitude > interaction.equilibriumDistance * constants.maxTearingRatio) { particleInteractions.RemoveAt(interactionIndex); // Don't satisfy this constraint, since they it's broken now continue; } } SatisfyConstraint(interaction); } }
// UPDATE STEPS void AddInternalForces() { for (int interactionIndex = particleInteractions.Count - 1; interactionIndex >= 0; interactionIndex--) { // Using a reverse loop allows us to safely remove items from the indices list ParticleInteraction interaction = particleInteractions[interactionIndex]; SpringForceSettings springForceOfInteraction = simulationManager.GetSpringForce(interaction.interactionType); if (springForceOfInteraction.enabled) { EulerParticle particle1 = particles[interaction.particle1]; EulerParticle particle2 = particles[interaction.particle2]; Vector3 direction = particle1.Position - particle2.Position; float magnitude = direction.magnitude; // Cloth ripping if (constants.enableTearing && magnitude > interaction.equilibriumDistance * constants.maxTearingRatio) { // Break the connection (we could do the same for the reverse one). No force added. particleInteractions.RemoveAt(interactionIndex); continue; } Vector3 force = direction / magnitude * (interaction.equilibriumDistance - magnitude) * springForceOfInteraction.forceConstant; Vector3 dampingForce = (particles[interaction.particle2].velocity - particles[interaction.particle1].velocity) * constants.springDampingConstant; particle1.AddForce(force + dampingForce); } } }
public void TestInterpolation() { var left = new Vector2(1, 2); var right = new Vector2(4, 7); var searchPoint = 3.0f; var interaction = new ParticleInteraction(); interaction.GraphDots = new List <Vector2>(); interaction.GraphDots.Add(left); interaction.GraphDots.Add(right); Assert.AreEqual(interaction.GetInteraction(searchPoint), (left.Y + ((searchPoint - left.X) / (right.X - left.X)) * (right.Y - left.Y)) ); }
// CONSTRAINTS void SatisfyConstraint(ParticleInteraction interaction) { VerletParticle particle1 = particles[interaction.particle1]; VerletParticle particle2 = particles[interaction.particle2]; // Correction vector from particle1 -> particle2 Vector3 directionVector = particle2.Position - particle1.Position; Vector3 correctionVector = (1 - interaction.equilibriumDistance / directionVector.magnitude) * directionVector; // Apply half the correction to each particle (unless one is fixed) if (!particle1.isFixed && !particle2.isFixed) { particle1.Position += correctionVector / 2; particle2.Position -= correctionVector / 2; } else if (particle1.isFixed && !particle2.isFixed) { particle2.Position -= correctionVector; } else if (!particle1.isFixed && particle2.isFixed) { particle1.Position += correctionVector; } }