• fullscreen
• Particle.pde
• fabric.pde
• ```// The Link class is used for handling constraints between particles.
float restingDistance;
float stiffness;

Particle p1;
Particle p2;

// the scalars are how much "tug" the particles have on each other
// this takes into account masses and stiffness, and are set in the Link constructor
float scalarP1;
float scalarP2;

// if you want this link to be invisible, set this to false
boolean drawThis = true;

Link (Particle which1, Particle which2, float restingDist, float stiff) {
p1 = which1; // when you set one object to another, it's pretty much a reference.
p2 = which2; // Anything that'll happen to p1 or p2 in here will happen to the paticles in our array

restingDistance = restingDist;
stiffness = stiff;

// although there are no differences in masses for the curtain,
// this opens up possibilities in the future for if we were to have a fabric with particles of different weights
float im1 = 1 / p1.mass; // inverse mass quantities
float im2 = 1 / p2.mass;
scalarP1 = (im1 / (im1 + im2)) * stiffness;
scalarP2 = (im2 / (im1 + im2)) * stiffness;
}

void constraintSolve () {
// calculate the distance between the two particles
PVector delta = PVector.sub(p1.position, p2.position);
float d = sqrt(delta.x * delta.x + delta.y * delta.y);
float difference = (restingDistance - d) / d;

// if the distance is more than curtainTearSensitivity, the cloth tears
// it would probably be better if force was calculated, but this works
if (d > curtainTearSensitivity)

// P1.position += delta * scalarP1 * difference
// P2.position -= delta * scalarP2 * difference
p2.position.sub(PVector.mult(delta, scalarP2 * difference));
}

void draw () {
if (drawThis)
line(p1.position.x, p1.position.y, p2.position.x, p2.position.y);
}
}
```
```// the Particle class.
class Particle {
PVector lastPosition; // for calculating position change (velocity)
PVector position;

PVector acceleration;

float mass = 1;
float damping = 20;

// An ArrayList for links, so we can have as many links as we want to this particle :)

boolean pinned = false;
PVector pinLocation = new PVector(0,0);

// Particle constructor
Particle (PVector pos) {
position = pos.get();
lastPosition = pos.get();
acceleration = new PVector(0,0);
}

// The update function is used to update the physics of the particle.
// motion is applied, and links are drawn here
void updatePhysics (float timeStep) { // timeStep should be in elapsed seconds (deltaTime)
// gravity:
// f(gravity) = m * g
PVector fg = new PVector(0, mass * gravity);
this.applyForce(fg);

/* Verlet Integration, WAS using http://archive.gamedev.net/reference/programming/features/verlet/
however, we're using the tradition Velocity Verlet integration, because our timestep is now constant. */
// velocity = position - lastPosition
PVector velocity = PVector.sub(position, lastPosition);
// apply damping: acceleration -= velocity * (damping/mass)
acceleration.sub(PVector.mult(velocity,damping/mass));
// newPosition = position + velocity + 0.5 * acceleration * deltaTime * deltaTime

// reset variables
lastPosition.set(position);
position.set(nextPos);
acceleration.set(0,0,0);
}
void updateInteractions () {
// this is where our interaction comes in.
if (mousePressed) {
float distanceSquared = distPointToSegmentSquared(pmouseX,pmouseY,mouseX,mouseY,position.x,position.y);
if (mouseButton == LEFT) {
if (distanceSquared < mouseInfluenceSize) { // remember mouseInfluenceSize was squared in setup()
// To change the velocity of our particle, we subtract that change from the lastPosition.
// When the physics gets integrated (see updatePhysics()), the change is calculated
// Here, the velocity is set equal to the cursor's velocity
lastPosition = PVector.sub(position, new PVector((mouseX-pmouseX)*mouseInfluenceScalar, (mouseY-pmouseY)*mouseInfluenceScalar));
}
}
else { // if the right mouse button is clicking, we tear the cloth by removing links
if (distanceSquared < mouseTearSize)
}
}
}

void draw () {
// draw the links and points
stroke(0);
for (int i = 0; i < links.size(); i++) {
}
}
else
point(position.x, position.y);
}
/* Constraints */
void solveConstraints () {
// Links make sure particles connected to this one is at a set distance away
for (int i = 0; i < links.size(); i++) {
}

/* Boundary Constraints */
// These if statements keep the particles within the screen
if (position.y < 1)
position.y = 2 * (1) - position.y;
if (position.y > height-1)
position.y = 2 * (height - 1) - position.y;
if (position.x > width-1)
position.x = 2 * (width - 1) - position.x;
if (position.x < 1)
position.x = 2 * (1) - position.x;

/* Other Constraints */
// make sure the particle stays in its place if it's pinned
if (pinned)
position.set(pinLocation);
}

// attachTo can be used to create links between this particle and other particles
void attachTo (Particle P, float restingDist, float stiff) {
}
}

void applyForce (PVector f) {
// acceleration = (1/mass) * force
// or
// acceleration = force / mass
}

void pinTo (PVector location) {
pinned = true;
pinLocation.set(location);
}
}
```
```/*
Curtain (Fabric Simulator)
Made by BlueThen on February 5th, 2011; updated February 10th and 11th, 2011 and July 18th and 19th, 2011
To interact, left click and drag, right click to tear,
press 'G' to toggle gravity, and press 'R' to reset
www.bluethen.com
*/

ArrayList particles;

// every particle within this many pixels will be influenced by the cursor
float mouseInfluenceSize = 15;
// minimum distance for tearing when user is right clicking
float mouseTearSize = 8;
float mouseInfluenceScalar = 1;

// force of gravity is really 9.8, but because of scaling, we use 9.8 * 40 (392)
// (9.8 is too small for a 1 second timestep)
float gravity = 392;

// Dimensions for our curtain. These are number of particles for each direction, not actual widths and heights
// the true width and height can be calculated by multiplying restingDistances by the curtain dimensions
final int curtainHeight = 56;
final int curtainWidth = 80;
final int yStart = 25; // where will the curtain start on the y axis?
final float restingDistances = 5;
final float stiffnesses = 1;
final float curtainTearSensitivity = 50; // distance the particles have to go before ripping

// These variables are used to keep track of how much time is elapsed between each frame
// they're used in the physics to maintain a certain level of accuracy and consistency
// this program should run the at the same rate whether it's running at 30 FPS or 300,000 FPS
long previousTime;
long currentTime;
// Delta means change. It's actually a triangular symbol, to label variables in equations
// some programmers like to call it elapsedTime, or changeInTime. It's all a matter of preference
// To keep the simulation accurate, we use a fixed time step.
final int fixedDeltaTime = 15;
float fixedDeltaTimeSeconds = (float)fixedDeltaTime / 1000.0;

// the leftOverDeltaTime carries over change in time that isn't accounted for over to the next frame
int leftOverDeltaTime = 0;

// How many times are the constraints solved for per frame:
int constraintAccuracy = 3;

// instructional stuffs:
PFont font;
final int instructionLength = 3000;
void setup () {
// I find that P2D is the fastest renderer for 2D graphics
// OPENGL may be faster for some people
// The default renderer is JAVA2D
size(640,480, P2D);

// we square the mouseInfluenceSize and mouseTearSize so we don't have to use squareRoot when comparing distances with this.
mouseInfluenceSize *= mouseInfluenceSize;
mouseTearSize *= mouseTearSize;

// create the curtain
createCurtain();

textFont(font);
}

void draw () {
background(255);

/******** Physics ********/
// time related stuff
currentTime = millis();
// deltaTimeMS: change in time in milliseconds since last frame
long deltaTimeMS = currentTime - previousTime;
previousTime = currentTime; // reset previousTime
// timeStepAmt will be how many of our fixedDeltaTime's can fit in the physics for this frame.
int timeStepAmt = (int)((float)(deltaTimeMS + leftOverDeltaTime) / (float)fixedDeltaTime);
// Here we cap the timeStepAmt to prevent the iteration count from getting too high and exploding
timeStepAmt = min(timeStepAmt, 5);

leftOverDeltaTime += (int)deltaTimeMS - (timeStepAmt * fixedDeltaTime); // add to the leftOverDeltaTime.

// If the mouse is pressing, it's influence will be spread out over every iteration in equal parts.
// This keeps the program from exploding from user interaction if the timeStepAmt gets too high.
mouseInfluenceScalar = 1.0 / timeStepAmt;

// update physics
for (int iteration = 1; iteration <= timeStepAmt; iteration++) {
// solve the constraints multiple times
// the more it's solved, the more accurate.
for (int x = 0; x < constraintAccuracy; x++) {
for (int i = 0; i < particles.size(); i++) {
Particle particle = (Particle) particles.get(i);
particle.solveConstraints();
}
}

// update each particle's position
for (int i = 0; i < particles.size(); i++) {
Particle particle = (Particle) particles.get(i);
particle.updateInteractions();
particle.updatePhysics(fixedDeltaTimeSeconds);
}
}
// draw each particle or its links
for (int i = 0; i < particles.size(); i++) {
Particle particle = (Particle) particles.get(i);
particle.draw();
}

if (millis() < instructionLength)
drawInstructions();

if (frameCount % 60 == 0)
println("Frame rate is " + frameRate);
}
void createCurtain () {
// We use an ArrayList instead of an array so we could add or remove particles at will.
// not that it isn't possible using an array, it's just more convenient this way
particles = new ArrayList();

// midWidth: amount to translate the curtain along x-axis for it to be centered
// (curtainWidth * restingDistances) = curtain's pixel width
int midWidth = (int) (width/2 - (curtainWidth * restingDistances)/2);
// Since this our fabric is basically a grid of points, we have two loops
for (int y = 0; y <= curtainHeight; y++) { // due to the way particles are attached, we need the y loop on the outside
for (int x = 0; x <= curtainWidth; x++) {
Particle particle = new Particle(new PVector(midWidth + x * restingDistances, y * restingDistances + yStart));

// attach to
// x - 1  and
// y - 1
// particle attachTo parameters: Particle particle, float restingDistance, float stiffness
// try disabling the next 2 lines (the if statement and attachTo part) to create a hairy effect
if (x != 0)
particle.attachTo((Particle)(particles.get(particles.size()-1)), restingDistances, stiffnesses);
// the index for the particles are one dimensions,
// so we convert x,y coordinates to 1 dimension using the formula y*width+x
if (y != 0)
particle.attachTo((Particle)(particles.get((y - 1) * (curtainWidth+1) + x)), restingDistances, stiffnesses);

/*
// shearing, presumably. Attaching invisible links diagonally between points can give our cloth stiffness.
// the stiffer these are, the more our cloth acts like jello.
// these are unnecessary for me, so I keep them disabled.
if ((x != 0) && (y != 0))
particle.attachTo((Particle)(particles.get((y - 1) * (curtainWidth+1) + (x-1))), restingDistances * sqrt(2), 0.1, false);
if ((x != curtainWidth) && (y != 0))
particle.attachTo((Particle)(particles.get((y - 1) * (curtainWidth+1) + (x+1))), restingDistances * sqrt(2), 1, true);
*/

// we pin the very top particles to where they are
if (y == 0)
particle.pinTo(particle.position);

}
}
}

// Controls. The r key resets the curtain, g toggles gravity
void keyPressed() {
if ((key == 'r') || (key == 'R'))
createCurtain();
if ((key == 'g') || (key == 'G'))
toggleGravity();
}
void toggleGravity () {
if (gravity != 0)
gravity = 0;
else
gravity = 392;
}

void drawInstructions () {
rect(0,0, 200,45);
text("'r' : reset", 10, 20);
text("'g' : toggle gravity", 10, 35);
}

// Credit to: http://www.codeguru.com/forum/showpost.php?p=1913101&postcount=16
float distPointToSegmentSquared (float lineX1, float lineY1, float lineX2, float lineY2, float pointX, float pointY) {
float vx = lineX1 - pointX;
float vy = lineY1 - pointY;
float ux = lineX2 - lineX1;
float uy = lineY2 - lineY1;

float len = ux*ux + uy*uy;
float det = (-vx * ux) + (-vy * uy);
if ((det < 0) || (det > len)) {
ux = lineX2 - pointX;
uy = lineY2 - pointY;
return min(vx*vx+vy*vy, ux*ux+uy*uy);
}

det = ux*vy - uy*vx;
return (det*det) / len;
}
```

### tweaks (1)

This sketch is running as Java applet, exported from Processing.

Report Sketch

Report for inappropriate content

Your have successfully reported the sketch. Thank you very much for helping to keep OpenProcessing clean and tidy :)

## Curtain

423

http://jaredcounts.com

Fabric simulation in Processing. It makes use of
verlet integration. I did my best to comment the code.

How to make a Fabric Simulator:
http://gamedevelopment.tutsplus.com/tutorials/simulate-tearable-cloth-and-ragdolls-with-simple-verlet-integration--gamedev-519

Left click and drag to interact.
Right click to tear.
Press 'G' to toggle gravity.
Press 'R' to reset.

Jacob Haip
5 Feb 2011
Very nicely done. The organization and commenting on the code makes this a great sketch.
Jared Counts
5 Feb 2011
Thank you. I try my best to aim for clean and well documented code. I was going to separate the classes into their own files, but forgot to when uploading this.

I sometimes fear over-commenting it, as editing it later on will be a hassle maneuvering around comments.
Jared Counts
5 Feb 2011
Just added tearing. You can tear the curtain by pushing it too hard (left click), or right clicking.
Wolfe
5 Feb 2011
Amazing!
Asher Salomon
6 Feb 2011
This is one kick @\$\$ sketch
bitcraft
7 Feb 2011
If you are fast with the mouse you can even tear it apart! This makes me feel like Zorro.
Awesome!
Jared Counts
7 Feb 2011
bitcraft, try messing with some of the variables such as mouseStrength and mouseInfluenceSize. The curtain will tear to shreds effortlessly if the mouseStrengths set high enough.
N-I-C-E. My friend Brian, thinks this is wayyy cool!!!
Jared Counts
11 Feb 2011
Hi. I updated the applet. It's now more consistent with different frame rates, and a gravity toggle has been added.

I'll be updating my blog tomorrow morning with details on what I've done, and how you could make a verlet integrated physics engine more consistent.
Thang Phan
4 Mar 2011
Awesome sketch! well done!
Wow, this is great!
Ferhat Sen
12 Mar 2011
Hi,

I have combined your awesome cloth simulator with Kinect.
http://www.vimeo.com/20964926

Thank you
Cool Ferhat Sen. Any plans on sharing the code?
Jared Counts
12 Mar 2011
Ferhat: Awesome!
Ferhat Sen
13 Mar 2011
thank you :)

I will share the code in my course blog soon. I can comment the link when I post it there.
Sorry for making you wait. But only for a week
Pistachio Pony
18 Mar 2011
Absolutely beautiful work!!! I'm learning so much from it! Thank you!
chiaki
21 Mar 2011
cooooool.....!!!!
Cheyanne Rogers
25 Mar 2011
man this is fun!
Kyle McDonald
23 Apr 2011
seriously just played with this for the last 10 minutes. the dynamics are perfect.

and yes, wonderfully documented + organized code. i'd love to see an OF port to get an idea of how fast this could be.
Jared Counts
24 Apr 2011
Hi Kyle. Mind telling me what OF is?

And thanks for the comment @ Kyle and everybody else. Let me know if there's any errors or bad coding. I appreciate any constructive criticism anyone might add.
Kyle McDonald
24 Apr 2011
OF is short for openFrameworks. it's similar to Processing in that it's aimed at 'creative coding', but OF uses C++ instead of Java, so it can be much faster for these kinds of low-level computations. check it out: http://openframeworks.cc/
Jared Counts
24 Apr 2011
Aw sweet! I'll definitely check it out.
Ilya Zarembsky
2 May 2011
Awesome & beautiful.

There's a bug; grab the curtain and pull it up until the cursor is above the hanging rod, then move the cursor laterally.
kim scott
6 May 2011
NICE!
very nice!
jesus great!
Daphne Tang
2 Jun 2011
This is very nice.. You can even shred it. Genius!
Simo Endre
16 Jun 2011
the most inspiring verlet integration i have ever seen! congrats!
Marius Gerum
20 Jun 2011
AMAZING!!!! AWESOME!!!!
Ted Brown
7 Jul 2011
/bow
Jared Counts
19 Jul 2011
Hey everyone, thanks for the feedback!

I updated the source to be cleaner, faster, and smoother.

Excellent! This is great work. Congratulations.
Tony Blanco
4 Aug 2011
Sweet!
bejoscha
11 Aug 2011
really nice. Thanks for putting it on.
Paul Myburgh
9 Sep 2011
awesome.
Gerd Platl
27 Sep 2011
// Really nice work! I like this simulation!
// Here's a hint for a small speedup of following function...

// get squared distance of a point to a line segment
float distPointToSegmentSquared (float lineX1, float lineY1, float lineX2, float lineY2, float pointX, float pointY) {
float vx = pointX - lineX1;
float vy = pointY - lineY1;
float ux = lineX2 - lineX1;
float uy = lineY2 - lineY1;

float det = vx * ux + vy * uy;
if (det &lt; 0)
return vx*vx+vy*vy;

float len = ux*ux + uy*uy;
if (det &gt; len)
return sq(lineX2 - pointX) + sq (lineY2 - pointY);

return sq(ux*vy - uy*vx) / len;
}
Ergun Coruh
22 Oct 2011
Amazing! Beautiful code too. Thanks for sharing.
FORMIDABLE monsieur........!
Hello
I spent hours to find the font:

LucidaBright-Demi-16.vlw

for my Mac Book Pro 10.5

any ideas?

best
Peter Hofmann
21 Mar 2012
Wow, it's amazing what you can do with Processing. Great work!
franco e
23 Mar 2012
Gottfried, just replace it for another font.

btw, no more bluethen wordpress?
Jared Counts
23 Mar 2012
franco: Crap! Looks like my domain's expiring. I'll be getting it back up asap.

Gottfried: You can use any font. The LucidaBright-Demi-16 was made using Processing's Create Font tool, which lets you load whichever font you'd like into the data folder.
ok, bon super

merci beaucoup
oups, I forgot
suppose You want to change the thickness and/or the wideness of the net's squares sorry my english is limited and the colour where is the best place and how should I do

I am still a bit new to Processing....

thanks a lot
Jared Counts
24 Mar 2012
Gottfried: You can change the distances between points by changing the value of restingDistances in fabric.pde

final float restingDistances = 5; // <- this number

final int curtainHeight = 56; // <- how many rows there are
final int curtainWidth = 80; // <- how many columns
bonjour a tous

merci once more

now a (perheps) last question(3), sorry 2 questions
Q1:
how to change randomly or "controlled by a variable": control panel
- the size of the thread
- distance of the squares

Q2:
- how to "introduce" my own paintings into the squares
- put a set of for exemple 10 paintings via control panel
- make them working

globally said : the curtain will become a sort of personally designed tissu

thanks a lot
and hughs from Montmartre

gottfried
Jared Counts
25 Mar 2012
Q1 A: The size of each link is contained within Link.pde. To get to each link, you can access them through the Particle class.

From fabric.pde, you can access every link by looping through every particle:
for (int i = 0; i < particles.size(); i++) {
Particle particle = (Particle) particles.get(i);
for (int i = 0; i &lt; links.size(); i++) {
currentLink.restingDistance = newLength; // newLength being whatever number you want
}
}

If you want to change the stroke width (how thick each line is), you'll need to change Link's draw code. In Link.pde:

void draw () {
if (drawThis) {
strokeWidth(strokeSize); // strokeSize being however thick
line(p1.position.x, p1.position.y, p2.position.x, p2.position.y);
}
}

Alternatively, you can put strokeWidth(strokeSize) inside Particle's draw method, before it draws the links, or you can put it in fabric.pde, before telling each particle to draw its links.

If you're wanting to program in some sort of graphical menu, I can't really tell you how to do that in a small post like this (controlP5 is a pretty good GUI libarary, google that). The quickest way to add user control is to add some more if statements in the keyPressed method in fabric.pde:

if ((key == 'q') || (key == 'Q'))
// loop through particles and increase stroke size or length,

Q2 A: I'm guessing you want to texture the whole curtain? That's going to be a bit more challenging. I made a fairly basic textured version of Curtain and uploaded it here: http://bluethen.com/secretApplets/texturedFabric/applet/

You can access the source files from here: http://bluethen.com/secretApplets/texturedFabric/

I hope that helps. Good luck.
many thanks
I will have to integrate all this

merci encore
g
Awesome! Tearing is great idea and the whole stuff is nice implemented! I'm just learning Processing and this is nice part of material to learn!
Jared Counts
9 Apr 2012
Let me know if you need any help, Pawel!
I'm in love with this sketch.
Kate Eisenbraun
17 Aug 2012
I like to rip it to shreds and then reset it
:D *thumbs up*
Ray Shortridge
19 Sep 2012
Brilliant! Having just started data vis I am amazed at what can be achieved. I hope I can be half as good as this.
Dylan Wynn
4 Oct 2012
Hi Jared, Is there a way I could talk to you perhaps e-mail or something? I need your help with something
Jared Counts
6 Oct 2012
Dylan: Sure, email me at bluethen (at) gmail.com
polguezennec
9 Nov 2012
fantastic
This is the coolest thing I've seen all day, and I've been looking at some pretty cool stuff. I just love playing with it!
Jared Counts
17 Dec 2012
I made some minor changes. It should no longer flicker on slower machines.
Gene Kao
21 Feb 2013
great idea! I like your pinTo haha..... really smart~~
And I made a little change and try it like 3D, hope you like it :))
http://www.openprocessing.org/sketch/90549
Raime Todoca
4 Mar 2013
Hey! I tweaked your curtain to make it react to sound input. Had lots of fun with it! Fantastic sketch!

Jared Counts
4 Mar 2013
Raime Todoca, that is awesome!! Play some music over it and see what happens!
Raime Todoca
5 Mar 2013
I find it more funny to mess with it with distorted and huge bass soundwaves :)

You can get it at https://dl.dropbox.com/u/6708989/processing/fabric.rar if you'd like to
Ever considered doing this in 3D?
Great stuff man, im gonna go through your code and try and learn more about this. I'm really interested in the interactive art medium (not video games, per se), and your curtain is a good example of that, but i wanted to add some color to it.

So, i "tweaked" your code to change color based on velocity. its pretty crude implementation of that, and i really only added like 2 lines of code. None-the-less, i think it looks really cool and i havent even played with the colors all that much, its just red and yellow at the moment.

Jared Counts
14 Mar 2013
Anson Mansfield: I have, and I did do a version in 3D! http://bluethen.com/secretapplets/superShadedFabric/applet/

Tom Sterkenburg: Thanks! If you have any issues, then let me know.
ale plus+
6 Apr 2013
Hi, Jared.
I recently found this javascript port:
http://codepen.io/stuffit/details/KrAwx
...and thanks for sharing! : )
This is awesome!
How do you change the size and color to the curtain? Is it possible to apply an Image to it? Like a JPG texture?

Been playing around with this for houers XD
Jared Counts
9 Apr 2013
Ale: Yes, I saw it too! It's pretty well-done, despite the "Copyright lonely-pixel" and permissions slapped on there.

olaf: You certainly can apply an image. I made a version quite awhile back, hosted here: http://bluethen.com/secretapplets/texturedFabric/applet/
Michael S
28 Aug 2013
Wonderful. Truly outstanding.
claire kang
29 Oct 2013
crazy beautiful
cylia
20 Nov 2013
wooooooow !!!!great!!!!!!!
Thanks for this wonderful implementation and awesome comments, Jared. I made a port of the 2D version to openFrameworks.

https://github.com/tomana/curtain_OFport
did you know that your sketch responds differently on a Mac vs. a PC? I initially found your sketch on my PC and your instructions work -left click drag, right click tear. But on a Mac, right and left click both tear. Do you have any idea what might cause that?
Jared Counts
7 Feb 2014
Tom,

That's wonderful! I actually made a C++ port at around the same time as you.

Thanks for the contribution.
Jan Stapler
12 Feb 2014
I love this sketch and could play it for ages. Awesome work Jared!

I thought it would be quite funny to have this on the mobile phone. But I can't get the sketch working in android mode. Does someone have an idea how to make it run for mobile phone?
Darby Smurf
3 Apr 2014
so nice sketch!
Parag Kulkarni
5 May 2014
No wonder this is most awesome sketch i have ever seen.
leeznp
5 Jun 2014
How do i fill window curtain colors? plz help me~
leeznp
5 Jun 2014
How did i fill window curtain colors? plz help me~
Aloysiusbe
8 Jul 2014
wow
Aloysiusbe
8 Jul 2014
wow
陈俊魁
9 May 2015
Amazing!I may use it to attractmy friends to learn processing!
You need to login/register to comment.