Explorar o código

Examples: Move code from Cloth.js to the example.

Mugen87 %!s(int64=6) %!d(string=hai) anos
pai
achega
67b1fbd5db
Modificáronse 2 ficheiros con 361 adicións e 352 borrados
  1. 0 340
      examples/js/Cloth.js
  2. 361 12
      examples/webgl_animation_cloth.html

+ 0 - 340
examples/js/Cloth.js

@@ -1,340 +0,0 @@
-/*
- * Cloth Simulation using a relaxed constraints solver
- */
-
-// Suggested Readings
-
-// Advanced Character Physics by Thomas Jakobsen Character
-// http://freespace.virgin.net/hugo.elias/models/m_cloth.htm
-// http://en.wikipedia.org/wiki/Cloth_modeling
-// http://cg.alexandra.dk/tag/spring-mass-system/
-// Real-time Cloth Animation http://www.darwin3d.com/gamedev/articles/col0599.pdf
-
-var DAMPING = 0.03;
-var DRAG = 1 - DAMPING;
-var MASS = 0.1;
-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, target ) {
-
-		var x = ( u - 0.5 ) * width;
-		var y = ( v + 0.5 ) * height;
-		var z = 0;
-
-		target.set( x, y, z );
-
-	};
-
-}
-
-function Particle( x, y, z, mass ) {
-
-	this.position = new THREE.Vector3();
-	this.previous = new THREE.Vector3();
-	this.original = new THREE.Vector3();
-	this.a = new THREE.Vector3( 0, 0, 0 ); // acceleration
-	this.mass = mass;
-	this.invMass = 1 / mass;
-	this.tmp = new THREE.Vector3();
-	this.tmp2 = new THREE.Vector3();
-
-	// init
-
-	clothFunction( x, y, this.position ); // position
-	clothFunction( x, y, this.previous ); // previous
-	clothFunction( x, y, this.original );
-
-}
-
-// Force -> Acceleration
-
-Particle.prototype.addForce = function ( force ) {
-
-	this.a.add(
-		this.tmp2.copy( force ).multiplyScalar( this.invMass )
-	);
-
-};
-
-
-// Performs Verlet integration
-
-Particle.prototype.integrate = function ( timesq ) {
-
-	var newPos = this.tmp.subVectors( this.position, this.previous );
-	newPos.multiplyScalar( DRAG ).add( this.position );
-	newPos.add( this.a.multiplyScalar( timesq ) );
-
-	this.tmp = this.previous;
-	this.previous = this.position;
-	this.position = newPos;
-
-	this.a.set( 0, 0, 0 );
-
-};
-
-
-var diff = new THREE.Vector3();
-
-function satisfyConstraints( p1, p2, distance ) {
-
-	diff.subVectors( p2.position, p1.position );
-	var currentDist = diff.length();
-	if ( currentDist === 0 ) return; // prevents division by 0
-	var correction = diff.multiplyScalar( 1 - distance / currentDist );
-	var correctionHalf = correction.multiplyScalar( 0.5 );
-	p1.position.add( correctionHalf );
-	p2.position.sub( correctionHalf );
-
-}
-
-
-function Cloth( w, h ) {
-
-	w = w || 10;
-	h = h || 10;
-	this.w = w;
-	this.h = h;
-
-	var particles = [];
-	var constraints = [];
-
-	var u, v;
-
-	// Create particles
-	for ( v = 0; v <= h; v ++ ) {
-
-		for ( u = 0; u <= w; u ++ ) {
-
-			particles.push(
-				new Particle( u / w, v / h, 0, MASS )
-			);
-
-		}
-
-	}
-
-	// Structural
-
-	for ( v = 0; v < h; v ++ ) {
-
-		for ( u = 0; u < w; u ++ ) {
-
-			constraints.push( [
-				particles[ index( u, v ) ],
-				particles[ index( u, v + 1 ) ],
-				restDistance
-			] );
-
-			constraints.push( [
-				particles[ index( u, v ) ],
-				particles[ index( u + 1, v ) ],
-				restDistance
-			] );
-
-		}
-
-	}
-
-	for ( u = w, v = 0; v < h; v ++ ) {
-
-		constraints.push( [
-			particles[ index( u, v ) ],
-			particles[ index( u, v + 1 ) ],
-			restDistance
-
-		] );
-
-	}
-
-	for ( v = h, u = 0; u < w; u ++ ) {
-
-		constraints.push( [
-			particles[ index( u, v ) ],
-			particles[ index( u + 1, v ) ],
-			restDistance
-		] );
-
-	}
-
-
-	// While many systems use shear and bend springs,
-	// the relaxed constraints model seems to be just fine
-	// using structural springs.
-	// Shear
-	// var diagonalDist = Math.sqrt(restDistance * restDistance * 2);
-
-
-	// for (v=0;v<h;v++) {
-	// 	for (u=0;u<w;u++) {
-
-	// 		constraints.push([
-	// 			particles[index(u, v)],
-	// 			particles[index(u+1, v+1)],
-	// 			diagonalDist
-	// 		]);
-
-	// 		constraints.push([
-	// 			particles[index(u+1, v)],
-	// 			particles[index(u, v+1)],
-	// 			diagonalDist
-	// 		]);
-
-	// 	}
-	// }
-
-
-	this.particles = particles;
-	this.constraints = constraints;
-
-	function index( u, v ) {
-
-		return u + v * ( w + 1 );
-
-	}
-
-	this.index = index;
-
-}
-
-function simulate( time ) {
-
-	if ( ! lastTime ) {
-
-		lastTime = time;
-		return;
-
-	}
-
-	var i, il, particles, particle, pt, constraints, constraint;
-
-	// Aerodynamics forces
-
-	if ( wind ) {
-
-		var indx;
-		var normal = new THREE.Vector3();
-		var indices = clothGeometry.index;
-		var normals = clothGeometry.attributes.normal;
-
-		particles = cloth.particles;
-
-		for ( i = 0, il = indices.count; i < il; i += 3 ) {
-
-			for ( j = 0; j < 3; j ++ ) {
-
-				indx = indices.getX( i + j );
-				normal.fromBufferAttribute( normals, indx )
-				tmpForce.copy( normal ).normalize().multiplyScalar( normal.dot( windForce ) );
-				particles[ indx ].addForce( tmpForce );
-
-			}
-
-		}
-
-	}
-
-	for ( particles = cloth.particles, i = 0, il = particles.length; i < il; i ++ ) {
-
-		particle = particles[ i ];
-		particle.addForce( gravity );
-
-		particle.integrate( TIMESTEP_SQ );
-
-	}
-
-	// Start Constraints
-
-	constraints = cloth.constraints;
-	il = constraints.length;
-
-	for ( i = 0; i < il; i ++ ) {
-
-		constraint = constraints[ i ];
-		satisfyConstraints( constraint[ 0 ], constraint[ 1 ], constraint[ 2 ] );
-
-	}
-
-	// Ball Constraints
-
-	ballPosition.z = - Math.sin( Date.now() / 600 ) * 90; //+ 40;
-	ballPosition.x = Math.cos( Date.now() / 400 ) * 70;
-
-	if ( sphere.visible ) {
-
-		for ( particles = cloth.particles, i = 0, il = particles.length; i < il; i ++ ) {
-
-			particle = particles[ i ];
-			var pos = particle.position;
-			diff.subVectors( pos, ballPosition );
-			if ( diff.length() < ballSize ) {
-
-				// collided
-				diff.normalize().multiplyScalar( ballSize );
-				pos.copy( ballPosition ).add( diff );
-
-			}
-
-		}
-
-	}
-
-
-	// Floor Constraints
-
-	for ( particles = cloth.particles, i = 0, il = particles.length; i < il; i ++ ) {
-
-		particle = particles[ i ];
-		pos = particle.position;
-		if ( pos.y < - 250 ) {
-
-			pos.y = - 250;
-
-		}
-
-	}
-
-	// Pin Constraints
-
-	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 );
-
-	}
-
-
-}

+ 361 - 12
examples/webgl_animation_cloth.html

@@ -19,9 +19,6 @@
 	<body>
 		<div id="info">Simple Cloth Simulation<br/>
 			Verlet integration with relaxed constraints<br/>
-			<a onclick="wind = !wind;">Wind</a> |
-			<a onclick="sphere.visible = !sphere.visible;">Ball</a> |
-			<a onclick="togglePins();">Pins</a>
 		</div>
 
 		<script src="../build/three.js"></script>
@@ -29,11 +26,360 @@
 		<script src="js/WebGL.js"></script>
 		<script src="js/controls/OrbitControls.js"></script>
 		<script src="js/libs/stats.min.js"></script>
-
-		<script src="js/Cloth.js"></script>
+		<script src="js/libs/dat.gui.min.js"></script>
 
 		<script>
 
+			/*
+			 * Cloth Simulation using a relaxed constraints solver
+			 */
+
+			// Suggested Readings
+
+			// Advanced Character Physics by Thomas Jakobsen Character
+			// http://freespace.virgin.net/hugo.elias/models/m_cloth.htm
+			// http://en.wikipedia.org/wiki/Cloth_modeling
+			// http://cg.alexandra.dk/tag/spring-mass-system/
+			// Real-time Cloth Animation http://www.darwin3d.com/gamedev/articles/col0599.pdf
+
+			var params = {
+				enableWind: true,
+				showBall: false,
+				tooglePins: togglePins
+			};
+
+			var DAMPING = 0.03;
+			var DRAG = 1 - DAMPING;
+			var MASS = 0.1;
+			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 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, target ) {
+
+					var x = ( u - 0.5 ) * width;
+					var y = ( v + 0.5 ) * height;
+					var z = 0;
+
+					target.set( x, y, z );
+
+				};
+
+			}
+
+			function Particle( x, y, z, mass ) {
+
+				this.position = new THREE.Vector3();
+				this.previous = new THREE.Vector3();
+				this.original = new THREE.Vector3();
+				this.a = new THREE.Vector3( 0, 0, 0 ); // acceleration
+				this.mass = mass;
+				this.invMass = 1 / mass;
+				this.tmp = new THREE.Vector3();
+				this.tmp2 = new THREE.Vector3();
+
+				// init
+
+				clothFunction( x, y, this.position ); // position
+				clothFunction( x, y, this.previous ); // previous
+				clothFunction( x, y, this.original );
+
+			}
+
+			// Force -> Acceleration
+
+			Particle.prototype.addForce = function ( force ) {
+
+				this.a.add(
+					this.tmp2.copy( force ).multiplyScalar( this.invMass )
+				);
+
+			};
+
+
+			// Performs Verlet integration
+
+			Particle.prototype.integrate = function ( timesq ) {
+
+				var newPos = this.tmp.subVectors( this.position, this.previous );
+				newPos.multiplyScalar( DRAG ).add( this.position );
+				newPos.add( this.a.multiplyScalar( timesq ) );
+
+				this.tmp = this.previous;
+				this.previous = this.position;
+				this.position = newPos;
+
+				this.a.set( 0, 0, 0 );
+
+			};
+
+
+			var diff = new THREE.Vector3();
+
+			function satisfyConstraints( p1, p2, distance ) {
+
+				diff.subVectors( p2.position, p1.position );
+				var currentDist = diff.length();
+				if ( currentDist === 0 ) return; // prevents division by 0
+				var correction = diff.multiplyScalar( 1 - distance / currentDist );
+				var correctionHalf = correction.multiplyScalar( 0.5 );
+				p1.position.add( correctionHalf );
+				p2.position.sub( correctionHalf );
+
+			}
+
+
+			function Cloth( w, h ) {
+
+				w = w || 10;
+				h = h || 10;
+				this.w = w;
+				this.h = h;
+
+				var particles = [];
+				var constraints = [];
+
+				var u, v;
+
+				// Create particles
+				for ( v = 0; v <= h; v ++ ) {
+
+					for ( u = 0; u <= w; u ++ ) {
+
+						particles.push(
+							new Particle( u / w, v / h, 0, MASS )
+						);
+
+					}
+
+				}
+
+				// Structural
+
+				for ( v = 0; v < h; v ++ ) {
+
+					for ( u = 0; u < w; u ++ ) {
+
+						constraints.push( [
+							particles[ index( u, v ) ],
+							particles[ index( u, v + 1 ) ],
+							restDistance
+						] );
+
+						constraints.push( [
+							particles[ index( u, v ) ],
+							particles[ index( u + 1, v ) ],
+							restDistance
+						] );
+
+					}
+
+				}
+
+				for ( u = w, v = 0; v < h; v ++ ) {
+
+					constraints.push( [
+						particles[ index( u, v ) ],
+						particles[ index( u, v + 1 ) ],
+						restDistance
+
+					] );
+
+				}
+
+				for ( v = h, u = 0; u < w; u ++ ) {
+
+					constraints.push( [
+						particles[ index( u, v ) ],
+						particles[ index( u + 1, v ) ],
+						restDistance
+					] );
+
+				}
+
+
+				// While many systems use shear and bend springs,
+				// the relaxed constraints model seems to be just fine
+				// using structural springs.
+				// Shear
+				// var diagonalDist = Math.sqrt(restDistance * restDistance * 2);
+
+
+				// for (v=0;v<h;v++) {
+				// 	for (u=0;u<w;u++) {
+
+				// 		constraints.push([
+				// 			particles[index(u, v)],
+				// 			particles[index(u+1, v+1)],
+				// 			diagonalDist
+				// 		]);
+
+				// 		constraints.push([
+				// 			particles[index(u+1, v)],
+				// 			particles[index(u, v+1)],
+				// 			diagonalDist
+				// 		]);
+
+				// 	}
+				// }
+
+
+				this.particles = particles;
+				this.constraints = constraints;
+
+				function index( u, v ) {
+
+					return u + v * ( w + 1 );
+
+				}
+
+				this.index = index;
+
+			}
+
+			function simulate( time ) {
+
+				if ( ! lastTime ) {
+
+					lastTime = time;
+					return;
+
+				}
+
+				var i, j, il, particles, particle, constraints, constraint;
+
+				// Aerodynamics forces
+
+				if ( params.enableWind ) {
+
+					var indx;
+					var normal = new THREE.Vector3();
+					var indices = clothGeometry.index;
+					var normals = clothGeometry.attributes.normal;
+
+					particles = cloth.particles;
+
+					for ( i = 0, il = indices.count; i < il; i += 3 ) {
+
+						for ( j = 0; j < 3; j ++ ) {
+
+							indx = indices.getX( i + j );
+							normal.fromBufferAttribute( normals, indx );
+							tmpForce.copy( normal ).normalize().multiplyScalar( normal.dot( windForce ) );
+							particles[ indx ].addForce( tmpForce );
+
+						}
+
+					}
+
+				}
+
+				for ( particles = cloth.particles, i = 0, il = particles.length; i < il; i ++ ) {
+
+					particle = particles[ i ];
+					particle.addForce( gravity );
+
+					particle.integrate( TIMESTEP_SQ );
+
+				}
+
+				// Start Constraints
+
+				constraints = cloth.constraints;
+				il = constraints.length;
+
+				for ( i = 0; i < il; i ++ ) {
+
+					constraint = constraints[ i ];
+					satisfyConstraints( constraint[ 0 ], constraint[ 1 ], constraint[ 2 ] );
+
+				}
+
+				// Ball Constraints
+
+				ballPosition.z = - Math.sin( Date.now() / 600 ) * 90; //+ 40;
+				ballPosition.x = Math.cos( Date.now() / 400 ) * 70;
+
+				if ( params.showBall ) {
+
+					sphere.visible = true;
+
+					for ( particles = cloth.particles, i = 0, il = particles.length; i < il; i ++ ) {
+
+						particle = particles[ i ];
+						var pos = particle.position;
+						diff.subVectors( pos, ballPosition );
+						if ( diff.length() < ballSize ) {
+
+							// collided
+							diff.normalize().multiplyScalar( ballSize );
+							pos.copy( ballPosition ).add( diff );
+
+						}
+
+					}
+
+				} else {
+
+					sphere.visible = false;
+
+				}
+
+
+				// Floor Constraints
+
+				for ( particles = cloth.particles, i = 0, il = particles.length; i < il; i ++ ) {
+
+					particle = particles[ i ];
+					pos = particle.position;
+					if ( pos.y < - 250 ) {
+
+						pos.y = - 250;
+
+					}
+
+				}
+
+				// Pin Constraints
+
+				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 );
+
+				}
+
+
+			}
+
 			/* testing cloth simulation */
 
 			var pinsFormation = [];
@@ -55,10 +401,9 @@
 
 			pins = pinsFormation[ 1 ];
 
-
 			function togglePins() {
 
-				pins = pinsFormation[ ~~ ( Math.random() * pinsFormation.length ) ];
+				pins = pinsFormation[ ~ ~ ( Math.random() * pinsFormation.length ) ];
 
 			}
 
@@ -142,11 +487,9 @@
 				scene.add( object );
 
 				object.customDepthMaterial = new THREE.MeshDepthMaterial( {
-
 					depthPacking: THREE.RGBADepthPacking,
 					map: clothTexture,
 					alphaTest: 0.5
-
 				} );
 
 				// sphere
@@ -157,6 +500,7 @@
 				sphere = new THREE.Mesh( ballGeo, ballMaterial );
 				sphere.castShadow = true;
 				sphere.receiveShadow = true;
+				sphere.visible = false;
 				scene.add( sphere );
 
 				// ground
@@ -243,7 +587,12 @@
 
 				window.addEventListener( 'resize', onWindowResize, false );
 
-				sphere.visible = ! true;
+				//
+
+				var gui = new dat.GUI();
+				gui.add( params, 'enableWind' );
+				gui.add( params, 'showBall' );
+				gui.add( params, 'tooglePins' );
 
 			}
 
@@ -268,8 +617,8 @@
 
 				var windStrength = Math.cos( time / 7000 ) * 20 + 40;
 
-				windForce.set( Math.sin( time / 2000 ), Math.cos( time / 3000 ), Math.sin( time / 1000 ) )
-				windForce.normalize()
+				windForce.set( Math.sin( time / 2000 ), Math.cos( time / 3000 ), Math.sin( time / 1000 ) );
+				windForce.normalize();
 				windForce.multiplyScalar( windStrength );
 
 				simulate( time );