Skip to content

Commit a8853b8

Browse files
zz85mrdoob
authored andcommitted
Tweaked the cloth simulation example a little.
1 parent 438b7b7 commit a8853b8

2 files changed

Lines changed: 81 additions & 127 deletions

File tree

examples/js/Cloth.js

Lines changed: 73 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,5 @@
11
/*
2-
* Aug 3 2012
3-
*
4-
* Since I started working for a new startup not too long ago,
5-
* I commute between home and work for over 2 hours a day.
6-
* Although this means less time on three.js,
7-
* I try getting a little coding on the train.
8-
*
9-
* This set of experiments started from a simple hook's law doodle,
10-
* to spring simulation, string simulation, and I realized
11-
* I once again stepped onto physics and particle simulation,
12-
* this time, more specifically soft body physics.
13-
*
14-
* Based on the "Advanced Character Physics" article,
15-
* this experiment attempts to use a "massless"
16-
* cloth simulation model. It's somewhat similiar
17-
* but simplier to most cloth simulations I found.
18-
*
19-
* This was coded out fairly quickly, so expect more to come
20-
* meanwhile feel free to experiment yourself and share
21-
*
22-
* Cheers,
23-
* Graphics Noob (aka @Blurspline, zz85)
2+
* Cloth Simulation using a relaxed constrains solver
243
*/
254

265
// Suggested Readings
@@ -31,14 +10,56 @@
3110
// http://cg.alexandra.dk/tag/spring-mass-system/
3211
// Real-time Cloth Animation http://www.darwin3d.com/gamedev/articles/col0599.pdf
3312

34-
var DAMPING = 0.01;
13+
var DAMPING = 0.03;
3514
var DRAG = 1 - DAMPING;
3615
var MASS = .1;
37-
var restDistance = 25; //
16+
var restDistance = 25;
17+
18+
19+
var xSegs = 10; //
20+
var ySegs = 10; //
21+
22+
var clothFunction = plane(restDistance * xSegs, restDistance * ySegs);
23+
24+
var cloth = new Cloth(xSegs, ySegs);
25+
26+
var GRAVITY = 981 * 1.4; //
27+
var gravity = new THREE.Vector3( 0, -GRAVITY, 0 ).multiplyScalar(MASS);
28+
29+
30+
var TIMESTEP = 18 / 1000;
31+
var TIMESTEP_SQ = TIMESTEP * TIMESTEP;
32+
33+
var pins = [];
34+
35+
36+
var wind = true;
37+
var windStrength = 2;
38+
var windForce = new THREE.Vector3(0,0,0);
39+
40+
var ballPosition = new THREE.Vector3(0, -45, 0);
41+
var ballSize = 60; //40
42+
43+
var tmpForce = new THREE.Vector3();
44+
45+
var lastTime;
46+
47+
48+
function plane(width, height) {
49+
50+
return function(u, v) {
51+
var x = (u-0.5) * width;
52+
var y = (v+0.5) * height;
53+
var z = 0;
54+
55+
return new THREE.Vector3(x, y, z);
56+
};
57+
}
3858

3959
function Particle(x, y, z, mass) {
40-
this.position = new THREE.Vector3(x, y, z); // position
41-
this.previous = new THREE.Vector3(x, y, z); // previous
60+
this.position = clothFunction(x, y); // position
61+
this.previous = clothFunction(x, y); // previous
62+
this.original = clothFunction(x, y);
4263
this.a = new THREE.Vector3(0, 0, 0); // acceleration
4364
this.mass = mass;
4465
this.invMass = 1 / mass;
@@ -78,12 +99,6 @@ function satisifyConstrains(p1, p2, distance) {
7899
var correctionHalf = correction.multiplyScalar(0.5);
79100
p1.position.addSelf(correctionHalf);
80101
p2.position.subSelf(correctionHalf);
81-
82-
// float difference = (restingDistance - d) / d
83-
// im1 = 1 / p1.mass // inverse mass quantities
84-
// im2 = 1 / p2.mass
85-
// p1.position += delta * (im1 / (im1 + im2)) * stiffness * difference
86-
87102
}
88103

89104

@@ -102,7 +117,7 @@ function Cloth(w, h) {
102117
for (v=0;v<=h;v++) {
103118
for (u=0;u<=w;u++) {
104119
particles.push(
105-
new Particle((u - w/2) * restDistance, (v - h/2) * -restDistance, 0, MASS)
120+
new Particle(u/w, v/h, 0, MASS)
106121
);
107122
}
108123
}
@@ -148,7 +163,7 @@ function Cloth(w, h) {
148163
// While many system uses shear and bend springs,
149164
// the relax constrains model seem to be just fine
150165
// using structural springs.
151-
// // Shear
166+
// Shear
152167
// var diagonalDist = Math.sqrt(restDistance * restDistance * 2);
153168

154169

@@ -171,87 +186,22 @@ function Cloth(w, h) {
171186
// }
172187

173188

174-
// // Bend
175-
176-
// var wlen = restDistance * 2;
177-
// var hlen = restDistance * 2;
178-
// diagonalDist = Math.sqrt(wlen * wlen + hlen * hlen);
179-
180-
// for (v=0;v<h-1;v++) {
181-
// for (u=0;u<w-1;u++) {
182-
// constrains.push([
183-
// particles[index(u, v)],
184-
// particles[index(u+2, v)],
185-
// wlen
186-
// ]);
187-
188-
// constrains.push([
189-
// particles[index(u, v)],
190-
// particles[index(u, v+2)],
191-
// hlen
192-
// ]);
193-
194-
// constrains.push([
195-
// particles[index(u, v)],
196-
// particles[index(u+2, v+2)],
197-
// diagonalDist
198-
// ]);
199-
200-
// constrains.push([
201-
// particles[index(u, v+2)],
202-
// particles[index(u+2, v+2)],
203-
// wlen
204-
// ]);
205-
206-
// constrains.push([
207-
// particles[index(u+2, v+2)],
208-
// particles[index(u+2, v+2)],
209-
// hlen
210-
// ]);
211-
212-
// constrains.push([
213-
// particles[index(u+2, v)],
214-
// particles[index(u, v+2)],
215-
// diagonalDist
216-
// ]);
217-
218-
// }
219-
// }
220-
221-
222189
this.particles = particles;
223190
this.constrains = constrains;
224191

225192
function index(u, v) {
226193
return u + v * (w + 1);
227194
}
228195

196+
this.index = index;
229197

230198
}
231199

232-
var cloth = new Cloth();
233-
234-
var GRAVITY = 981; //
235-
var gravity = new THREE.Vector3( 0, -GRAVITY, 0 ).multiplyScalar(MASS);
236-
237-
238-
var TIMESTEP = 14 / 1000;
239-
var TIMESTEP_SQ = TIMESTEP * TIMESTEP;
240-
241-
var pins = [true];
242-
pins[cloth.w] = true;
243-
244-
245-
var wind = true;
246-
var windStrength = 2;
247-
var windForce = new THREE.Vector3(0,0,0);
248-
249-
var ballPosition = new THREE.Vector3(0, -45, 0);
250-
var ballSize = 60; //40
251-
252-
var tmpForce = new THREE.Vector3();
253-
254-
function simulate() {
200+
function simulate(time) {
201+
if (!lastTime) {
202+
lastTime = time;
203+
return;
204+
}
255205

256206
var i, il, particles, particle, pt, constrains, constrain;
257207

@@ -276,7 +226,7 @@ function simulate() {
276226
;i<il;i++) {
277227
particle = particles[i];
278228
particle.addForce(gravity);
279-
// particle.addForce(windForce);
229+
280230
particle.integrate(TIMESTEP_SQ);
281231
}
282232

@@ -292,8 +242,8 @@ function simulate() {
292242
// Ball Constrains
293243

294244

295-
ballPosition.z = -Math.sin(Date.now()/300) * 90 ; //+ 40;
296-
ballPosition.x = Math.cos(Date.now()/200) * 70
245+
ballPosition.z = -Math.sin(Date.now()/600) * 90 ; //+ 40;
246+
ballPosition.x = Math.cos(Date.now()/400) * 70
297247

298248
if (sphere.visible)
299249
for (particles = cloth.particles, i=0, il = particles.length
@@ -308,15 +258,23 @@ function simulate() {
308258
}
309259
}
310260

311-
// Pin Constrains
312-
313-
for (i=0, il=cloth.w;i<=il;i++) {
314-
if (pins[i]) {
315-
particle = particles[i];
316-
particle.previous.set((i - cloth.w/2) * restDistance, -cloth.h/2 * -restDistance, 0);
317-
particle.position.copy(particle.previous);
261+
// Floor Constains
262+
for (particles = cloth.particles, i=0, il = particles.length
263+
;i<il;i++) {
264+
particle = particles[i];
265+
pos = particle.position;
266+
if (pos.y < -250) {
267+
pos.y = -250;
318268
}
319269
}
320270

271+
// Pin Constrains
272+
for (i=0, il=pins.length;i<il;i++) {
273+
var xy = pins[i];
274+
var p = particles[xy];
275+
p.position.copy(p.original);
276+
p.previous.copy(p.original);
277+
}
278+
321279

322280
}

examples/webgl_animation_cloth.html

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
</head>
3030

3131
<body>
32-
<div id="info">Simple Cloth Simulation #3<br/>
33-
Verlet based with Constrains relaxation<br/>
32+
<div id="info">Simple Cloth Simulation<br/>
33+
Verlet integration with Constrains relaxation<br/>
3434
Toggle: <a onclick="rotate = !rotate;">Camera</a> |
3535
<a onclick="wind = !wind;">Wind</a> |
3636
<a onclick="sphere.visible = !sphere.visible;">Ball</a> |
@@ -42,7 +42,6 @@
4242
<script src="js/Detector.js"></script>
4343
<script src="js/Stats.js"></script>
4444

45-
<script src="js/ParametricGeometries.js"></script>
4645
<script src="js/Cloth.js"></script>
4746

4847
<script type="x-shader/x-fragment" id="fragmentShaderDepth">
@@ -92,22 +91,20 @@
9291
/* testing cloth simulation */
9392

9493
var pinsFormation = [];
95-
var pins = [];
94+
var pins = [6];
9695

97-
pins[6] = true;
9896
pinsFormation.push( pins );
9997

100-
pins = [ true, true, true, true, true, true, true, true, true, true, true, true ];
98+
pins = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
10199
pinsFormation.push( pins );
102100

103-
pins = [ true ];
101+
pins = [ 0 ];
104102
pinsFormation.push( pins );
105103

106104
pins = []; // cut the rope ;)
107105
pinsFormation.push( pins );
108106

109-
pins = [ true ]; // classic 2 pins
110-
pins[ cloth.w ] = true;
107+
pins = [ 0, cloth.w ]; // classic 2 pins
111108
pinsFormation.push( pins );
112109

113110
pins = pinsFormation[ 1 ];
@@ -199,8 +196,7 @@
199196
];
200197

201198
// cloth geometry
202-
203-
clothGeometry = new THREE.ParametricGeometry( THREE.ParametricGeometries.plane( 200, 200 ), cloth.w, cloth.h, true );
199+
clothGeometry = new THREE.ParametricGeometry( clothFunction, cloth.w, cloth.h, true );
204200
clothGeometry.dynamic = true;
205201
clothGeometry.computeFaceNormals();
206202

@@ -357,7 +353,7 @@
357353
arrow.setLength( windStrength );
358354
arrow.setDirection( windForce );
359355

360-
simulate();
356+
simulate(time);
361357
render();
362358
stats.update();
363359

0 commit comments

Comments
 (0)