source: other-projects/nz-flag-design/trunk/render-3d/Flag_files/Flag.js@ 29547

Last change on this file since 29547 was 29547, checked in by bmt11, 9 years ago

Added updating of textures so when the flag is changed the updated version will display. Also started implementing some nice CSS buttons for weather control and wind control to come soon

File size: 7.5 KB
Line 
1/*
2 * Aug 9 2012
3 * Its Singapore's National Day, so
4 * Making a quick tweaks to simulate the Singapore flag in the wind
5 *
6 */
7/*
8 * Aug 3 2012
9 *
10 * Since I started working for a new startup not too long ago,
11 * I commute between home and work for over 2 hours a day.
12 * Although this means less time on three.js,
13 * I try getting a little coding on the train.
14 *
15 * This set of experiments started from a simple hook's law doodle,
16 * to spring simulation, string simulation, and I realized
17 * I once again stepped onto physics and particle simulation,
18 * this time, more specifically soft body physics.
19 *
20 * Based on the "Advanced Character Physics" article,
21 * this experiment attempts to use a "massless"
22 * cloth simulation model. It's somewhat similiar
23 * but simplier to most cloth simulations I found.
24 *
25 * This was coded out fairly quickly, so expect more to come
26 * meanwhile feel free to experiment yourself and share
27 *
28 * Cheers,
29 * Graphics Noob (aka @Blurspline, zz85)
30 */
31
32// Suggested Readings
33
34// Advanced Character Physics by Thomas Jakobsen Character - http://web.archive.org/web/20070610223835/http:/www.teknikus.dk/tj/gdc2001.htm
35// http://freespace.virgin.net/hugo.elias/models/m_cloth.htm
36// http://en.wikipedia.org/wiki/Cloth_modeling
37// http://cg.alexandra.dk/tag/spring-mass-system/
38// Real-time Cloth Animation http://www.darwin3d.com/gamedev/articles/col0599.pdf
39
40var DAMPING = 0.02;
41var DRAG = 1 - DAMPING;
42var MASS = .2;
43var restDistance = 20;
44
45
46var xSegs = 15; // ratio is 2:3
47var ySegs = 10; //
48
49var clothFunction = plane(restDistance * xSegs, restDistance * ySegs);
50
51var cloth = new Cloth(xSegs, ySegs);
52
53var GRAVITY = 981 * 1.4; //
54var gravity = new THREE.Vector3( 0, -GRAVITY, 0 ).multiplyScalar(MASS);
55
56
57var TIMESTEP = 18 / 1000;
58var TIMESTEP_SQ = TIMESTEP * TIMESTEP;
59
60var pins = [];
61var pinning = true;
62
63var wind = true;
64var windStrength = 2;
65var windForce = new THREE.Vector3(0,0,0);
66
67var ballPosition = new THREE.Vector3(0, -45, 0);
68var ballSize = 60; //40
69
70var tmpForce = new THREE.Vector3();
71
72var lastTime;
73
74
75
76
77function plane(width, height) {
78
79 return function(u, v) {
80 var x = u * width; //(u-0.5)
81 var y = v * height;
82 var z = 0;
83
84 return new THREE.Vector3(x, y, z);
85 };
86}
87
88function Particle(x, y, z, mass) {
89 this.position = clothFunction(x, y); // position
90 this.previous = clothFunction(x, y); // previous
91 this.original = clothFunction(x, y);
92 this.a = new THREE.Vector3(0, 0, 0); // acceleration
93 this.mass = mass;
94 this.invMass = 1 / mass;
95 this.tmp = new THREE.Vector3();
96 this.tmp2 = new THREE.Vector3();
97}
98
99// Force -> Acceleration
100Particle.prototype.addForce = function(force) {
101 this.a.add(
102 this.tmp2.copy(force).multiplyScalar(this.invMass)
103 );
104};
105
106
107// Performs verlet integration
108Particle.prototype.integrate = function(timesq) {
109 var newPos = this.tmp.subVectors(this.position, this.previous);
110 newPos.multiplyScalar(DRAG).add(this.position);
111 newPos.add(this.a.multiplyScalar(timesq));
112
113 this.tmp = this.previous;
114 this.previous = this.position;
115 this.position = newPos;
116
117 this.a.set(0, 0, 0);
118}
119
120
121var diff = new THREE.Vector3();
122
123function satisifyConstrains(p1, p2, distance) {
124 diff.subVectors(p2.position, p1.position);
125 var currentDist = diff.length();
126 if (currentDist==0) return; // prevents division by 0
127 var correction = diff.multiplyScalar(1 - distance/currentDist);
128 var correctionHalf = correction.multiplyScalar(0.5);
129 p1.position.add(correctionHalf);
130 p2.position.sub(correctionHalf);
131
132 // float difference = (restingDistance - d) / d
133 // im1 = 1 / p1.mass // inverse mass quantities
134 // im2 = 1 / p2.mass
135 // p1.position += delta * (im1 / (im1 + im2)) * stiffness * difference
136
137}
138
139function Cloth(w, h) {
140 w = w || 10;
141 h = h || 10;
142 this.w = w;
143 this.h = h;
144
145 var particles = [];
146 var constrains = [];
147
148 var u, v;
149
150 // Create particles
151 for (v=0;v<=h;v++) {
152 for (u=0;u<=w;u++) {
153 particles.push(
154 new Particle(u/w, v/h, 0, MASS)
155 );
156 }
157 }
158
159 // Structural
160
161 for (v=0;v<h;v++) {
162 for (u=0;u<w;u++) {
163
164 constrains.push([
165 particles[index(u, v)],
166 particles[index(u, v+1)],
167 restDistance
168 ]);
169
170 constrains.push([
171 particles[index(u, v)],
172 particles[index(u+1, v)],
173 restDistance
174 ]);
175
176 }
177 }
178
179 for (u=w, v=0;v<h;v++) {
180 constrains.push([
181 particles[index(u, v)],
182 particles[index(u, v+1)],
183 restDistance
184
185 ]);
186 }
187
188 for (v=h, u=0;u<w;u++) {
189 constrains.push([
190 particles[index(u, v)],
191 particles[index(u+1, v)],
192 restDistance
193 ]);
194 }
195
196
197 // While many system uses shear and bend springs,
198 // the relax constrains model seem to be just fine
199 // using structural springs.
200 // Shear
201 var diagonalDist = Math.sqrt(restDistance * restDistance * 2);
202
203
204 for (v=0;v<h;v++) {
205 for (u=0;u<w;u++) {
206
207 constrains.push([
208 particles[index(u, v)],
209 particles[index(u+1, v+1)],
210 diagonalDist
211 ]);
212
213 constrains.push([
214 particles[index(u+1, v)],
215 particles[index(u, v+1)],
216 diagonalDist
217 ]);
218
219 }
220 }
221
222
223 // // Bend
224
225 // var wlen = restDistance * 2;
226 // var hlen = restDistance * 2;
227 // diagonalDist = Math.sqrt(wlen * wlen + hlen * hlen);
228
229 // for (v=0;v<h-1;v++) {
230 // for (u=0;u<w-1;u++) {
231 // constrains.push([
232 // particles[index(u, v)],
233 // particles[index(u+2, v)],
234 // wlen
235 // ]);
236
237 // constrains.push([
238 // particles[index(u, v)],
239 // particles[index(u, v+2)],
240 // hlen
241 // ]);
242
243 // constrains.push([
244 // particles[index(u, v)],
245 // particles[index(u+2, v+2)],
246 // diagonalDist
247 // ]);
248
249 // constrains.push([
250 // particles[index(u, v+2)],
251 // particles[index(u+2, v+2)],
252 // wlen
253 // ]);
254
255 // constrains.push([
256 // particles[index(u+2, v+2)],
257 // particles[index(u+2, v+2)],
258 // hlen
259 // ]);
260
261 // constrains.push([
262 // particles[index(u+2, v)],
263 // particles[index(u, v+2)],
264 // diagonalDist
265 // ]);
266
267 // }
268 // }
269
270
271 this.particles = particles;
272 this.constrains = constrains;
273
274 function index(u, v) {
275 return u + v * (w + 1);
276 }
277
278 this.index = index;
279
280}
281
282function setPinning(bool){
283 pinning = bool;
284}
285
286function simulate(time) {
287 if (!lastTime) {
288 lastTime = time;
289 return;
290 }
291
292 // TIMESTEP = (time - lastTime);
293 // TIMESTEP = (TIMESTEP > 30) ? TIMESTEP / 1000 : 30 / 1000;
294 // TIMESTEP_SQ = TIMESTEP * TIMESTEP;
295 // lastTime = time;
296 // console.log(TIMESTEP);
297
298 var i, il, particles, particle, pt, constrains, constrain;
299
300 // Aerodynamics forces
301 if (wind) {
302 var face, faces = clothGeometry.faces, normal;
303
304 particles = cloth.particles;
305
306 for (i=0,il=faces.length;i<il;i++) {
307 face = faces[i];
308 normal = face.normal;
309
310 tmpForce.copy(normal).normalize().multiplyScalar(normal.dot(windForce));
311 particles[face.a].addForce(tmpForce);
312 particles[face.b].addForce(tmpForce);
313 particles[face.c].addForce(tmpForce);
314 }
315 }
316
317 for (particles = cloth.particles, i=0, il = particles.length
318 ;i<il;i++) {
319 particle = particles[i];
320 particle.addForce(gravity);
321 //
322 // var x = particle.position.x, y = particle.position.y, z = particle.position.z, t=Date.now() / 1000;
323 // windForce.set(Math.sin(x*y*t), Math.cos(z*t), Math.sin(Math.cos(5*x*y*z))).multiplyScalar(100);
324 // particle.addForce(windForce);
325 particle.integrate(TIMESTEP_SQ);
326 }
327
328 // Start Constrains
329
330 constrains = cloth.constrains,
331 il = constrains.length;
332 for (i=0;i<il;i++) {
333 constrain = constrains[i];
334 satisifyConstrains(constrain[0], constrain[1], constrain[2]);
335 }
336
337 // Ball Constrains
338
339
340 ballPosition.z = -Math.sin(Date.now()/300) * 90 ; //+ 40;
341 ballPosition.x = Math.cos(Date.now()/200) * 70
342
343 // Pin Constrains
344 if(Boolean(pinning)){
345 for (i=0, il=pins.length;i<il;i++) {
346 var xy = pins[i];
347 var p = particles[xy];
348 p.position.copy(p.original);
349 p.previous.copy(p.original);
350 }
351 }
352
353}
Note: See TracBrowser for help on using the repository browser.