CS 184: Computer Graphics and Imaging, Spring 2017

Project 4: Cloth Simulator

Isabel Zhang, CS184-abe



Overview

In this project, I implemented real-time cloth simulation with the ability to detect cloth-primitive collision and cloth self-collision. Cloth modeling is a notoriously difficult problem that researchers today are still working on. This project uses a particle-based model of the cloth where a particle is represented as a PointMass within the cloth. For extra credit, I created different shaders for the cloth as well as implemented wind as a time and spatially varying force.





Part I: Masses and springs

In order to have a cloth simulation, we must figure out a way to represent the cloth. The purpose of this section was to find a way to represent the cloth as a series of PointMasses and Springs.

Each cloth has an input width and height as well as the number of PointMasses needed to represent the cloth, num_width_points x num_height_points. of points. To create the points that represent the cloth, I looped through num_width_points x num_height_points, creating all the necessary points. If the cloth is horizontal (same y value), I set the point's position's y - value to 1.0 so the points all have uniform height. If the cloth is vertical, I set the point's position's z - value to a random offset between 1/1000 and -1/1000. If the point is pinned (meaning the point should not be moved during simulation steps), I set the point's pinned value to true. All other points' pinned values are set to false. All points are added to the cloth's vector of PointMasses.

With the collection of points, we need to connect them together. Connections between points are called springs. There exist 3 types of springs:

I loop through the cloth's points, adding springs when the index conditions are correct (see image below). The newly created springs are each pushed into the springs vector so the cloth is able to reference it for updates when needed.

Spring Diagram for example cloth


Cloth Wireframe

All constraints enabled for cloth with 2 pins

Cloth with 2 pins and all constraints

Cloth with 2 pins and all constraints




Cloth Wireframe with Varying Constraints

No shearing constraints (structural & bending)

Only shearing constraints (shearing)

All constraints (structural, shearing, & bending)




Part II: Simulation via Numerical Integration

The goal of this section is to simulate the cloth's motion over time. In our cloth sim, objects are affected by two kinds of forces: external forces which exert uniform force to all objects in the scene and spring correction forces which affect each object differently depending on the spring constraint type. To simulate movement, I update each PointMass with the sum of all the forces. Next, I use Verlet Integration to calculate the PointMass's change in position. Finally, I correct positions for PointMasses with abnormally high deformation. The simulation cloth should now behave similarly to a cloth in real life.

Each PointMass object has a force vector that represents the sum total of forces on the PointMass at the current step of the simulation. I loop through all the Springs and add the external_accelerations (like gravity, wind, etc.). Then, I calculate the spring correction forces using Hooke's Law:

F_s = k_s * (||p_a - p_b|| - l)
where k_s is the spring constant which represents a spring's "stiffness" and l represents the resting length of the spring.

Next, I looped through all the PointMasses. If the point is not pinned (meaning the point is allowed to move), I calculate its new position, taking into account the forces.


x_t represents the point's current position. x_(t-dt) represents the point's position at the last timestep. a_t is represented by the sum of the total forces divided by the mass of the point. d is the damping value of the cloth which represents the frictional force on the spring.

For the final step of that time step's simulation, I loop through all the springs to correct positions of points that may have strayed too far, causing the springs between points to exceed 10% of their resting length. If the distance between the two points of a spring is more than 10% greater than the spring's resting length, I adjust the position points. If neither of the spring's points are pinned, I correct both point positions (by half the amount I would if one point was pinned). I adjust each point by the current distance between the points multiplied by the difference between our maximally allowed distance (1.10 x distance).


Varying Effects of ks

ks is the spring constant in Hooke's Law. It measures a spring's stiffness. This constant is uniformly applied to all springs in the cloth so low ks may indicate "stretchier" springs while high ks may indicate "tighter" springs.

Low ks: 100 N/m with shaded cloth
Low ks: 100 N/m with normals cloth
High ks: 10,000 N/m with shaded cloth
High ks: 10,000 N/m with normals cloth

In the top image, the cloth appears much more elastic. The folds are not distinct and the curvature of the top of the cloth is much greater than the curvature of the cloth on the right. Conversely, in the bottom image, the higher ks value indicates a less elastic cloth where the respective PointMasses of the springs are not able to move as far away as they could with a low ks value.

Varying Effects of Density

Density is used to calculate the mass of each point in the cloth. It measures the mass per unit area of the cloth. At low densities, external forces have a lesser effect overall (for F = ma, if we keep a constant, and decrease m, F will decrease). Therefore, the low density cloth looks lighter and has a slighter curvature to the top of the cloth. Conversely, high density indicates that each PointMass takes up significant mass. This leads to the top of the cloth appearing to be very curved and the folds to be much more pronounced in shape as the external forces are pushing the PointMasses further down with each step of the simulation.

Low density: 1g/cm^2 with shaded cloth
Low density: 1g/cm^2 with normals cloth
High density: 100g/cm^2 with shaded cloth
High density: 100g/cm^2 with normals cloth

Low Density (1g/cm^2) = not a huge amount of give in the springs (top curve is not intense). Also note the gradient of the normals are much smoother in the low density cloth simulation.
High Density (10g/cm^2) = cloth seemed much thicker with very heavy large folds. The higher the density, the more contrast and color variation occurs in the normals.

Varying Effects of Damping

Damping value is used to simulate energy loss. The higher the damping value, the faster the cloth stops swaying since the energy loss per timestep of the simulation is greater. For the following pictures, I initially set my damping value to 0.0% which caused the simulation to run (seemingly) forever as the energy was not being lost. With high damping values, the cloth stopped after one swing (on the way down from its horizontal position).

Low damping: 0.0%; Shaded cloth
Low damping: 0.0%; Normals of cloth
Low damping: 0.080460%; Shaded cloth
Low damping: 0.080460%; Normals of cloth
High damping: 1.00%; Shaded cloth
High damping: 1.00%; Normals of cloth

No Damping (0.0%) = Takes forever to run since energy can't dissapate at a normal rate. With no energy dissapation from friction, the cloth kept oscillating for the 5 minutes the simulation ran for.
Low Damping (0.080460%) = Moves for a while before settling into final position. The damping value is relatively low and thus the cloth swings for a while before the energy from the forces on each spring stop the cloth. Note that there is a smoother gradient between normals for low damping (compared to the normal gradient for high damping).
High Damping (1.0%) = Falls immediately without any swaying. Note that the normals at the top of the cloth are also flatter (more green) and the fold in the cloth is much more evident.



Cloth with 4 Pins in its Resting State

Shaded Cloth with 4 Pins
Normals Cloth with 4 Pins

Wireframe Cloth with 4 Pins




Part III: Handling collisions with other objects

In order to accurately simulate the real world, we need to implement collisions with other objects. In this section, I implemented the plane's collision with spheres and planes.

In each step of the simulation, I loop through all my points and check their positions. If the position is within the surface of the sphere or on the sphere's surface, I update their position so that the PointMass now lies on top of the sphere at its tangent point. Then, I compute the PointMass's correction vector which is the difference between the tangent point and the PointMass's position at its last time step. This vector is multiplied against the friction value (so that the PointMass can lie slightly above the surface) and added to the PointMass's position at its last timestep.

Cloth on sphere with ks: 500 N/m
Cloth on sphere with ks: 5,000 N/m
Cloth on sphere with ks: 500,000 N/m

For the plane collision, I used the ray-plane equation to calculate the tangent point of the PointMass and the plane. After finding the tangent point, I compare the distance between the tangent point and the PointMass's last position with the distance between the position and the PointMass's last position. The goal is to find out if this timestep led to a point crossing past a plane. If the distance between the PointMass's current position is greater than the last position and the tangent point (that is on the plane), the PointMass must have intersected the plane. Given this is the case, I calculate the correction vector which moves the PointMass to a small surface offset above the plane (in the direction of the plane's normal). I set the PointMass's position to the sum of the PointMass's last position and the correction vector.

Cloth resting on plane with ks: 500 N/m




Part IV: Handling self-collisions

At this stage of the simulation, the cloth is able to detect collision with other objects. However, it will still clip into itself as it cannot detect its own points. The purpose of this section is to implement self-collision where the cloth will fold and the majority of PointMasses will adjust such that clipping is minimal.

In order to implement this, I first divided the cloth's maximum space into bounding boxes, eaching containing some number of PointMasses. All points within the same bounding box, are then hashed to the same bucket. By hashing every point in the cloth, I can build a spatial map that groups together the closest points within a section. The buckets are used to check points against their closest neighbors (other points within the same box) for clipping. If the difference between any pair of points within each bucket is less than 2 x thickness (represents the cloth's thickness), then I adjust the initial point's position to be a total of 2 x thickness distance away from that particular neighbor. The initial point's final position is the average of all the corrected positions divided by the number of simulation steps the cloth sim is running. Less correction is needed if more simulation steps are done.

An issue with this particular method is that it does not check for points < (2 x thickness) away when PointMasses are within different buckets. This can lead to clipping (seen in some screenshots below). However, over time, the clipping issue disappeared as the cloth flattened out. The number of buckets are also expected to decrease as the simulation runs.

Self-colliding cloth with default parameters



Varying Density:

Low Density @ 1g/cm^2: Note that the cloth is relatively smooth with any folds that occur being large in size. There are no small wrinkles and the simulation ran quickly.


High Density @ 100g/cm^2: Note that the cloth has many wrinkles throughout the simulation and the folds vary in size (large and small). The simulation took longer to complete and clipping occurred.



Varying ks:

Low ks @ 1 N/m: Note that the cloth is insanely wrinkled. The small spring constant value means that the springs are extremely elastic. This simulation took a while for the cloth to flatten out but no significant clipping occurred.


High ks @ 100,000 N/m: Note that the cloth only contained large folds. The relative stiffness of the springs meant that each individual spring's PointMasses could not undergo large changes in position. As such, the collisions were isolated to larger areas.



Part V: Extra Credit

Shaders

I implemented a couple different shaders in addition to the current shader:


Wind

Wind is a spatially and time-varying force. My intuition behind this section was to change the position of each point by some small random number (fractional) in each step of Verlet Integration during simulation. I generate 6 random numbers: 3 are used to determine the sign of the fraction and the other 3 represent the numerator of the fraction added to position.x, position.y, position.z. I multiply this wind-vector by delta_t since wind varies with time.
The current line is commented out in the code so feel free to adjust to test (Line 207 in cloth.cpp).

Cloth wireframe with 2 pins & wind force
Cloth with 2 pins & wind force

Gif of wind (Simulation sped up)