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
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 ;
3514var DRAG = 1 - DAMPING ;
3615var 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
3959function 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}
0 commit comments