Overview
In this part, we create wireframes of clothes using point masses and springs between the masses.
First, we create
an evenly spaced grid of point masses with size num_width_points by num_height_points in 3D space. If the cloth's orientation
if horizontal, set y to 1; if the orientation is vertical, set z to a small number (between -1/1000 and 1/1000). The top
left mass will be on coordinate (0,0). Then we set all point mass whose coordinates are in the "pinned points" list with
property pinned set to be true. The point masses are stored in a vector in row-major order.
The second step is to create springs belonging to three types: structual, shear, and bending constraints. Every spring will
have property: two point masses on the two ends of it, and the spring type. Structural constraints are between a point and
the point on its left or top. Shearing constraints are between a point and the point to its diagonal upper left or diagonal
upper right. Bending constraints are between a point and the point two away to its left or top.
Below are screenshots of a wireframe of a piece of flat cloth. You can see the structure of point masses (vertices) and springs(edges) on the screenshots.
![]() |
![]() |
Below are screenshots of the same wireframe with different types of springs shown.
no shearing ![]() |
only shearing ![]() |
all constraints ![]() |
To simulate the motion of the cloth by simulating movements of point masses, we mainly calculate the forces on every
masses and rely on the equation \(F=ma\), where F is the total force, m is the mass of the particle(calculated by dividing
the total mass(height*width*density of cloth) of the cloth by number of point masses), and a is the acceleration.
The force on a mass contains two parts. The first one is an external force same for every mass, and it's calculated by
\(F=ma\), where m is mass of the point mass again, and a is given external_accelerations. The second one is
spring correction force (for every spring of enabled constraints), calculated by Hooke's Law \(F_s = k_s *
(||p_a-p_b)- l)\), where \(k_s\) iss spring constant, \(p_a\) and \(p_b\) are positions of two point masses, and
\(l_s\) is the spring's rest length. For springs of bending constraints, we further multiply \(F_s\) with
another small constant (we used 0.2), because bending constraint is weaker than the other two constraints.
Then we calculate the position of masses by Verlet integration. The new position is calculated by:
\(x_{t+dt} = x_t+(1-d)*(x_t-x_{t-dt})+a_t*dt^2\), where d is the damping term (betwen 0 and 1). Every point mass
will have property position and last_posistion.
Another thing to pay attention is the constraint that every spring can only have maxmum length equal to 1.1 * rest_length.
If the distance of the spring is larger than the maximum length allowed, perform half of the correction to each point mass on its
ends if none of them is pinned. Otherwise apply the whole correction to the unpinned point mass.
Below is a screenshots of a two-corner-pinned cloth simulated with default settings: \(k_s\)=5000, density=15, damping=0.2.
Below are some screenshots with different spring consant values \(k_s\). We can see lower the \(k_s\)(left), more wrinkles there would be on the top edge of the cloth which natually hangs down. Higher the \(k_s\)(right), more rigid the cloth is, and there are less wrinkles.
ks = 100 ![]() |
ks = 100000 ![]() |
Below are screenshots with different cloth density. We can see lower the density(left), less wrinkles there would be on the top edge of the cloth. That's because the cloth is light and it's less likely to fall towards earth. Higher the denity, the cloth is more attracted by earth, so the upper edge falls lower with more wrinkles.
density = 1 ![]() |
density = 100 ![]() |
Below are screenshots with different damping coefficients. We can see less the damping(left), the cloth swings faster, longer with gerater degree. That's because there's no "friction" and no energy loss, and the motion is consistent. Higher the damping(right), the cloth swings slower with shorter time and less degree. When damping is 1, there's no swing and the cloth just fall until it's vertical to the ground.
damping = 0 ![]() |
damping = 0.2 (default) ![]() |
damping = 1 ![]() |
Below is a piece of cloth with all of the 4 corners pinned instead of 2 for examples above.
view 1 ![]() |
view 2 ![]() |
In this part, we add collision behaviorws for the clothes. When collision happens, we want to make sure the cloth will rest
on the surface of the object instead of "getting into" the object.
When the cloth collides with a sphere, for every point mass, we check if it gets into the sphere by checking of the distance between
the mass and center of the sphere is smaller than the radius of the sphere. If so, update the position of the point mass to its tangent
point, which is the intersection of the path passing center and the point mass and the sphere surface. Notice that the change of the
position should be sacled down by friction (1-f).
When the cloth collodes with a plane, for every point mass, we check if it passes the plane from one side to the other side in last step.
If so, call the intersection of the mass's moving path and plane tangent point, and update the position of the point mass to its last_position
changed to a point SURFACE_OFFSET (a small constant) above the tangent point. Similarly, the change of the
position should be sacled down by friction (1-f).
Below are some screenshots with different spring consant values \(k_s\). We can see lower the \(k_s\)(left), softer the cloth is, and there are more wrinkles on parts of the cloth which falls around the sphere. Higher the \(k_s\)(right), more rigid the cloth is, and there are less wrinkles on parts of the cloth falling around the sphere.
ks = 500 ![]() |
ks = 5000 (default) ![]() |
ks = 50000 ![]() |
Below is a screenshot of a piece of shaded cloth falling on a plane. (Change to customized-color version later!!!!!!!!!!)
In this part, we want to handle another collision that we haven't implemented yet: self-collision. Instead of calculating the distance between every pair of point masses and apply a force to separate them if they are too close, which is very inefficient, we do spatial hashing. The main idea is to divide the whole space to smaller equal-sized 3D box volumes, so we can store point masses in a specific 3D box volume into a vector and create a map that the keys are indexes representing the volumes and the values are vectors of point masses in those volumes. To check if self-collision happens, for every point mass A, check if the distance between it and every other point mass B in the same 3D box volume is smaller than 2*THICKNESS. If so, record the distance change needed for this point mass A so that it's 2*THICKNESS away from point mass B. The final distance change needede for point mass A would be the average of all changes between A and another point mass in the same volume. Notice that we scale down (divide) the distance change by SIMULATION_STEPS to reduce the number of sudden position corrections.
Below are screenshots of the process of a piece of cloth falling on the ground. We can see the cloth will fold on itself when the bottom part touches the ground and the upper part is still falling. The upper part collides with the bottom part, so instead of passing through the bottom part, the upper part will rest on top of the bottom part.
![]() |
![]() |
![]() |
Below are screenshots with different cloth density. We can see lower the density, less wrinkles there would be for the cloth. There are less folding layers, and the surface of the cloth will be flatter and more tidy. Higher the denity, there are more wrinkles and more folding layers.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Below are some screenshots with different spring consant values \(k_s\). We can see lower the \(k_s\), similar to high density, there are more wrinkles and more folding layers, and that's reasonable for soft clothes. Higher the \(k_s\), more rigid the cloth is, and similar to low density, there are less wrinkles and less folding layers with flat and tidy surface.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |