Week 10 – Fabrik by Dachi

Sketch: p5.js Web Editor | Fabrik

Inspiration

The development of this fabric simulation was mainly influenced by the two provided topics outlined in Daniel Shiffman’s “The Nature of Code.” Cloth simulations represent a perfect convergence of multiple physics concepts, making them an ideal platform for exploring forces, constraints, and collision dynamics. What makes cloth particularly fascinating is its ability to demonstrate complex emergent behavior through the interaction of simple forces. While many physics simulations deal with discrete objects, cloth presents the unique challenge of simulating a continuous, flexible surface that must respond naturally to both external forces and its own internal constraints. This complexity makes cloth simulation a particularly challenging and rewarding subject in game development, as it requires careful consideration of both physical accuracy and computational efficiency.

Development Process

The development of this simulation followed an iterative approach, building complexity gradually to ensure stability at each stage. The foundation began with a simple grid of particles connected by spring constraints, establishing the basic structure of the cloth. This was followed by the implementation of mouse interactions, allowing users to grab and manipulate the cloth directly. The addition of a rock object introduced collision dynamics, creating opportunities for more complex interactions. Throughout development, considerable time was spent fine-tuning the physical properties – adjusting stiffness, damping, and grab radius parameters until the cloth behaved naturally. Performance optimization was a constant consideration, leading to the implementation of particle limiting systems during grab interactions. The final stage involved adding velocity-based interactions to create more dynamic and realistic behavior when throwing or quickly manipulating the cloth.

How It Works

At its core, the simulation operates on a particle system where each point in the cloth is connected to its neighbors through spring constraints. The cloth grabbing mechanism works by detecting particles within a specified radius of the mouse position and creating dynamic constraints between these points and the mouse location. These constraints maintain the relative positions of grabbed particles, allowing the cloth to deform naturally when pulled. A separate interaction mode for the rock object is activated by holding the ‘R’ key, creating a single stiff constraint for precise control, with velocity applied upon release to enable throwing mechanics. The physics simulation uses a constraint-based approach for stable cloth behavior, with distance-based stiffness calculations providing natural-feeling grab mechanics and appropriate velocity transfer for realistic momentum.

Code I am proud of

The particle grabbing system stands out as the most sophisticated portion of the codebase. It is sorting particles based on their distance from the mouse and applying distance-based stiffness calculations. Here’s the core implementation:
// Array to store particles within grab radius
let grabbableParticles = [];

// Scan all cloth particles
for (let i = 0; i < cloth.cols; i++) {
    for (let j = 0; j < cloth.rows; j++) {
        let particle = cloth.particles[i][j];
        if (!particle.isStatic) {  // Skip fixed particles
            // Calculate distance from mouse to particle
            let d = dist(mouseX, mouseY, particle.position.x, particle.position.y);
            if (d < DRAG_CONFIG.GRAB_RADIUS) {
                // Store particle info if within grab radius
                grabbableParticles.push({
                    particle: particle,
                    distance: d,
                    offset: {
                        // Store initial offset from mouse to maintain relative positions
                        x: particle.position.x - mouseX,
                        y: particle.position.y - mouseY
                    }
                });
            }
        }
    }
}

// Sort particles by distance to mouse (closest first)
grabbableParticles.sort((a, b) => a.distance - b.distance);
// Limit number of grabbed particles
grabbableParticles = grabbableParticles.slice(0, DRAG_CONFIG.MAX_GRAB_POINTS);

// Only proceed if we have enough particles for natural grab
if (grabbableParticles.length >= DRAG_CONFIG.MIN_POINTS) {
    grabbableParticles.forEach(({particle, distance, offset}) => {
        // Calculate stiffness based on distance (closer = stiffer)
        let constraintStiffness = DRAG_CONFIG.STIFFNESS * (1 - distance / DRAG_CONFIG.GRAB_RADIUS);
        
        // Create constraint between mouse and particle
        let constraint = Constraint.create({
            pointA: { x: mouseX, y: mouseY },  // Anchor at mouse position
            bodyB: particle,                   // Connect to particle
            stiffness: constraintStiffness,    // Distance-based stiffness
            damping: DRAG_CONFIG.DAMPING,      // Reduce oscillation
            length: distance * 0.5             // Allow some slack based on distance
        });
        
        // Store constraint and particle info
        mouseConstraints.push(constraint);
        draggedParticles.add(particle);
        initialGrabOffsets.set(particle.id, offset);
        Composite.add(engine.world, constraint);
        
        // Stop particle's current motion
        Body.setVelocity(particle, { x: 0, y: 0 });
    });
}

This system maintains a minimum number of grab points to ensure stable behavior while limiting the maximum to prevent performance issues. The stiffness of each constraint is calculated based on the particle’s distance from the grab point, creating a more realistic deformation pattern where closer particles are more strongly influenced by the mouse movement.

Challenges

While performance optimization was addressed through careful limiting of active constraints, the primary challenge was in achieving authentic cloth behavior. Real fabric exhibits complex properties that proved difficult to replicate – it stretches but maintains its shape, folds naturally along stress lines, and responds to forces with varying degrees of resistance depending on the direction of the force. The initial implementation used uniform spring constants throughout the cloth, resulting in a rubber-like behavior that felt artificial and bouncy. Achieving natural draping behavior required extensive experimentation with different constraint configurations, ultimately leading to a system where horizontal and vertical constraints had different properties than diagonal ones. The way cloth bunches and folds was another significant challenge – early versions would either stretch indefinitely or resist folding altogether. This was solved by implementing a constraint lengths and stiffness values, allowing the cloth to maintain its overall structure while still being able to fold naturally. The grab mechanics also required considerable refinement to feel natural – initial versions would either grab too rigidly, causing the cloth to behave like a solid sheet, or too loosely, resulting in unrealistic stretching like a pointy tear. The solution involved implementing distance-based stiffness calculations and maintaining relative positions between grabbed particles, creating more natural deformation patterns during interaction.

Reflection and Future Considerations

The current implementation successfully demonstrates complex physics interactions in an accessible and intuitive way, but there remain numerous opportunities for enhancement. Future development could incorporate air resistance for more realistic cloth movement, along with self-collision detection to enable proper folding behavior. The addition of tear mechanics would introduce another layer of physical simulation, allowing the cloth to react more realistically to extreme forces. From a performance perspective, implementing spatial partitioning for collision detection and utilizing Web Workers for physics calculations could significantly improve efficiency, especially when dealing with larger cloth sizes. The interactive aspects could be expanded by implementing multiple cloth layers, cutting mechanics, and advanced texture mapping and shading systems. There’s also significant potential for educational applications, such as adding visualizations of forces and constraints, creating interactive tutorials about physics concepts, and implementing different material properties for comparison. Additionally, there is no depth to current implementation because this is inherently a 2D library. For depth-based clashing (which is what happens in real world) we would need to find 3D library.
These enhancements would further strengthen the project’s value as both a technical demonstration and an educational tool, illustrating how complex physical behaviors can be effectively simulated through carefully crafted rules and constraints.

Leave a Reply

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