|
@@ -42,48 +42,48 @@
|
|
|
// http://cg.alexandra.dk/tag/spring-mass-system/
|
|
|
// Real-time Cloth Animation http://www.darwin3d.com/gamedev/articles/col0599.pdf
|
|
|
|
|
|
- var params = {
|
|
|
+ const params = {
|
|
|
enableWind: true,
|
|
|
showBall: false,
|
|
|
togglePins: togglePins
|
|
|
};
|
|
|
|
|
|
- var DAMPING = 0.03;
|
|
|
- var DRAG = 1 - DAMPING;
|
|
|
- var MASS = 0.1;
|
|
|
- var restDistance = 25;
|
|
|
+ const DAMPING = 0.03;
|
|
|
+ const DRAG = 1 - DAMPING;
|
|
|
+ const MASS = 0.1;
|
|
|
+ const restDistance = 25;
|
|
|
|
|
|
- var xSegs = 10;
|
|
|
- var ySegs = 10;
|
|
|
+ const xSegs = 10;
|
|
|
+ const ySegs = 10;
|
|
|
|
|
|
- var clothFunction = plane( restDistance * xSegs, restDistance * ySegs );
|
|
|
+ const clothFunction = plane( restDistance * xSegs, restDistance * ySegs );
|
|
|
|
|
|
- var cloth = new Cloth( xSegs, ySegs );
|
|
|
+ const cloth = new Cloth( xSegs, ySegs );
|
|
|
|
|
|
- var GRAVITY = 981 * 1.4;
|
|
|
- var gravity = new THREE.Vector3( 0, - GRAVITY, 0 ).multiplyScalar( MASS );
|
|
|
+ const GRAVITY = 981 * 1.4;
|
|
|
+ const gravity = new THREE.Vector3( 0, - GRAVITY, 0 ).multiplyScalar( MASS );
|
|
|
|
|
|
|
|
|
- var TIMESTEP = 18 / 1000;
|
|
|
- var TIMESTEP_SQ = TIMESTEP * TIMESTEP;
|
|
|
+ const TIMESTEP = 18 / 1000;
|
|
|
+ const TIMESTEP_SQ = TIMESTEP * TIMESTEP;
|
|
|
|
|
|
- var pins = [];
|
|
|
+ let pins = [];
|
|
|
|
|
|
- var windForce = new THREE.Vector3( 0, 0, 0 );
|
|
|
+ const windForce = new THREE.Vector3( 0, 0, 0 );
|
|
|
|
|
|
- var ballPosition = new THREE.Vector3( 0, - 45, 0 );
|
|
|
- var ballSize = 60; //40
|
|
|
+ const ballPosition = new THREE.Vector3( 0, - 45, 0 );
|
|
|
+ const ballSize = 60; //40
|
|
|
|
|
|
- var tmpForce = new THREE.Vector3();
|
|
|
+ const tmpForce = new THREE.Vector3();
|
|
|
|
|
|
|
|
|
function plane( width, height ) {
|
|
|
|
|
|
return function ( u, v, target ) {
|
|
|
|
|
|
- var x = ( u - 0.5 ) * width;
|
|
|
- var y = ( v + 0.5 ) * height;
|
|
|
- var z = 0;
|
|
|
+ const x = ( u - 0.5 ) * width;
|
|
|
+ const y = ( v + 0.5 ) * height;
|
|
|
+ const z = 0;
|
|
|
|
|
|
target.set( x, y, z );
|
|
|
|
|
@@ -125,7 +125,7 @@
|
|
|
|
|
|
Particle.prototype.integrate = function ( timesq ) {
|
|
|
|
|
|
- var newPos = this.tmp.subVectors( this.position, this.previous );
|
|
|
+ const newPos = this.tmp.subVectors( this.position, this.previous );
|
|
|
newPos.multiplyScalar( DRAG ).add( this.position );
|
|
|
newPos.add( this.a.multiplyScalar( timesq ) );
|
|
|
|
|
@@ -138,15 +138,15 @@
|
|
|
};
|
|
|
|
|
|
|
|
|
- var diff = new THREE.Vector3();
|
|
|
+ const diff = new THREE.Vector3();
|
|
|
|
|
|
function satisfyConstraints( p1, p2, distance ) {
|
|
|
|
|
|
diff.subVectors( p2.position, p1.position );
|
|
|
- var currentDist = diff.length();
|
|
|
+ const currentDist = diff.length();
|
|
|
if ( currentDist === 0 ) return; // prevents division by 0
|
|
|
- var correction = diff.multiplyScalar( 1 - distance / currentDist );
|
|
|
- var correctionHalf = correction.multiplyScalar( 0.5 );
|
|
|
+ const correction = diff.multiplyScalar( 1 - distance / currentDist );
|
|
|
+ const correctionHalf = correction.multiplyScalar( 0.5 );
|
|
|
p1.position.add( correctionHalf );
|
|
|
p2.position.sub( correctionHalf );
|
|
|
|
|
@@ -160,15 +160,13 @@
|
|
|
this.w = w;
|
|
|
this.h = h;
|
|
|
|
|
|
- var particles = [];
|
|
|
- var constraints = [];
|
|
|
-
|
|
|
- var u, v;
|
|
|
+ const particles = [];
|
|
|
+ const constraints = [];
|
|
|
|
|
|
// Create particles
|
|
|
- for ( v = 0; v <= h; v ++ ) {
|
|
|
+ for ( let v = 0; v <= h; v ++ ) {
|
|
|
|
|
|
- for ( u = 0; u <= w; u ++ ) {
|
|
|
+ for ( let u = 0; u <= w; u ++ ) {
|
|
|
|
|
|
particles.push(
|
|
|
new Particle( u / w, v / h, 0, MASS )
|
|
@@ -180,9 +178,9 @@
|
|
|
|
|
|
// Structural
|
|
|
|
|
|
- for ( v = 0; v < h; v ++ ) {
|
|
|
+ for ( let v = 0; v < h; v ++ ) {
|
|
|
|
|
|
- for ( u = 0; u < w; u ++ ) {
|
|
|
+ for ( let u = 0; u < w; u ++ ) {
|
|
|
|
|
|
constraints.push( [
|
|
|
particles[ index( u, v ) ],
|
|
@@ -200,7 +198,7 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
- for ( u = w, v = 0; v < h; v ++ ) {
|
|
|
+ for ( let u = w, v = 0; v < h; v ++ ) {
|
|
|
|
|
|
constraints.push( [
|
|
|
particles[ index( u, v ) ],
|
|
@@ -211,7 +209,7 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
- for ( v = h, u = 0; u < w; u ++ ) {
|
|
|
+ for ( let v = h, u = 0; u < w; u ++ ) {
|
|
|
|
|
|
constraints.push( [
|
|
|
particles[ index( u, v ) ],
|
|
@@ -226,7 +224,7 @@
|
|
|
// the relaxed constraints model seems to be just fine
|
|
|
// using structural springs.
|
|
|
// Shear
|
|
|
- // var diagonalDist = Math.sqrt(restDistance * restDistance * 2);
|
|
|
+ // const diagonalDist = Math.sqrt(restDistance * restDistance * 2);
|
|
|
|
|
|
|
|
|
// for (v=0;v<h;v++) {
|
|
@@ -263,28 +261,26 @@
|
|
|
|
|
|
function simulate( now ) {
|
|
|
|
|
|
- var windStrength = Math.cos( now / 7000 ) * 20 + 40;
|
|
|
+ const windStrength = Math.cos( now / 7000 ) * 20 + 40;
|
|
|
|
|
|
windForce.set( Math.sin( now / 2000 ), Math.cos( now / 3000 ), Math.sin( now / 1000 ) );
|
|
|
windForce.normalize();
|
|
|
windForce.multiplyScalar( windStrength );
|
|
|
|
|
|
- var i, j, il, particles, particle, constraints, constraint;
|
|
|
-
|
|
|
// Aerodynamics forces
|
|
|
|
|
|
- if ( params.enableWind ) {
|
|
|
+ const particles = cloth.particles;
|
|
|
|
|
|
- var indx;
|
|
|
- var normal = new THREE.Vector3();
|
|
|
- var indices = clothGeometry.index;
|
|
|
- var normals = clothGeometry.attributes.normal;
|
|
|
+ if ( params.enableWind ) {
|
|
|
|
|
|
- particles = cloth.particles;
|
|
|
+ let indx;
|
|
|
+ const normal = new THREE.Vector3();
|
|
|
+ const indices = clothGeometry.index;
|
|
|
+ const normals = clothGeometry.attributes.normal;
|
|
|
|
|
|
- for ( i = 0, il = indices.count; i < il; i += 3 ) {
|
|
|
+ for ( let i = 0, il = indices.count; i < il; i += 3 ) {
|
|
|
|
|
|
- for ( j = 0; j < 3; j ++ ) {
|
|
|
+ for ( let j = 0; j < 3; j ++ ) {
|
|
|
|
|
|
indx = indices.getX( i + j );
|
|
|
normal.fromBufferAttribute( normals, indx );
|
|
@@ -297,9 +293,9 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
- for ( particles = cloth.particles, i = 0, il = particles.length; i < il; i ++ ) {
|
|
|
+ for ( let i = 0, il = particles.length; i < il; i ++ ) {
|
|
|
|
|
|
- particle = particles[ i ];
|
|
|
+ const particle = particles[ i ];
|
|
|
particle.addForce( gravity );
|
|
|
|
|
|
particle.integrate( TIMESTEP_SQ );
|
|
@@ -308,12 +304,12 @@
|
|
|
|
|
|
// Start Constraints
|
|
|
|
|
|
- constraints = cloth.constraints;
|
|
|
- il = constraints.length;
|
|
|
+ const constraints = cloth.constraints;
|
|
|
+ const il = constraints.length;
|
|
|
|
|
|
- for ( i = 0; i < il; i ++ ) {
|
|
|
+ for ( let i = 0; i < il; i ++ ) {
|
|
|
|
|
|
- constraint = constraints[ i ];
|
|
|
+ const constraint = constraints[ i ];
|
|
|
satisfyConstraints( constraint[ 0 ], constraint[ 1 ], constraint[ 2 ] );
|
|
|
|
|
|
}
|
|
@@ -327,10 +323,10 @@
|
|
|
|
|
|
sphere.visible = true;
|
|
|
|
|
|
- for ( particles = cloth.particles, i = 0, il = particles.length; i < il; i ++ ) {
|
|
|
+ for ( let i = 0, il = particles.length; i < il; i ++ ) {
|
|
|
|
|
|
- particle = particles[ i ];
|
|
|
- var pos = particle.position;
|
|
|
+ const particle = particles[ i ];
|
|
|
+ const pos = particle.position;
|
|
|
diff.subVectors( pos, ballPosition );
|
|
|
if ( diff.length() < ballSize ) {
|
|
|
|
|
@@ -351,10 +347,10 @@
|
|
|
|
|
|
// Floor Constraints
|
|
|
|
|
|
- for ( particles = cloth.particles, i = 0, il = particles.length; i < il; i ++ ) {
|
|
|
+ for ( let i = 0, il = particles.length; i < il; i ++ ) {
|
|
|
|
|
|
- particle = particles[ i ];
|
|
|
- pos = particle.position;
|
|
|
+ const particle = particles[ i ];
|
|
|
+ const pos = particle.position;
|
|
|
if ( pos.y < - 250 ) {
|
|
|
|
|
|
pos.y = - 250;
|
|
@@ -365,10 +361,10 @@
|
|
|
|
|
|
// Pin Constraints
|
|
|
|
|
|
- for ( i = 0, il = pins.length; i < il; i ++ ) {
|
|
|
+ for ( let i = 0, il = pins.length; i < il; i ++ ) {
|
|
|
|
|
|
- var xy = pins[ i ];
|
|
|
- var p = particles[ xy ];
|
|
|
+ const xy = pins[ i ];
|
|
|
+ const p = particles[ xy ];
|
|
|
p.position.copy( p.original );
|
|
|
p.previous.copy( p.original );
|
|
|
|
|
@@ -379,8 +375,8 @@
|
|
|
|
|
|
/* testing cloth simulation */
|
|
|
|
|
|
- var pinsFormation = [];
|
|
|
- var pins = [ 6 ];
|
|
|
+ const pinsFormation = [];
|
|
|
+ pins = [ 6 ];
|
|
|
|
|
|
pinsFormation.push( pins );
|
|
|
|
|
@@ -404,12 +400,12 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
- var container, stats;
|
|
|
- var camera, scene, renderer;
|
|
|
+ let container, stats;
|
|
|
+ let camera, scene, renderer;
|
|
|
|
|
|
- var clothGeometry;
|
|
|
- var sphere;
|
|
|
- var object;
|
|
|
+ let clothGeometry;
|
|
|
+ let sphere;
|
|
|
+ let object;
|
|
|
|
|
|
init();
|
|
|
animate( 0 );
|
|
@@ -434,7 +430,7 @@
|
|
|
|
|
|
scene.add( new THREE.AmbientLight( 0x666666 ) );
|
|
|
|
|
|
- var light = new THREE.DirectionalLight( 0xdfebff, 1 );
|
|
|
+ const light = new THREE.DirectionalLight( 0xdfebff, 1 );
|
|
|
light.position.set( 50, 200, 100 );
|
|
|
light.position.multiplyScalar( 1.3 );
|
|
|
|
|
@@ -443,7 +439,7 @@
|
|
|
light.shadow.mapSize.width = 1024;
|
|
|
light.shadow.mapSize.height = 1024;
|
|
|
|
|
|
- var d = 300;
|
|
|
+ const d = 300;
|
|
|
|
|
|
light.shadow.camera.left = - d;
|
|
|
light.shadow.camera.right = d;
|
|
@@ -456,11 +452,11 @@
|
|
|
|
|
|
// cloth material
|
|
|
|
|
|
- var loader = new THREE.TextureLoader();
|
|
|
- var clothTexture = loader.load( 'textures/patterns/circuit_pattern.png' );
|
|
|
+ const loader = new THREE.TextureLoader();
|
|
|
+ const clothTexture = loader.load( 'textures/patterns/circuit_pattern.png' );
|
|
|
clothTexture.anisotropy = 16;
|
|
|
|
|
|
- var clothMaterial = new THREE.MeshLambertMaterial( {
|
|
|
+ const clothMaterial = new THREE.MeshLambertMaterial( {
|
|
|
map: clothTexture,
|
|
|
side: THREE.DoubleSide,
|
|
|
alphaTest: 0.5
|
|
@@ -485,8 +481,8 @@
|
|
|
|
|
|
// sphere
|
|
|
|
|
|
- var ballGeo = new THREE.SphereBufferGeometry( ballSize, 32, 16 );
|
|
|
- var ballMaterial = new THREE.MeshLambertMaterial();
|
|
|
+ const ballGeo = new THREE.SphereBufferGeometry( ballSize, 32, 16 );
|
|
|
+ const ballMaterial = new THREE.MeshLambertMaterial();
|
|
|
|
|
|
sphere = new THREE.Mesh( ballGeo, ballMaterial );
|
|
|
sphere.castShadow = true;
|
|
@@ -496,15 +492,15 @@
|
|
|
|
|
|
// ground
|
|
|
|
|
|
- var groundTexture = loader.load( 'textures/terrain/grasslight-big.jpg' );
|
|
|
+ const groundTexture = loader.load( 'textures/terrain/grasslight-big.jpg' );
|
|
|
groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
|
|
|
groundTexture.repeat.set( 25, 25 );
|
|
|
groundTexture.anisotropy = 16;
|
|
|
groundTexture.encoding = THREE.sRGBEncoding;
|
|
|
|
|
|
- var groundMaterial = new THREE.MeshLambertMaterial( { map: groundTexture } );
|
|
|
+ const groundMaterial = new THREE.MeshLambertMaterial( { map: groundTexture } );
|
|
|
|
|
|
- var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 20000, 20000 ), groundMaterial );
|
|
|
+ let mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 20000, 20000 ), groundMaterial );
|
|
|
mesh.position.y = - 250;
|
|
|
mesh.rotation.x = - Math.PI / 2;
|
|
|
mesh.receiveShadow = true;
|
|
@@ -512,39 +508,39 @@
|
|
|
|
|
|
// poles
|
|
|
|
|
|
- var poleGeo = new THREE.BoxBufferGeometry( 5, 375, 5 );
|
|
|
- var poleMat = new THREE.MeshLambertMaterial();
|
|
|
+ const poleGeo = new THREE.BoxBufferGeometry( 5, 375, 5 );
|
|
|
+ const poleMat = new THREE.MeshLambertMaterial();
|
|
|
|
|
|
- var mesh = new THREE.Mesh( poleGeo, poleMat );
|
|
|
+ mesh = new THREE.Mesh( poleGeo, poleMat );
|
|
|
mesh.position.x = - 125;
|
|
|
mesh.position.y = - 62;
|
|
|
mesh.receiveShadow = true;
|
|
|
mesh.castShadow = true;
|
|
|
scene.add( mesh );
|
|
|
|
|
|
- var mesh = new THREE.Mesh( poleGeo, poleMat );
|
|
|
+ mesh = new THREE.Mesh( poleGeo, poleMat );
|
|
|
mesh.position.x = 125;
|
|
|
mesh.position.y = - 62;
|
|
|
mesh.receiveShadow = true;
|
|
|
mesh.castShadow = true;
|
|
|
scene.add( mesh );
|
|
|
|
|
|
- var mesh = new THREE.Mesh( new THREE.BoxBufferGeometry( 255, 5, 5 ), poleMat );
|
|
|
+ mesh = new THREE.Mesh( new THREE.BoxBufferGeometry( 255, 5, 5 ), poleMat );
|
|
|
mesh.position.y = - 250 + ( 750 / 2 );
|
|
|
mesh.position.x = 0;
|
|
|
mesh.receiveShadow = true;
|
|
|
mesh.castShadow = true;
|
|
|
scene.add( mesh );
|
|
|
|
|
|
- var gg = new THREE.BoxBufferGeometry( 10, 10, 10 );
|
|
|
- var mesh = new THREE.Mesh( gg, poleMat );
|
|
|
+ const gg = new THREE.BoxBufferGeometry( 10, 10, 10 );
|
|
|
+ mesh = new THREE.Mesh( gg, poleMat );
|
|
|
mesh.position.y = - 250;
|
|
|
mesh.position.x = 125;
|
|
|
mesh.receiveShadow = true;
|
|
|
mesh.castShadow = true;
|
|
|
scene.add( mesh );
|
|
|
|
|
|
- var mesh = new THREE.Mesh( gg, poleMat );
|
|
|
+ mesh = new THREE.Mesh( gg, poleMat );
|
|
|
mesh.position.y = - 250;
|
|
|
mesh.position.x = - 125;
|
|
|
mesh.receiveShadow = true;
|
|
@@ -564,7 +560,7 @@
|
|
|
renderer.shadowMap.enabled = true;
|
|
|
|
|
|
// controls
|
|
|
- var controls = new OrbitControls( camera, renderer.domElement );
|
|
|
+ const controls = new OrbitControls( camera, renderer.domElement );
|
|
|
controls.maxPolarAngle = Math.PI * 0.5;
|
|
|
controls.minDistance = 1000;
|
|
|
controls.maxDistance = 5000;
|
|
@@ -580,7 +576,7 @@
|
|
|
|
|
|
//
|
|
|
|
|
|
- var gui = new GUI();
|
|
|
+ const gui = new GUI();
|
|
|
gui.add( params, 'enableWind' ).name( 'Enable wind' );
|
|
|
gui.add( params, 'showBall' ).name( 'Show ball' );
|
|
|
gui.add( params, 'togglePins' ).name( 'Toggle pins' );
|
|
@@ -588,7 +584,7 @@
|
|
|
|
|
|
if ( typeof TESTING !== 'undefined' ) {
|
|
|
|
|
|
- for ( var i = 0; i < 50; i ++ ) {
|
|
|
+ for ( let i = 0; i < 50; i ++ ) {
|
|
|
|
|
|
simulate( 500 - 10 * i );
|
|
|
|
|
@@ -622,11 +618,11 @@
|
|
|
|
|
|
function render() {
|
|
|
|
|
|
- var p = cloth.particles;
|
|
|
+ const p = cloth.particles;
|
|
|
|
|
|
- for ( var i = 0, il = p.length; i < il; i ++ ) {
|
|
|
+ for ( let i = 0, il = p.length; i < il; i ++ ) {
|
|
|
|
|
|
- var v = p[ i ].position;
|
|
|
+ const v = p[ i ].position;
|
|
|
|
|
|
clothGeometry.attributes.position.setXYZ( i, v.x, v.y, v.z );
|
|
|
|
|
@@ -644,4 +640,4 @@
|
|
|
|
|
|
</script>
|
|
|
</body>
|
|
|
-</html>
|
|
|
+</html>
|