Positioning Non-Rigid Objects In A Pool Game Simulation

Simulating Non-Rigid Object Physics

The positioning and motion of non-rigid objects like cloth and fabric in a pool game simulation requires an understanding of the physics of soft body dynamics. Key concepts include implementing numerical integration methods like verlet integration to update particle positions over time, applying mass-spring constraints between particles to mimic natural materials, configuring physical properties like mass, stiffness, and friction, and handling collisions and responses.

Understanding cloth and fabric simulation

Cloth, fabric, and other non-rigid materials can be simulated by representing them as a grid or mesh of discrete particles connected by springs. The springs exert forces on the particles to maintain the shape while allowing stretching, compression, and bending. Factors like mass, damping, stiffness, shear resistance, and bend resistance determine the look and behavior.

Implementing verlet integration

Updating the position of each particle over time is done using numerical time integration. Verlet integration is a common choice as it is straightforward to implement and balances accuracy and efficiency. It uses the current position, previous position, accelerations, and time step to calculate an updated position for the next time step.

Applying constraints between particles

To mimic real materials, constraints are applied between particles, usually in the form of harmonic springs. The springs resist stretching, shearing, and bending forces exerted on the mesh. Mass-spring constraints with properly tuned stiffness and damping parameters are key to avoiding instability and achieving natural dynamics.

Configuring materials and collision properties

Physical parameters like mass, friction, stiffness, tear resistance, and damping coefficients must be carefully tuned on a per-material basis. Together with geometric collision parameters like thickness and collision margins, this controls how the cloth reacts on contact, how much it penetrates objects, and how momentum transfers between colliding items.

Setting up the game environment

Creating the pool table

The foundational element of the simulation is modeling the pool table itself with the correct dimensions, material physics, and collision properties. This may include rigid bodies for the rails and bumpers, and a kinetic friction surface for ball roll and cloth interaction. The table geometry forms the arena for the game physics.

Adding balls and pockets

Game balls are rigid spherical objects defined with metrics like diameter, mass distribution, elasticity coefficients for impacts, and appropriate surface friction. Pockets have opening sizes and dead zone triggers to detect when a ball enters for removal. Balls and pockets have complementary shapes, masses, and collision properties to allow realistic trajectories, impacts, and scoring.

Initializing cue stick strikes

Applying impulse forces

Striking with the cue stick applies an impulse force to the cue ball. An impulse is an instantaneous change in momentum defined by the strike mass, velocity, duration, and direction. Well-tuned impulse parameters allow controlling the applied spin and speed, enabling a range of shots from soft taps to power drives.

Randomizing spin

Adding variability by randomizing the exact impulse parameters for each shot better mimics human unpredictability. Randomness is added by varying direction, offset position, and torque at impact while conforming to ranges seen in real pool shots. This makes each break and shot unique and challenging.

Handling object collisions

Detecting collisions

Efficient collision detection utilizes spatial partitioning, bounding volumes, and optimization structures like BVHs. These accelerate interference and contact point checks between the discrete simulation elements. Collision queries between cloth particles, cloth and rigid bodies, and rigid bodies against each other enable complex multi-object interaction.

Calculating collision responses

Collisions generate response forces that alter momentum and change trajectories. Factors in the calculation include impact velocity, relative mass, elasticity, friction coefficients, surface properties, and current momentum values. Realistic collision responses are key for proper object reactions, from cling, slide, and roll to bounce, scatter, and recoil motions.

Optimizing performance

Using multithreading

Cloth simulation involves many independent calculations per particle which can be accelerated through parallel processing. By dividing cloth particles and constraints across CPU cores via multithreading, position updates, constraint solves, and collision handling achieve near-linear speed improvements.

Simplifying calculations

Performance bottlenecks can be reduced by simplifying expensive math when possible. Adaptive solvers skip constraint iterations when forces are low. Custom SIMD code leverages vector hardware. Approximations use LOD models, reduce particle counts, and disable effects if interactions are minor or distant from the player view.

Example Code Snippets

Verlet cloth integration

for each particle p:
  
  // Update position
  vertex.x += (vertex.x - vertex.previousX) * damping;
  vertex.y += (vertex.y - vertex.previousY) * damping;
  
  // Store previous
  vertex.previousX = vertex.x;
  vertex.previousY = vertex.y;

  // Accelerate with forces
  vertex.x += netForceX * timeStepSquared;
  vertex.y += netForceY * timeStepSquared;

Configuring mass-spring constraints

struct Constraint {
  Particle *particleA;
  Particle *particleB;
  
  float restLength;
  float stiffness;
  float damping;
}

void AddConstraint(Particle *a, Particle *b) {

  Constraint c;
  c.particleA = a;
  c.particleB = b;
  
  c.restLength = Length(a->position, b->position);
  c.stiffness = 100.0f; //Tune this
  c.damping = 0.5f; //And this
  
  constraints.Add(c);
}

Applying impulse forces

void ApplyImpulse(Particle p, Vector3 imp) {

  Vector3 velocityChange = imp / p.mass;
  
  p.velocity += velocityChange;
  
  DoVerletIntegration(p); //Impulse changes particle trajectory 
}

// Striking cue ball applies impulse 
Vector3 impulse = CalculateCueImpulse(); 
ApplyImpulse(cueBall, impulse);

Collision detection and response

void HandleCollisions() {

  for(Particle p1 : particles) {
    for(Particle p2 : particles) {
    
      if(BoundingVolumesIntersect(p1,p2)) {
      
        //Calculate collision depth, normal, etc
        ResolveCollision(p1, p2); //Change velocities
        
      }
      
    }
  }

}

void ResolveCollision(p1, p2) {

  Vector3 relativeVelocity = p1.velocity - p2.velocity;
  Vector3 normal = NormalAtContactPoint();
  
  //Simple particle collision response
  float elasticity = 0.8; //Tune restitution
  
  p1.velocity -= (1 + elasticity) * dot(relativeVelocity, normal) * normal;  
  p2.velocity += (1 + elasticity) * dot(relativeVelocity, normal) * normal;
}

Leave a Reply

Your email address will not be published. Required fields are marked *