提交 a8853b88 编写于 作者: Z zz85 提交者: Mr.doob

Tweaked the cloth simulation example a little.

上级 438b7b74
/* /*
* Aug 3 2012 * Cloth Simulation using a relaxed constrains solver
*
* Since I started working for a new startup not too long ago,
* I commute between home and work for over 2 hours a day.
* Although this means less time on three.js,
* I try getting a little coding on the train.
*
* This set of experiments started from a simple hook's law doodle,
* to spring simulation, string simulation, and I realized
* I once again stepped onto physics and particle simulation,
* this time, more specifically soft body physics.
*
* Based on the "Advanced Character Physics" article,
* this experiment attempts to use a "massless"
* cloth simulation model. It's somewhat similiar
* but simplier to most cloth simulations I found.
*
* This was coded out fairly quickly, so expect more to come
* meanwhile feel free to experiment yourself and share
*
* Cheers,
* Graphics Noob (aka @Blurspline, zz85)
*/ */
// Suggested Readings // Suggested Readings
...@@ -31,14 +10,56 @@ ...@@ -31,14 +10,56 @@
// http://cg.alexandra.dk/tag/spring-mass-system/ // http://cg.alexandra.dk/tag/spring-mass-system/
// Real-time Cloth Animation http://www.darwin3d.com/gamedev/articles/col0599.pdf // Real-time Cloth Animation http://www.darwin3d.com/gamedev/articles/col0599.pdf
var DAMPING = 0.01; var DAMPING = 0.03;
var DRAG = 1 - DAMPING; var DRAG = 1 - DAMPING;
var MASS = .1; var MASS = .1;
var restDistance = 25; // var restDistance = 25;
var xSegs = 10; //
var ySegs = 10; //
var clothFunction = plane(restDistance * xSegs, restDistance * ySegs);
var cloth = new Cloth(xSegs, ySegs);
var GRAVITY = 981 * 1.4; //
var gravity = new THREE.Vector3( 0, -GRAVITY, 0 ).multiplyScalar(MASS);
var TIMESTEP = 18 / 1000;
var TIMESTEP_SQ = TIMESTEP * TIMESTEP;
var pins = [];
var wind = true;
var windStrength = 2;
var windForce = new THREE.Vector3(0,0,0);
var ballPosition = new THREE.Vector3(0, -45, 0);
var ballSize = 60; //40
var tmpForce = new THREE.Vector3();
var lastTime;
function plane(width, height) {
return function(u, v) {
var x = (u-0.5) * width;
var y = (v+0.5) * height;
var z = 0;
return new THREE.Vector3(x, y, z);
};
}
function Particle(x, y, z, mass) { function Particle(x, y, z, mass) {
this.position = new THREE.Vector3(x, y, z); // position this.position = clothFunction(x, y); // position
this.previous = new THREE.Vector3(x, y, z); // previous this.previous = clothFunction(x, y); // previous
this.original = clothFunction(x, y);
this.a = new THREE.Vector3(0, 0, 0); // acceleration this.a = new THREE.Vector3(0, 0, 0); // acceleration
this.mass = mass; this.mass = mass;
this.invMass = 1 / mass; this.invMass = 1 / mass;
...@@ -78,12 +99,6 @@ function satisifyConstrains(p1, p2, distance) { ...@@ -78,12 +99,6 @@ function satisifyConstrains(p1, p2, distance) {
var correctionHalf = correction.multiplyScalar(0.5); var correctionHalf = correction.multiplyScalar(0.5);
p1.position.addSelf(correctionHalf); p1.position.addSelf(correctionHalf);
p2.position.subSelf(correctionHalf); p2.position.subSelf(correctionHalf);
// float difference = (restingDistance - d) / d
// im1 = 1 / p1.mass // inverse mass quantities
// im2 = 1 / p2.mass
// p1.position += delta * (im1 / (im1 + im2)) * stiffness * difference
} }
...@@ -102,7 +117,7 @@ function Cloth(w, h) { ...@@ -102,7 +117,7 @@ function Cloth(w, h) {
for (v=0;v<=h;v++) { for (v=0;v<=h;v++) {
for (u=0;u<=w;u++) { for (u=0;u<=w;u++) {
particles.push( particles.push(
new Particle((u - w/2) * restDistance, (v - h/2) * -restDistance, 0, MASS) new Particle(u/w, v/h, 0, MASS)
); );
} }
} }
...@@ -148,7 +163,7 @@ function Cloth(w, h) { ...@@ -148,7 +163,7 @@ function Cloth(w, h) {
// While many system uses shear and bend springs, // While many system uses shear and bend springs,
// the relax constrains model seem to be just fine // the relax constrains model seem to be just fine
// using structural springs. // using structural springs.
// // Shear // Shear
// var diagonalDist = Math.sqrt(restDistance * restDistance * 2); // var diagonalDist = Math.sqrt(restDistance * restDistance * 2);
...@@ -171,54 +186,6 @@ function Cloth(w, h) { ...@@ -171,54 +186,6 @@ function Cloth(w, h) {
// } // }
// // Bend
// var wlen = restDistance * 2;
// var hlen = restDistance * 2;
// diagonalDist = Math.sqrt(wlen * wlen + hlen * hlen);
// for (v=0;v<h-1;v++) {
// for (u=0;u<w-1;u++) {
// constrains.push([
// particles[index(u, v)],
// particles[index(u+2, v)],
// wlen
// ]);
// constrains.push([
// particles[index(u, v)],
// particles[index(u, v+2)],
// hlen
// ]);
// constrains.push([
// particles[index(u, v)],
// particles[index(u+2, v+2)],
// diagonalDist
// ]);
// constrains.push([
// particles[index(u, v+2)],
// particles[index(u+2, v+2)],
// wlen
// ]);
// constrains.push([
// particles[index(u+2, v+2)],
// particles[index(u+2, v+2)],
// hlen
// ]);
// constrains.push([
// particles[index(u+2, v)],
// particles[index(u, v+2)],
// diagonalDist
// ]);
// }
// }
this.particles = particles; this.particles = particles;
this.constrains = constrains; this.constrains = constrains;
...@@ -226,32 +193,15 @@ function Cloth(w, h) { ...@@ -226,32 +193,15 @@ function Cloth(w, h) {
return u + v * (w + 1); return u + v * (w + 1);
} }
this.index = index;
} }
var cloth = new Cloth(); function simulate(time) {
if (!lastTime) {
var GRAVITY = 981; // lastTime = time;
var gravity = new THREE.Vector3( 0, -GRAVITY, 0 ).multiplyScalar(MASS); return;
}
var TIMESTEP = 14 / 1000;
var TIMESTEP_SQ = TIMESTEP * TIMESTEP;
var pins = [true];
pins[cloth.w] = true;
var wind = true;
var windStrength = 2;
var windForce = new THREE.Vector3(0,0,0);
var ballPosition = new THREE.Vector3(0, -45, 0);
var ballSize = 60; //40
var tmpForce = new THREE.Vector3();
function simulate() {
var i, il, particles, particle, pt, constrains, constrain; var i, il, particles, particle, pt, constrains, constrain;
...@@ -276,7 +226,7 @@ function simulate() { ...@@ -276,7 +226,7 @@ function simulate() {
;i<il;i++) { ;i<il;i++) {
particle = particles[i]; particle = particles[i];
particle.addForce(gravity); particle.addForce(gravity);
// particle.addForce(windForce);
particle.integrate(TIMESTEP_SQ); particle.integrate(TIMESTEP_SQ);
} }
...@@ -292,8 +242,8 @@ function simulate() { ...@@ -292,8 +242,8 @@ function simulate() {
// Ball Constrains // Ball Constrains
ballPosition.z = -Math.sin(Date.now()/300) * 90 ; //+ 40; ballPosition.z = -Math.sin(Date.now()/600) * 90 ; //+ 40;
ballPosition.x = Math.cos(Date.now()/200) * 70 ballPosition.x = Math.cos(Date.now()/400) * 70
if (sphere.visible) if (sphere.visible)
for (particles = cloth.particles, i=0, il = particles.length for (particles = cloth.particles, i=0, il = particles.length
...@@ -308,15 +258,23 @@ function simulate() { ...@@ -308,15 +258,23 @@ function simulate() {
} }
} }
// Pin Constrains // Floor Constains
for (particles = cloth.particles, i=0, il = particles.length
for (i=0, il=cloth.w;i<=il;i++) { ;i<il;i++) {
if (pins[i]) { particle = particles[i];
particle = particles[i]; pos = particle.position;
particle.previous.set((i - cloth.w/2) * restDistance, -cloth.h/2 * -restDistance, 0); if (pos.y < -250) {
particle.position.copy(particle.previous); pos.y = -250;
} }
} }
// Pin Constrains
for (i=0, il=pins.length;i<il;i++) {
var xy = pins[i];
var p = particles[xy];
p.position.copy(p.original);
p.previous.copy(p.original);
}
} }
\ No newline at end of file
...@@ -29,8 +29,8 @@ ...@@ -29,8 +29,8 @@
</head> </head>
<body> <body>
<div id="info">Simple Cloth Simulation #3<br/> <div id="info">Simple Cloth Simulation<br/>
Verlet based with Constrains relaxation<br/> Verlet integration with Constrains relaxation<br/>
Toggle: <a onclick="rotate = !rotate;">Camera</a> | Toggle: <a onclick="rotate = !rotate;">Camera</a> |
<a onclick="wind = !wind;">Wind</a> | <a onclick="wind = !wind;">Wind</a> |
<a onclick="sphere.visible = !sphere.visible;">Ball</a> | <a onclick="sphere.visible = !sphere.visible;">Ball</a> |
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
<script src="js/Detector.js"></script> <script src="js/Detector.js"></script>
<script src="js/Stats.js"></script> <script src="js/Stats.js"></script>
<script src="js/ParametricGeometries.js"></script>
<script src="js/Cloth.js"></script> <script src="js/Cloth.js"></script>
<script type="x-shader/x-fragment" id="fragmentShaderDepth"> <script type="x-shader/x-fragment" id="fragmentShaderDepth">
...@@ -92,22 +91,20 @@ ...@@ -92,22 +91,20 @@
/* testing cloth simulation */ /* testing cloth simulation */
var pinsFormation = []; var pinsFormation = [];
var pins = []; var pins = [6];
pins[6] = true;
pinsFormation.push( pins ); pinsFormation.push( pins );
pins = [ true, true, true, true, true, true, true, true, true, true, true, true ]; pins = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
pinsFormation.push( pins ); pinsFormation.push( pins );
pins = [ true ]; pins = [ 0 ];
pinsFormation.push( pins ); pinsFormation.push( pins );
pins = []; // cut the rope ;) pins = []; // cut the rope ;)
pinsFormation.push( pins ); pinsFormation.push( pins );
pins = [ true ]; // classic 2 pins pins = [ 0, cloth.w ]; // classic 2 pins
pins[ cloth.w ] = true;
pinsFormation.push( pins ); pinsFormation.push( pins );
pins = pinsFormation[ 1 ]; pins = pinsFormation[ 1 ];
...@@ -199,8 +196,7 @@ ...@@ -199,8 +196,7 @@
]; ];
// cloth geometry // cloth geometry
clothGeometry = new THREE.ParametricGeometry( clothFunction, cloth.w, cloth.h, true );
clothGeometry = new THREE.ParametricGeometry( THREE.ParametricGeometries.plane( 200, 200 ), cloth.w, cloth.h, true );
clothGeometry.dynamic = true; clothGeometry.dynamic = true;
clothGeometry.computeFaceNormals(); clothGeometry.computeFaceNormals();
...@@ -357,7 +353,7 @@ ...@@ -357,7 +353,7 @@
arrow.setLength( windStrength ); arrow.setLength( windStrength );
arrow.setDirection( windForce ); arrow.setDirection( windForce );
simulate(); simulate(time);
render(); render();
stats.update(); stats.update();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册