From 92e32e17a164e2d60bdd73ab8b3e90360555ad2d Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Mon, 30 Jan 2017 10:53:02 -0500 Subject: [PATCH 01/18] wing motion + body --- src/main.js | 264 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 256 insertions(+), 8 deletions(-) diff --git a/src/main.js b/src/main.js index fd8fbd4..8a253a2 100755 --- a/src/main.js +++ b/src/main.js @@ -4,6 +4,36 @@ const THREE = require('three'); // older modules are imported like this. You shouldn't have to worry about this much import Framework from './framework' + +// 14 step motion: http://www.brendanbody.co.uk/flight_tutorial/ +var state = 0; // 14 states total: 0-8 down, 8-13 up +var motion = { + states: [ + {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,3,5), wrist: new THREE.Vector3(7,7,5)}, + {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,2,5), wrist: new THREE.Vector3(7,5,5)}, + {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,1,5), wrist: new THREE.Vector3(7,4,5)}, + {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,0.5,5), wrist: new THREE.Vector3(7,2,5)}, + {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,0,5), wrist: new THREE.Vector3(7,1,5)}, + {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,-0.5,5), wrist: new THREE.Vector3(7,0.5,5)}, + {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,-1,5), wrist: new THREE.Vector3(7,0,5)}, + {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,-2,5), wrist: new THREE.Vector3(7,-1,5)}, + {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,-3,5), wrist: new THREE.Vector3(7,-3,5)}, + {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,-3,5), wrist: new THREE.Vector3(7,-4,5)}, + {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,-1,5), wrist: new THREE.Vector3(7,-2,5)}, + {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,0.5,5), wrist: new THREE.Vector3(7,-1,5)}, + {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,2,5), wrist: new THREE.Vector3(7,2,5)}, + {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,3,5), wrist: new THREE.Vector3(7,4,5)}, + ] +}; + +var timeDelta = 100; // ms +var startTime; + + + + + + // called after the scene loads function onLoad(framework) { var scene = framework.scene; @@ -13,7 +43,9 @@ function onLoad(framework) { var stats = framework.stats; // Basic Lambert white - var lambertWhite = new THREE.MeshLambertMaterial({ color: 0xaaaaaa, side: THREE.DoubleSide }); + var lambertYellow = new THREE.MeshLambertMaterial({ color: 0x5b4e3c, side: THREE.DoubleSide }); + var lambertLBrown = new THREE.MeshLambertMaterial({ color: 0x4c402f, side: THREE.DoubleSide }); + var lambertDBrown = new THREE.MeshLambertMaterial({ color: 0x2d251a, side: THREE.DoubleSide }); // Set light var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 ); @@ -40,13 +72,112 @@ function onLoad(framework) { // LOOK: This function runs after the obj has finished loading var featherGeo = obj.children[0].geometry; - var featherMesh = new THREE.Mesh(featherGeo, lambertWhite); - featherMesh.name = "feather"; - scene.add(featherMesh); + + + + for (var i = 0; i < 10; i++) { + var featherMesh = new THREE.Mesh(featherGeo, lambertYellow); + featherMesh.name = "sefeather"+i; + featherMesh.rotation.y = 1.8; + featherMesh.scale.set(0.5 + (Math.random() - 0.5)/3,1,1); + scene.add(featherMesh); + } + + for (var i = 0; i < 10; i++) { + var featherMesh = new THREE.Mesh(featherGeo, lambertLBrown); + featherMesh.name = "sefeather"+i+"-2"; + featherMesh.rotation.y = 1.6; + featherMesh.scale.set(1 + (Math.random() - 0.5)/2,1,1); + scene.add(featherMesh); + } + + for (var i = 0; i < 10; i++) { + var featherMesh = new THREE.Mesh(featherGeo, lambertDBrown); + featherMesh.name = "sefeather"+i+"-3"; + featherMesh.rotation.y = 1.6; + featherMesh.scale.set(1.5 + (Math.random() - 0.5)/2,1,1); + scene.add(featherMesh); + } + + for (var i = 0; i < 10; i++) { + var featherMesh = new THREE.Mesh(featherGeo, lambertYellow); + featherMesh.name = "ewfeather"+i; + featherMesh.rotation.y = 1.6; + featherMesh.scale.set((10 - i)/20 + (Math.random() - 0.5)/3,1,1); + scene.add(featherMesh); + } + + for (var i = 0; i < 10; i++) { + var featherMesh = new THREE.Mesh(featherGeo, lambertLBrown); + featherMesh.name = "ewfeather"+i+"-2"; + featherMesh.rotation.y = 1.6/(1+Math.exp(i-7)); + featherMesh.scale.set(1 + (Math.random() - 0.5)/2,1,1); + scene.add(featherMesh); + } + + for (var i = 0; i < 10; i++) { + var featherMesh = new THREE.Mesh(featherGeo, lambertDBrown); + featherMesh.name = "ewfeather"+i+"-3"; + featherMesh.rotation.y = 1.6/(1+Math.exp(i-7)); + featherMesh.scale.set(1.5 + (Math.random() - 0.5)/2,1,1); + scene.add(featherMesh); + } + }); + + var geometry = new THREE.BoxGeometry(0,0,0 ); + var material = new THREE.MeshBasicMaterial( {color: 0xCB2400} ); + var shoulder = new THREE.Mesh( geometry, material ); + shoulder.position.set(0,0,5); + shoulder.name = "shoulder"; + scene.add( shoulder ); + + var geometry = new THREE.BoxGeometry( 0,0,0); + var material = new THREE.MeshBasicMaterial( {color: 0xC67563} ); + var elbow = new THREE.Mesh( geometry, material ); + elbow.position.set(3,-3,5); + elbow.name = "elbow"; + scene.add( elbow ); + + + var geometry = new THREE.BoxGeometry(0,0,0 ); + var material = new THREE.MeshBasicMaterial( {color: 0xCAA8A1} ); + var wrist = new THREE.Mesh( geometry, material ); + wrist.position.set(7,-7,5); + wrist.name = "wrist"; + scene.add( wrist ); + + // body + var geometry = new THREE.CylinderGeometry( 0.01, 0.5, 2, 5 ); + var material = new THREE.MeshBasicMaterial( {color: 0xffff00} ); + var cylinder = new THREE.Mesh( geometry, material ); + cylinder.position.set(0,0,6); + cylinder.rotation.x = 2; + scene.add( cylinder ); + + + var geometry = new THREE.CylinderGeometry( 0.8, 0.8, 1, 5 ); + var material = new THREE.MeshBasicMaterial( {color: 0xf7f4ef} ); + var cylinder = new THREE.Mesh( geometry, material ); + cylinder.position.set(0,0.5,5.5); + cylinder.rotation.x = 1.8; + scene.add( cylinder ); + + + var geometry = new THREE.CylinderGeometry( 1, 0.8, 6, 5 ); + var material = new THREE.MeshBasicMaterial( {color: 0x2d251a} ); + var cylinder = new THREE.Mesh( geometry, material ); + cylinder.position.set(0,-0.5,2); + cylinder.rotation.x = 1.4; + scene.add( cylinder ); + + + + + // set camera position - camera.position.set(0, 1, 5); + camera.position.set(0, 10, 10); camera.lookAt(new THREE.Vector3(0,0,0)); // scene.add(lambertCube); @@ -57,17 +188,134 @@ function onLoad(framework) { gui.add(camera, 'fov', 0, 180).onChange(function(newVal) { camera.updateProjectionMatrix(); }); + + startTime = (new Date).getTime(); } // called on frame updates function onUpdate(framework) { - var feather = framework.scene.getObjectByName("feather"); + var feather = framework.scene.getObjectByName("feather"); if (feather !== undefined) { // Simply flap wing var date = new Date(); - feather.rotateZ(Math.sin(date.getTime() / 100) * 2 * Math.PI / 180); + feather.rotateZ(Math.sin(date.getTime() / 100) * 2 * Math.PI / 180); + } + + var v = new THREE.Vector3(0,0,0); + + // increment the state every timeDelta milliseconds + // and set the lerp alpha to equal the percentage of time elapsed between state changes + var curTime = (new Date).getTime() * 0.005; + + // if (Math.sign(10*Math.sin(0.1*curTime + 0.5 * Math.sin(0.1*curTime))) > 0) return; + + var elapsed = (new Date).getTime() - startTime; + var alpha = elapsed / timeDelta; // amount to lerp + if (elapsed > timeDelta) { + alpha = 0; + startTime = (new Date).getTime(); + state = (state + 1) % 14; + } + + var start = state; + var end = (state + 1) % 14; + + + var shoulder = framework.scene.getObjectByName("shoulder"); + if (shoulder !== undefined) { + var newPos = v.lerpVectors(motion.states[start].shoulder, motion.states[end].shoulder, alpha); + shoulder.position.set(newPos.x, newPos.y, newPos.z); + } + + var elbow = framework.scene.getObjectByName("elbow"); + if (elbow !== undefined) { + // var newPos = v.lerpVectors(motion.states[start].elbow, motion.states[end].elbow, alpha); + // elbow.position.set(newPos.x, newPos.y, newPos.z); + elbow.position.set(elbow.position.x, 3 * Math.sin(curTime+1 + 0.5 * Math.sin(curTime+1)), elbow.position.z); + } + + var wrist = framework.scene.getObjectByName("wrist"); + if (wrist !== undefined) { + // var newPos = v.lerpVectors(motion.states[start].wrist, motion.states[end].wrist, alpha); + // wrist.position.set(newPos.x, newPos.y, newPos.z); + wrist.position.set(wrist.position.x, 6 * Math.sin(curTime + 0.5 * Math.sin(curTime)), wrist.position.z); } + + for (var i = 0; i < 10; i++) { + var sefeather = framework.scene.getObjectByName("sefeather"+i); + if (sefeather !== undefined) { + // Simply flap wing + var newPos = v.lerpVectors(shoulder.position, elbow.position, (i+1)/10); + var direction = newPos.y - sefeather.position.y; + sefeather.position.set(newPos.x, newPos.y, newPos.z); + sefeather.rotation.z = -direction; + // sefeather.rotation.y = 1.8 + 0.05 * Math.random(); + // sefeather.rotation.x = 0.05 * Math.random(); + } + } + + for (var i = 0; i < 10; i++) { + var sefeather = framework.scene.getObjectByName("sefeather"+i+"-2"); + if (sefeather !== undefined) { + // Simply flap wing + var newPos = v.lerpVectors(shoulder.position, elbow.position, (i+1)/10); + var direction = newPos.y - sefeather.position.y; + sefeather.position.set(newPos.x, newPos.y-0.05, newPos.z-0.5); + sefeather.rotation.z = -direction; + // sefeather.rotation.y = 1.8 + 0.05 * Math.random(); + // sefeather.rotation.x = 0.05 * Math.random(); + } + } + + for (var i = 0; i < 10; i++) { + var sefeather = framework.scene.getObjectByName("sefeather"+i+"-3"); + if (sefeather !== undefined) { + // Simply flap wing + var newPos = v.lerpVectors(shoulder.position, elbow.position, (i+1)/10); + var direction = newPos.y - sefeather.position.y; + sefeather.position.set(newPos.x, newPos.y-0.1, newPos.z-1.5); + sefeather.rotation.z = -direction; + // sefeather.rotation.y = 1.8 + 0.05 * Math.random(); + // sefeather.rotation.x = 0.05 * Math.random(); + } + } + + + for (var i = 0; i < 10; i++) { + var ewfeather = framework.scene.getObjectByName("ewfeather"+i); + if (ewfeather !== undefined) { + // Simply flap wing + var newPos = v.lerpVectors(elbow.position, wrist.position, (i+1)/10); + var direction = newPos.y - ewfeather.position.y; + ewfeather.position.set(newPos.x, newPos.y, newPos.z); + ewfeather.rotation.z = -direction; + } + } + + for (var i = 0; i < 10; i++) { + var ewfeather = framework.scene.getObjectByName("ewfeather"+i+"-2"); + if (ewfeather !== undefined) { + // Simply flap wing + var newPos = v.lerpVectors(elbow.position, wrist.position, (i+1)/10); + var direction = newPos.y - ewfeather.position.y; + ewfeather.position.set(newPos.x, newPos.y-0.05, newPos.z-0.5); + ewfeather.rotation.z = -direction; + } + } + + + for (var i = 0; i < 10; i++) { + var ewfeather = framework.scene.getObjectByName("ewfeather"+i+"-3"); + if (ewfeather !== undefined) { + // Simply flap wing + var newPos = v.lerpVectors(elbow.position, wrist.position, (i+1)/10); + var direction = newPos.y - ewfeather.position.y; + ewfeather.position.set(newPos.x, newPos.y-0.1, newPos.z-1.5); + ewfeather.rotation.z = -direction; + } + } + } // when the scene is done initializing, it will call onLoad, then on frame updates, call onUpdate -Framework.init(onLoad, onUpdate); \ No newline at end of file +Framework.init(onLoad, onUpdate); From 0069002069a81745cba36e7ad2bbec720e8fc769 Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Mon, 30 Jan 2017 11:32:44 -0500 Subject: [PATCH 02/18] add controls for speed --- src/main.js | 50 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/src/main.js b/src/main.js index 8a253a2..57d1358 100755 --- a/src/main.js +++ b/src/main.js @@ -30,8 +30,14 @@ var timeDelta = 100; // ms var startTime; +var settings = { + speed: 0.0 +} +function clamp(num, min, max) { + return num <= min ? min : num >= max ? max : num; +} // called after the scene loads @@ -148,7 +154,7 @@ function onLoad(framework) { wrist.name = "wrist"; scene.add( wrist ); - // body + // beak var geometry = new THREE.CylinderGeometry( 0.01, 0.5, 2, 5 ); var material = new THREE.MeshBasicMaterial( {color: 0xffff00} ); var cylinder = new THREE.Mesh( geometry, material ); @@ -156,20 +162,21 @@ function onLoad(framework) { cylinder.rotation.x = 2; scene.add( cylinder ); - - var geometry = new THREE.CylinderGeometry( 0.8, 0.8, 1, 5 ); + // head + var geometry = new THREE.CylinderGeometry( 0.7, 0.8, 1, 5 ); var material = new THREE.MeshBasicMaterial( {color: 0xf7f4ef} ); var cylinder = new THREE.Mesh( geometry, material ); cylinder.position.set(0,0.5,5.5); cylinder.rotation.x = 1.8; scene.add( cylinder ); - + // body var geometry = new THREE.CylinderGeometry( 1, 0.8, 6, 5 ); var material = new THREE.MeshBasicMaterial( {color: 0x2d251a} ); var cylinder = new THREE.Mesh( geometry, material ); cylinder.position.set(0,-0.5,2); cylinder.rotation.x = 1.4; + cylinder.name = "body"; scene.add( cylinder ); @@ -189,6 +196,8 @@ function onLoad(framework) { camera.updateProjectionMatrix(); }); + gui.add(settings, 'speed', 0.0, 0.01); + startTime = (new Date).getTime(); } @@ -205,21 +214,24 @@ function onUpdate(framework) { // increment the state every timeDelta milliseconds // and set the lerp alpha to equal the percentage of time elapsed between state changes - var curTime = (new Date).getTime() * 0.005; - - // if (Math.sign(10*Math.sin(0.1*curTime + 0.5 * Math.sin(0.1*curTime))) > 0) return; - - var elapsed = (new Date).getTime() - startTime; + var elapsed = ((new Date).getTime() - startTime); var alpha = elapsed / timeDelta; // amount to lerp if (elapsed > timeDelta) { alpha = 0; startTime = (new Date).getTime(); state = (state + 1) % 14; + } else { + return; } + var curTime = (new Date).getTime() * settings.speed; + + var start = state; var end = (state + 1) % 14; + var freq = settings.speed; + var shoulder = framework.scene.getObjectByName("shoulder"); if (shoulder !== undefined) { @@ -248,9 +260,16 @@ function onUpdate(framework) { var newPos = v.lerpVectors(shoulder.position, elbow.position, (i+1)/10); var direction = newPos.y - sefeather.position.y; sefeather.position.set(newPos.x, newPos.y, newPos.z); - sefeather.rotation.z = -direction; + sefeather.rotation.z = clamp(-direction, -1, 1); // sefeather.rotation.y = 1.8 + 0.05 * Math.random(); // sefeather.rotation.x = 0.05 * Math.random(); + + // body motion + var body = framework.scene.getObjectByName("body"); + if (body !== undefined) { + newPos = body.position; + body.position.set(newPos.x, newPos.y - 0.005 * direction, newPos.z); + } } } @@ -261,7 +280,7 @@ function onUpdate(framework) { var newPos = v.lerpVectors(shoulder.position, elbow.position, (i+1)/10); var direction = newPos.y - sefeather.position.y; sefeather.position.set(newPos.x, newPos.y-0.05, newPos.z-0.5); - sefeather.rotation.z = -direction; + sefeather.rotation.z = clamp(-direction, -1, 1); // sefeather.rotation.y = 1.8 + 0.05 * Math.random(); // sefeather.rotation.x = 0.05 * Math.random(); } @@ -274,7 +293,7 @@ function onUpdate(framework) { var newPos = v.lerpVectors(shoulder.position, elbow.position, (i+1)/10); var direction = newPos.y - sefeather.position.y; sefeather.position.set(newPos.x, newPos.y-0.1, newPos.z-1.5); - sefeather.rotation.z = -direction; + sefeather.rotation.z = clamp(-direction, -1, 1); // sefeather.rotation.y = 1.8 + 0.05 * Math.random(); // sefeather.rotation.x = 0.05 * Math.random(); } @@ -288,7 +307,7 @@ function onUpdate(framework) { var newPos = v.lerpVectors(elbow.position, wrist.position, (i+1)/10); var direction = newPos.y - ewfeather.position.y; ewfeather.position.set(newPos.x, newPos.y, newPos.z); - ewfeather.rotation.z = -direction; + ewfeather.rotation.z = clamp(-direction, -1, 1); } } @@ -299,11 +318,10 @@ function onUpdate(framework) { var newPos = v.lerpVectors(elbow.position, wrist.position, (i+1)/10); var direction = newPos.y - ewfeather.position.y; ewfeather.position.set(newPos.x, newPos.y-0.05, newPos.z-0.5); - ewfeather.rotation.z = -direction; + ewfeather.rotation.z = clamp(-direction, -1, 1); } } - for (var i = 0; i < 10; i++) { var ewfeather = framework.scene.getObjectByName("ewfeather"+i+"-3"); if (ewfeather !== undefined) { @@ -311,7 +329,7 @@ function onUpdate(framework) { var newPos = v.lerpVectors(elbow.position, wrist.position, (i+1)/10); var direction = newPos.y - ewfeather.position.y; ewfeather.position.set(newPos.x, newPos.y-0.1, newPos.z-1.5); - ewfeather.rotation.z = -direction; + ewfeather.rotation.z = clamp(-direction, -1, 1); } } From 79bbd8a4d34316f27fd4bd4ce191e68ee4f37380 Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Mon, 30 Jan 2017 12:31:10 -0500 Subject: [PATCH 03/18] add color controls --- src/main.js | 53 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/src/main.js b/src/main.js index 57d1358..876254d 100755 --- a/src/main.js +++ b/src/main.js @@ -31,10 +31,12 @@ var startTime; var settings = { - speed: 0.0 + speed: 0.003, + primaryColor: [ 91, 78, 60 ], + secondaryColor: [ 76, 64, 47 ], + tertiaryColor: [ 45, 37, 26 ] } - function clamp(num, min, max) { return num <= min ? min : num >= max ? max : num; } @@ -48,10 +50,14 @@ function onLoad(framework) { var gui = framework.gui; var stats = framework.stats; - // Basic Lambert white - var lambertYellow = new THREE.MeshLambertMaterial({ color: 0x5b4e3c, side: THREE.DoubleSide }); - var lambertLBrown = new THREE.MeshLambertMaterial({ color: 0x4c402f, side: THREE.DoubleSide }); - var lambertDBrown = new THREE.MeshLambertMaterial({ color: 0x2d251a, side: THREE.DoubleSide }); + // Basic Lambert + var primaryColor = new THREE.Color(settings.primaryColor[0]/255, settings.primaryColor[1]/255, settings.primaryColor[2]/255); + var secondaryColor = new THREE.Color(settings.secondaryColor[0]/255, settings.secondaryColor[1]/255, settings.secondaryColor[2]/255); + var tertiaryColor = new THREE.Color(settings.tertiaryColor[0]/255, settings.tertiaryColor[1]/255, settings.tertiaryColor[2]/255); + var lambertPrimary = new THREE.MeshLambertMaterial({ color: primaryColor, side: THREE.DoubleSide }); + var lambertSecondary = new THREE.MeshLambertMaterial({ color: secondaryColor, side: THREE.DoubleSide }); + var lambertTertiary = new THREE.MeshLambertMaterial({ color: tertiaryColor, side: THREE.DoubleSide }); + // Set light var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 ); @@ -82,7 +88,7 @@ function onLoad(framework) { for (var i = 0; i < 10; i++) { - var featherMesh = new THREE.Mesh(featherGeo, lambertYellow); + var featherMesh = new THREE.Mesh(featherGeo, lambertPrimary); featherMesh.name = "sefeather"+i; featherMesh.rotation.y = 1.8; featherMesh.scale.set(0.5 + (Math.random() - 0.5)/3,1,1); @@ -90,7 +96,7 @@ function onLoad(framework) { } for (var i = 0; i < 10; i++) { - var featherMesh = new THREE.Mesh(featherGeo, lambertLBrown); + var featherMesh = new THREE.Mesh(featherGeo, lambertSecondary); featherMesh.name = "sefeather"+i+"-2"; featherMesh.rotation.y = 1.6; featherMesh.scale.set(1 + (Math.random() - 0.5)/2,1,1); @@ -98,7 +104,7 @@ function onLoad(framework) { } for (var i = 0; i < 10; i++) { - var featherMesh = new THREE.Mesh(featherGeo, lambertDBrown); + var featherMesh = new THREE.Mesh(featherGeo, lambertTertiary); featherMesh.name = "sefeather"+i+"-3"; featherMesh.rotation.y = 1.6; featherMesh.scale.set(1.5 + (Math.random() - 0.5)/2,1,1); @@ -106,7 +112,7 @@ function onLoad(framework) { } for (var i = 0; i < 10; i++) { - var featherMesh = new THREE.Mesh(featherGeo, lambertYellow); + var featherMesh = new THREE.Mesh(featherGeo, lambertPrimary); featherMesh.name = "ewfeather"+i; featherMesh.rotation.y = 1.6; featherMesh.scale.set((10 - i)/20 + (Math.random() - 0.5)/3,1,1); @@ -114,7 +120,7 @@ function onLoad(framework) { } for (var i = 0; i < 10; i++) { - var featherMesh = new THREE.Mesh(featherGeo, lambertLBrown); + var featherMesh = new THREE.Mesh(featherGeo, lambertSecondary); featherMesh.name = "ewfeather"+i+"-2"; featherMesh.rotation.y = 1.6/(1+Math.exp(i-7)); featherMesh.scale.set(1 + (Math.random() - 0.5)/2,1,1); @@ -122,7 +128,7 @@ function onLoad(framework) { } for (var i = 0; i < 10; i++) { - var featherMesh = new THREE.Mesh(featherGeo, lambertDBrown); + var featherMesh = new THREE.Mesh(featherGeo, lambertTertiary); featherMesh.name = "ewfeather"+i+"-3"; featherMesh.rotation.y = 1.6/(1+Math.exp(i-7)); featherMesh.scale.set(1.5 + (Math.random() - 0.5)/2,1,1); @@ -197,12 +203,23 @@ function onLoad(framework) { }); gui.add(settings, 'speed', 0.0, 0.01); + gui.addColor(settings, 'primaryColor'); + gui.addColor(settings, 'secondaryColor'); + gui.addColor(settings, 'tertiaryColor'); startTime = (new Date).getTime(); } // called on frame updates function onUpdate(framework) { + + var primaryColor = new THREE.Color(settings.primaryColor[0]/255, settings.primaryColor[1]/255, settings.primaryColor[2]/255); + var secondaryColor = new THREE.Color(settings.secondaryColor[0]/255, settings.secondaryColor[1]/255, settings.secondaryColor[2]/255); + var tertiaryColor = new THREE.Color(settings.tertiaryColor[0]/255, settings.tertiaryColor[1]/255, settings.tertiaryColor[2]/255); + var lambertPrimary = new THREE.MeshLambertMaterial({ color: primaryColor, side: THREE.DoubleSide }); + var lambertSecondary = new THREE.MeshLambertMaterial({ color: secondaryColor, side: THREE.DoubleSide }); + var lambertTertiary = new THREE.MeshLambertMaterial({ color: tertiaryColor, side: THREE.DoubleSide }); + var feather = framework.scene.getObjectByName("feather"); if (feather !== undefined) { // Simply flap wing @@ -261,8 +278,7 @@ function onUpdate(framework) { var direction = newPos.y - sefeather.position.y; sefeather.position.set(newPos.x, newPos.y, newPos.z); sefeather.rotation.z = clamp(-direction, -1, 1); - // sefeather.rotation.y = 1.8 + 0.05 * Math.random(); - // sefeather.rotation.x = 0.05 * Math.random(); + sefeather.material = lambertPrimary; // body motion var body = framework.scene.getObjectByName("body"); @@ -281,8 +297,7 @@ function onUpdate(framework) { var direction = newPos.y - sefeather.position.y; sefeather.position.set(newPos.x, newPos.y-0.05, newPos.z-0.5); sefeather.rotation.z = clamp(-direction, -1, 1); - // sefeather.rotation.y = 1.8 + 0.05 * Math.random(); - // sefeather.rotation.x = 0.05 * Math.random(); + sefeather.material = lambertSecondary; } } @@ -294,8 +309,7 @@ function onUpdate(framework) { var direction = newPos.y - sefeather.position.y; sefeather.position.set(newPos.x, newPos.y-0.1, newPos.z-1.5); sefeather.rotation.z = clamp(-direction, -1, 1); - // sefeather.rotation.y = 1.8 + 0.05 * Math.random(); - // sefeather.rotation.x = 0.05 * Math.random(); + sefeather.material = lambertTertiary; } } @@ -308,6 +322,7 @@ function onUpdate(framework) { var direction = newPos.y - ewfeather.position.y; ewfeather.position.set(newPos.x, newPos.y, newPos.z); ewfeather.rotation.z = clamp(-direction, -1, 1); + ewfeather.material = lambertPrimary; } } @@ -319,6 +334,7 @@ function onUpdate(framework) { var direction = newPos.y - ewfeather.position.y; ewfeather.position.set(newPos.x, newPos.y-0.05, newPos.z-0.5); ewfeather.rotation.z = clamp(-direction, -1, 1); + ewfeather.material = lambertSecondary; } } @@ -330,6 +346,7 @@ function onUpdate(framework) { var direction = newPos.y - ewfeather.position.y; ewfeather.position.set(newPos.x, newPos.y-0.1, newPos.z-1.5); ewfeather.rotation.z = clamp(-direction, -1, 1); + ewfeather.material = lambertTertiary; } } From 80ac04f062da32123b658b382f606f6ea462df78 Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Mon, 30 Jan 2017 12:52:13 -0500 Subject: [PATCH 04/18] add control point controls --- src/main.js | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/main.js b/src/main.js index 876254d..9e93f9b 100755 --- a/src/main.js +++ b/src/main.js @@ -34,7 +34,11 @@ var settings = { speed: 0.003, primaryColor: [ 91, 78, 60 ], secondaryColor: [ 76, 64, 47 ], - tertiaryColor: [ 45, 37, 26 ] + tertiaryColor: [ 45, 37, 26 ], + elbowX: 3, + elbowZ: 5, + wristX: 7, + wristZ: 5 } function clamp(num, min, max) { @@ -58,7 +62,6 @@ function onLoad(framework) { var lambertSecondary = new THREE.MeshLambertMaterial({ color: secondaryColor, side: THREE.DoubleSide }); var lambertTertiary = new THREE.MeshLambertMaterial({ color: tertiaryColor, side: THREE.DoubleSide }); - // Set light var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 ); directionalLight.color.setHSL(0.1, 1, 0.95); @@ -137,7 +140,6 @@ function onLoad(framework) { }); - var geometry = new THREE.BoxGeometry(0,0,0 ); var material = new THREE.MeshBasicMaterial( {color: 0xCB2400} ); var shoulder = new THREE.Mesh( geometry, material ); @@ -206,6 +208,33 @@ function onLoad(framework) { gui.addColor(settings, 'primaryColor'); gui.addColor(settings, 'secondaryColor'); gui.addColor(settings, 'tertiaryColor'); + gui.add(settings, 'elbowX',0, 10).onChange(function(newVal) { + var elbow = framework.scene.getObjectByName("elbow"); + if (elbow !== undefined) { + elbow.position.set(newVal, elbow.position.y, elbow.position.z); + } + }); + + gui.add(settings, 'elbowZ',0, 10).onChange(function(newVal) { + var elbow = framework.scene.getObjectByName("elbow"); + if (elbow !== undefined) { + elbow.position.set(elbow.position.x, elbow.position.y, newVal); + } + }); + + gui.add(settings, 'wristX',0, 10).onChange(function(newVal) { + var wrist = framework.scene.getObjectByName("wrist"); + if (wrist !== undefined) { + wrist.position.set(newVal, wrist.position.y, wrist.position.z); + } + }); + + gui.add(settings, 'wristZ',0, 10).onChange(function(newVal) { + var wrist = framework.scene.getObjectByName("wrist"); + if (wrist !== undefined) { + elbow.position.set(wrist.position.x, wrist.position.y, newVal); + } + }); startTime = (new Date).getTime(); } From 3d8545390a67564999a9e068bab057a6cde69406 Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Mon, 30 Jan 2017 15:21:49 -0500 Subject: [PATCH 05/18] major refactor: generate feathers using config object --- src/main.js | 311 +++++++++++++++++++++------------------------------- 1 file changed, 128 insertions(+), 183 deletions(-) diff --git a/src/main.js b/src/main.js index 9e93f9b..a6f7b15 100755 --- a/src/main.js +++ b/src/main.js @@ -6,30 +6,10 @@ import Framework from './framework' // 14 step motion: http://www.brendanbody.co.uk/flight_tutorial/ -var state = 0; // 14 states total: 0-8 down, 8-13 up -var motion = { - states: [ - {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,3,5), wrist: new THREE.Vector3(7,7,5)}, - {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,2,5), wrist: new THREE.Vector3(7,5,5)}, - {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,1,5), wrist: new THREE.Vector3(7,4,5)}, - {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,0.5,5), wrist: new THREE.Vector3(7,2,5)}, - {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,0,5), wrist: new THREE.Vector3(7,1,5)}, - {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,-0.5,5), wrist: new THREE.Vector3(7,0.5,5)}, - {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,-1,5), wrist: new THREE.Vector3(7,0,5)}, - {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,-2,5), wrist: new THREE.Vector3(7,-1,5)}, - {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,-3,5), wrist: new THREE.Vector3(7,-3,5)}, - {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,-3,5), wrist: new THREE.Vector3(7,-4,5)}, - {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,-1,5), wrist: new THREE.Vector3(7,-2,5)}, - {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,0.5,5), wrist: new THREE.Vector3(7,-1,5)}, - {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,2,5), wrist: new THREE.Vector3(7,2,5)}, - {shoulder: new THREE.Vector3(0,0,5), elbow: new THREE.Vector3(3,3,5), wrist: new THREE.Vector3(7,4,5)}, - ] -}; - +var state = 0; var timeDelta = 100; // ms var startTime; - var settings = { speed: 0.003, primaryColor: [ 91, 78, 60 ], @@ -38,9 +18,79 @@ var settings = { elbowX: 3, elbowZ: 5, wristX: 7, - wristZ: 5 + wristZ: 5, + density: 1, + maxDensity: 20, + feathersPerLayer: 10 } +var featherConfig = { + getName: function(segment, region, i, l) { + return "feather(" + segment + "," + region + "," + i + "," + l + ")"; + }, + marginalCoverts: { + segment: "se", + region: "marginalCoverts", + yaw: function(i) { return 1.6; }, + scale: function(i) { return [0.5 + (Math.random() - 0.5)/3, 1, 1]; }, + color: 1, + yindex: 0, + zindex: 0 + }, + secondaryCoverts: { + segment: "se", + region: "secondaryCoverts", + yaw: function(i) { return 1.6; }, + scale: function(i) { return [1 + (Math.random() - 0.5)/2, 1, 1]; }, + color: 2, + yindex: -0.05, + zindex: -0.5 + }, + secondaries: { + segment: "se", + region: "secondaries", + yaw: function(i) { return 1.6; }, + scale: function(i) { return [1.5 + (Math.random() - 0.5)/2, 1, 1]; }, + color: 3, + yindex: -0.1, + zindex: -1 + }, + alula: { + segment: "ew", + region: "alula", + yaw: function(i) { return 1.6; }, + scale: function(i) { return [(10 - i)/20 + (Math.random() - 0.5)/3, 1, 1]; }, + color: 1, + yindex: 0, + zindex: 0 + }, + primaryCoverts: { + segment: "ew", + region: "primaryCoverts", + yaw: function(i) { return 1.6/(1+Math.exp(i-7)); }, + scale: function(i) { return [1 + (Math.random() - 0.5)/2, 1, 1]; }, + color: 2, + yindex: -0.05, + zindex: -0.5 + }, + primaries: { + segment: "ew", + region: "primaries", + yaw: function(i) { return 1.6/(1+Math.exp(i-7)); }, + scale: function(i) { return [1.5 + (Math.random() - 0.5)/2, 1, 1]; }, + color: 3, + yindex: -0.1, + zindex: -1 + } +}; + +var sections = [featherConfig.marginalCoverts, + featherConfig.secondaryCoverts, + featherConfig.secondaries, + featherConfig.alula, + featherConfig.primaryCoverts, + featherConfig.primaries]; + function clamp(num, min, max) { return num <= min ? min : num >= max ? max : num; } @@ -55,12 +105,7 @@ function onLoad(framework) { var stats = framework.stats; // Basic Lambert - var primaryColor = new THREE.Color(settings.primaryColor[0]/255, settings.primaryColor[1]/255, settings.primaryColor[2]/255); - var secondaryColor = new THREE.Color(settings.secondaryColor[0]/255, settings.secondaryColor[1]/255, settings.secondaryColor[2]/255); - var tertiaryColor = new THREE.Color(settings.tertiaryColor[0]/255, settings.tertiaryColor[1]/255, settings.tertiaryColor[2]/255); - var lambertPrimary = new THREE.MeshLambertMaterial({ color: primaryColor, side: THREE.DoubleSide }); - var lambertSecondary = new THREE.MeshLambertMaterial({ color: secondaryColor, side: THREE.DoubleSide }); - var lambertTertiary = new THREE.MeshLambertMaterial({ color: tertiaryColor, side: THREE.DoubleSide }); + var lambertWhite = new THREE.MeshLambertMaterial({ color: 0xffffff, side: THREE.DoubleSide }); // Set light var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 ); @@ -80,64 +125,25 @@ function onLoad(framework) { scene.background = skymap; + // load a simple obj mesh var objLoader = new THREE.OBJLoader(); objLoader.load('/geo/feather.obj', function(obj) { - - // LOOK: This function runs after the obj has finished loading var featherGeo = obj.children[0].geometry; - - - - - for (var i = 0; i < 10; i++) { - var featherMesh = new THREE.Mesh(featherGeo, lambertPrimary); - featherMesh.name = "sefeather"+i; - featherMesh.rotation.y = 1.8; - featherMesh.scale.set(0.5 + (Math.random() - 0.5)/3,1,1); - scene.add(featherMesh); - } - - for (var i = 0; i < 10; i++) { - var featherMesh = new THREE.Mesh(featherGeo, lambertSecondary); - featherMesh.name = "sefeather"+i+"-2"; - featherMesh.rotation.y = 1.6; - featherMesh.scale.set(1 + (Math.random() - 0.5)/2,1,1); - scene.add(featherMesh); - } - - for (var i = 0; i < 10; i++) { - var featherMesh = new THREE.Mesh(featherGeo, lambertTertiary); - featherMesh.name = "sefeather"+i+"-3"; - featherMesh.rotation.y = 1.6; - featherMesh.scale.set(1.5 + (Math.random() - 0.5)/2,1,1); - scene.add(featherMesh); - } - - for (var i = 0; i < 10; i++) { - var featherMesh = new THREE.Mesh(featherGeo, lambertPrimary); - featherMesh.name = "ewfeather"+i; - featherMesh.rotation.y = 1.6; - featherMesh.scale.set((10 - i)/20 + (Math.random() - 0.5)/3,1,1); - scene.add(featherMesh); - } - - for (var i = 0; i < 10; i++) { - var featherMesh = new THREE.Mesh(featherGeo, lambertSecondary); - featherMesh.name = "ewfeather"+i+"-2"; - featherMesh.rotation.y = 1.6/(1+Math.exp(i-7)); - featherMesh.scale.set(1 + (Math.random() - 0.5)/2,1,1); - scene.add(featherMesh); - } - - for (var i = 0; i < 10; i++) { - var featherMesh = new THREE.Mesh(featherGeo, lambertTertiary); - featherMesh.name = "ewfeather"+i+"-3"; - featherMesh.rotation.y = 1.6/(1+Math.exp(i-7)); - featherMesh.scale.set(1.5 + (Math.random() - 0.5)/2,1,1); - scene.add(featherMesh); + for (var s = 0; s < sections.length; s++) { + var config = sections[s]; + for (var l = 0; l < settings.density; l++) { + for (var i = 0; i < settings.feathersPerLayer; i++) { + var fi = 10 * i / settings.feathersPerLayer; + var featherMesh = new THREE.Mesh(featherGeo, lambertWhite); + featherMesh.name = featherConfig.getName(config.segment, config.region, i, l); + featherMesh.rotation.y = config.yaw(fi); + var scale = config.scale(fi); + featherMesh.scale.set(scale[0], scale[1], scale[2]); + scene.add(featherMesh); + } + } } - }); var geometry = new THREE.BoxGeometry(0,0,0 ); @@ -188,9 +194,6 @@ function onLoad(framework) { scene.add( cylinder ); - - - // set camera position camera.position.set(0, 10, 10); camera.lookAt(new THREE.Vector3(0,0,0)); @@ -205,9 +208,11 @@ function onLoad(framework) { }); gui.add(settings, 'speed', 0.0, 0.01); + gui.addColor(settings, 'primaryColor'); gui.addColor(settings, 'secondaryColor'); gui.addColor(settings, 'tertiaryColor'); + gui.add(settings, 'elbowX',0, 10).onChange(function(newVal) { var elbow = framework.scene.getObjectByName("elbow"); if (elbow !== undefined) { @@ -236,6 +241,8 @@ function onLoad(framework) { } }); + gui.add(settings, 'density', 0, settings.maxDensity); + startTime = (new Date).getTime(); } @@ -249,13 +256,6 @@ function onUpdate(framework) { var lambertSecondary = new THREE.MeshLambertMaterial({ color: secondaryColor, side: THREE.DoubleSide }); var lambertTertiary = new THREE.MeshLambertMaterial({ color: tertiaryColor, side: THREE.DoubleSide }); - var feather = framework.scene.getObjectByName("feather"); - if (feather !== undefined) { - // Simply flap wing - var date = new Date(); - feather.rotateZ(Math.sin(date.getTime() / 100) * 2 * Math.PI / 180); - } - var v = new THREE.Vector3(0,0,0); // increment the state every timeDelta milliseconds @@ -271,114 +271,59 @@ function onUpdate(framework) { } var curTime = (new Date).getTime() * settings.speed; - - - var start = state; - var end = (state + 1) % 14; - var freq = settings.speed; - var shoulder = framework.scene.getObjectByName("shoulder"); - if (shoulder !== undefined) { - var newPos = v.lerpVectors(motion.states[start].shoulder, motion.states[end].shoulder, alpha); - shoulder.position.set(newPos.x, newPos.y, newPos.z); - } - var elbow = framework.scene.getObjectByName("elbow"); if (elbow !== undefined) { - // var newPos = v.lerpVectors(motion.states[start].elbow, motion.states[end].elbow, alpha); - // elbow.position.set(newPos.x, newPos.y, newPos.z); elbow.position.set(elbow.position.x, 3 * Math.sin(curTime+1 + 0.5 * Math.sin(curTime+1)), elbow.position.z); } var wrist = framework.scene.getObjectByName("wrist"); if (wrist !== undefined) { - // var newPos = v.lerpVectors(motion.states[start].wrist, motion.states[end].wrist, alpha); - // wrist.position.set(newPos.x, newPos.y, newPos.z); wrist.position.set(wrist.position.x, 6 * Math.sin(curTime + 0.5 * Math.sin(curTime)), wrist.position.z); } - for (var i = 0; i < 10; i++) { - var sefeather = framework.scene.getObjectByName("sefeather"+i); - if (sefeather !== undefined) { - // Simply flap wing - var newPos = v.lerpVectors(shoulder.position, elbow.position, (i+1)/10); - var direction = newPos.y - sefeather.position.y; - sefeather.position.set(newPos.x, newPos.y, newPos.z); - sefeather.rotation.z = clamp(-direction, -1, 1); - sefeather.material = lambertPrimary; - - // body motion - var body = framework.scene.getObjectByName("body"); - if (body !== undefined) { - newPos = body.position; - body.position.set(newPos.x, newPos.y - 0.005 * direction, newPos.z); + for (var s = 0; s < sections.length; s++) { + var config = sections[s]; + for (var l = 0; l < settings.density; l++) { + for (var i = 0; i < settings.feathersPerLayer; i++) { + var fi = 10 * i / settings.feathersPerLayer; + var name = featherConfig.getName(config.segment, config.region, i, l); + var feather = framework.scene.getObjectByName(name); + if (feather !== undefined) { + + if (config.segment == "se") { + var start = shoulder; + var end = elbow; + } else if (config.segment == "ew") { + var start = elbow; + var end = wrist; + } + + var newPos = v.lerpVectors(start.position, end.position, (fi+1)/10); + var direction = newPos.y - feather.position.y; + feather.position.set(newPos.x, newPos.y+config.yindex, newPos.z+config.zindex); + feather.rotation.z = clamp(-direction, -1, 1); + + switch (config.color) { + case 1: + feather.material = lambertPrimary; + break; + case 2: + feather.material = lambertSecondary; + break; + case 3: + feather.material = lambertTertiary; + break; + } + + } else { + console.log("undefined feather: " + name); + } } } } - - for (var i = 0; i < 10; i++) { - var sefeather = framework.scene.getObjectByName("sefeather"+i+"-2"); - if (sefeather !== undefined) { - // Simply flap wing - var newPos = v.lerpVectors(shoulder.position, elbow.position, (i+1)/10); - var direction = newPos.y - sefeather.position.y; - sefeather.position.set(newPos.x, newPos.y-0.05, newPos.z-0.5); - sefeather.rotation.z = clamp(-direction, -1, 1); - sefeather.material = lambertSecondary; - } - } - - for (var i = 0; i < 10; i++) { - var sefeather = framework.scene.getObjectByName("sefeather"+i+"-3"); - if (sefeather !== undefined) { - // Simply flap wing - var newPos = v.lerpVectors(shoulder.position, elbow.position, (i+1)/10); - var direction = newPos.y - sefeather.position.y; - sefeather.position.set(newPos.x, newPos.y-0.1, newPos.z-1.5); - sefeather.rotation.z = clamp(-direction, -1, 1); - sefeather.material = lambertTertiary; - } - } - - - for (var i = 0; i < 10; i++) { - var ewfeather = framework.scene.getObjectByName("ewfeather"+i); - if (ewfeather !== undefined) { - // Simply flap wing - var newPos = v.lerpVectors(elbow.position, wrist.position, (i+1)/10); - var direction = newPos.y - ewfeather.position.y; - ewfeather.position.set(newPos.x, newPos.y, newPos.z); - ewfeather.rotation.z = clamp(-direction, -1, 1); - ewfeather.material = lambertPrimary; - } - } - - for (var i = 0; i < 10; i++) { - var ewfeather = framework.scene.getObjectByName("ewfeather"+i+"-2"); - if (ewfeather !== undefined) { - // Simply flap wing - var newPos = v.lerpVectors(elbow.position, wrist.position, (i+1)/10); - var direction = newPos.y - ewfeather.position.y; - ewfeather.position.set(newPos.x, newPos.y-0.05, newPos.z-0.5); - ewfeather.rotation.z = clamp(-direction, -1, 1); - ewfeather.material = lambertSecondary; - } - } - - for (var i = 0; i < 10; i++) { - var ewfeather = framework.scene.getObjectByName("ewfeather"+i+"-3"); - if (ewfeather !== undefined) { - // Simply flap wing - var newPos = v.lerpVectors(elbow.position, wrist.position, (i+1)/10); - var direction = newPos.y - ewfeather.position.y; - ewfeather.position.set(newPos.x, newPos.y-0.1, newPos.z-1.5); - ewfeather.rotation.z = clamp(-direction, -1, 1); - ewfeather.material = lambertTertiary; - } - } - } // when the scene is done initializing, it will call onLoad, then on frame updates, call onUpdate From 36ba239b555f9e836d16ffa63646486cb6b009b0 Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Tue, 31 Jan 2017 09:36:06 -0500 Subject: [PATCH 06/18] add controls for feather density and showing control points --- src/main.js | 98 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 35 deletions(-) diff --git a/src/main.js b/src/main.js index a6f7b15..6f20bde 100755 --- a/src/main.js +++ b/src/main.js @@ -19,9 +19,10 @@ var settings = { elbowZ: 5, wristX: 7, wristZ: 5, - density: 1, - maxDensity: 20, - feathersPerLayer: 10 + numLayers: 1, + maxDensity: 40, + density: 40, + showCtrlPts: false } var featherConfig = { @@ -125,16 +126,15 @@ function onLoad(framework) { scene.background = skymap; - // load a simple obj mesh var objLoader = new THREE.OBJLoader(); objLoader.load('/geo/feather.obj', function(obj) { var featherGeo = obj.children[0].geometry; for (var s = 0; s < sections.length; s++) { var config = sections[s]; - for (var l = 0; l < settings.density; l++) { - for (var i = 0; i < settings.feathersPerLayer; i++) { - var fi = 10 * i / settings.feathersPerLayer; + for (var l = 0; l < settings.numLayers; l++) { + for (var i = 0; i < settings.density; i++) { + var fi = 10 * i / settings.density; var featherMesh = new THREE.Mesh(featherGeo, lambertWhite); featherMesh.name = featherConfig.getName(config.segment, config.region, i, l); featherMesh.rotation.y = config.yaw(fi); @@ -243,6 +243,29 @@ function onLoad(framework) { gui.add(settings, 'density', 0, settings.maxDensity); + gui.add(settings, 'showCtrlPts').onChange(function(newVal) { + var shoulder = framework.scene.getObjectByName("shoulder"); + var elbow = framework.scene.getObjectByName("elbow"); + if (elbow !== undefined) { + if (newVal) { + var geometry = new THREE.BoxGeometry(1,1,1); + } else { + var geometry = new THREE.BoxGeometry(0,0,0); + } + elbow.geometry = geometry; + } + + var wrist = framework.scene.getObjectByName("wrist"); + if (wrist !== undefined) { + if (newVal) { + var geometry = new THREE.BoxGeometry(1,1,1); + } else { + var geometry = new THREE.BoxGeometry(0,0,0); + } + wrist.geometry = geometry; + } + }); + startTime = (new Date).getTime(); } @@ -267,7 +290,7 @@ function onUpdate(framework) { startTime = (new Date).getTime(); state = (state + 1) % 14; } else { - return; + return;a } var curTime = (new Date).getTime() * settings.speed; @@ -286,38 +309,43 @@ function onUpdate(framework) { for (var s = 0; s < sections.length; s++) { var config = sections[s]; - for (var l = 0; l < settings.density; l++) { - for (var i = 0; i < settings.feathersPerLayer; i++) { - var fi = 10 * i / settings.feathersPerLayer; + for (var l = 0; l < settings.numLayers; l++) { + for (var i = 0; i < settings.maxDensity; i++) { + var fi = 10 * i / settings.density; var name = featherConfig.getName(config.segment, config.region, i, l); var feather = framework.scene.getObjectByName(name); if (feather !== undefined) { - if (config.segment == "se") { - var start = shoulder; - var end = elbow; - } else if (config.segment == "ew") { - var start = elbow; - var end = wrist; + if (i < settings.density) { + if (config.segment == "se") { + var start = shoulder; + var end = elbow; + } else if (config.segment == "ew") { + var start = elbow; + var end = wrist; + } + + var newPos = v.lerpVectors(start.position, end.position, (fi+1)/10); + var direction = newPos.y - feather.position.y; + feather.position.set(newPos.x, newPos.y+config.yindex, newPos.z+config.zindex); + feather.rotation.z = clamp(-direction, -1, 1); + feather.rotation.x = 0.3 * Math.random(); + feather.visible = true; + + switch (config.color) { + case 1: + feather.material = lambertPrimary; + break; + case 2: + feather.material = lambertSecondary; + break; + case 3: + feather.material = lambertTertiary; + break; + } + } else { + feather.visible = false; } - - var newPos = v.lerpVectors(start.position, end.position, (fi+1)/10); - var direction = newPos.y - feather.position.y; - feather.position.set(newPos.x, newPos.y+config.yindex, newPos.z+config.zindex); - feather.rotation.z = clamp(-direction, -1, 1); - - switch (config.color) { - case 1: - feather.material = lambertPrimary; - break; - case 2: - feather.material = lambertSecondary; - break; - case 3: - feather.material = lambertTertiary; - break; - } - } else { console.log("undefined feather: " + name); } From 8883a2a828fabf5b229cab6e9b9ce62502acc0b0 Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Tue, 31 Jan 2017 09:48:18 -0500 Subject: [PATCH 07/18] added tail --- src/main.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main.js b/src/main.js index 6f20bde..abd54c6 100755 --- a/src/main.js +++ b/src/main.js @@ -144,6 +144,18 @@ function onLoad(framework) { } } } + + + // tail + for (var i = 5; i < 15; i++) { + var featherMesh = new THREE.Mesh(featherGeo, lambertWhite); + var fi = 10 * i / 20; + featherMesh.name = featherConfig.getName("tail", "tail", i, 0); + featherMesh.rotation.y = 3 * fi / 10; + featherMesh.position.set(0,-0.25,0); + featherMesh.scale.set(1,1,1); + scene.add(featherMesh); + } }); var geometry = new THREE.BoxGeometry(0,0,0 ); @@ -290,7 +302,7 @@ function onUpdate(framework) { startTime = (new Date).getTime(); state = (state + 1) % 14; } else { - return;a + return; } var curTime = (new Date).getTime() * settings.speed; @@ -352,6 +364,17 @@ function onUpdate(framework) { } } } + + + // tail + for (var i = 5; i < 15; i++) { + var fi = 10 * i / 20; + var name = featherConfig.getName("tail", "tail", i, 0); + var feather = framework.scene.getObjectByName(name); + if (feather !== undefined) { + feather.rotation.x = 0.05 * Math.random(); + } + } } // when the scene is done initializing, it will call onLoad, then on frame updates, call onUpdate From edd0fbf5664c769d16c2cd9e15f4d1389c41da01 Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Tue, 31 Jan 2017 10:27:40 -0500 Subject: [PATCH 08/18] add right wing --- src/main.js | 338 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 207 insertions(+), 131 deletions(-) diff --git a/src/main.js b/src/main.js index abd54c6..3ed715a 100755 --- a/src/main.js +++ b/src/main.js @@ -1,6 +1,4 @@ - // Skybox texture from: https://github.com/mrdoob/three.js/tree/master/examples/textures/cube/skybox - const THREE = require('three'); // older modules are imported like this. You shouldn't have to worry about this much import Framework from './framework' @@ -12,9 +10,9 @@ var startTime; var settings = { speed: 0.003, - primaryColor: [ 91, 78, 60 ], - secondaryColor: [ 76, 64, 47 ], - tertiaryColor: [ 45, 37, 26 ], + primaryColor: [91, 78, 60], + secondaryColor: [76, 64, 47], + tertiaryColor: [45, 37, 26], elbowX: 3, elbowZ: 5, wristX: 7, @@ -26,14 +24,18 @@ var settings = { } var featherConfig = { - getName: function(segment, region, i, l) { - return "feather(" + segment + "," + region + "," + i + "," + l + ")"; + getName: function(segment, region, side, i, l) { + return "feather(" + segment + "," + region + "," + side + "," + i + "," + l + ")"; }, marginalCoverts: { segment: "se", region: "marginalCoverts", - yaw: function(i) { return 1.6; }, - scale: function(i) { return [0.5 + (Math.random() - 0.5)/3, 1, 1]; }, + yaw: function(i) { + return Math.PI / 2; + }, + scale: function(i) { + return [0.5 + (Math.random() - 0.5) / 3, 1, 1]; + }, color: 1, yindex: 0, zindex: 0 @@ -41,8 +43,12 @@ var featherConfig = { secondaryCoverts: { segment: "se", region: "secondaryCoverts", - yaw: function(i) { return 1.6; }, - scale: function(i) { return [1 + (Math.random() - 0.5)/2, 1, 1]; }, + yaw: function(i) { + return Math.PI / 2; + }, + scale: function(i) { + return [1 + (Math.random() - 0.5) / 2, 1, 1]; + }, color: 2, yindex: -0.05, zindex: -0.5 @@ -50,8 +56,12 @@ var featherConfig = { secondaries: { segment: "se", region: "secondaries", - yaw: function(i) { return 1.6; }, - scale: function(i) { return [1.5 + (Math.random() - 0.5)/2, 1, 1]; }, + yaw: function(i) { + return Math.PI / 2; + }, + scale: function(i) { + return [1.5 + (Math.random() - 0.5) / 2, 1, 1]; + }, color: 3, yindex: -0.1, zindex: -1 @@ -59,8 +69,12 @@ var featherConfig = { alula: { segment: "ew", region: "alula", - yaw: function(i) { return 1.6; }, - scale: function(i) { return [(10 - i)/20 + (Math.random() - 0.5)/3, 1, 1]; }, + yaw: function(i) { + return Math.PI / 2; + }, + scale: function(i) { + return [(10 - i) / 20 + (Math.random() - 0.5) / 3, 1, 1]; + }, color: 1, yindex: 0, zindex: 0 @@ -68,8 +82,19 @@ var featherConfig = { primaryCoverts: { segment: "ew", region: "primaryCoverts", - yaw: function(i) { return 1.6/(1+Math.exp(i-7)); }, - scale: function(i) { return [1 + (Math.random() - 0.5)/2, 1, 1]; }, + yaw: function(i, side) { + if (side == "left") { + var coeff = Math.PI / 2; + var offset = 0; + } else { + var coeff = -Math.PI / 2; + var offset = Math.PI; + } + return coeff / (1 + Math.exp(i - 7)) + offset; + }, + scale: function(i) { + return [1 + (Math.random() - 0.5) / 2, 1, 1]; + }, color: 2, yindex: -0.05, zindex: -0.5 @@ -77,8 +102,19 @@ var featherConfig = { primaries: { segment: "ew", region: "primaries", - yaw: function(i) { return 1.6/(1+Math.exp(i-7)); }, - scale: function(i) { return [1.5 + (Math.random() - 0.5)/2, 1, 1]; }, + yaw: function(i, side) { + if (side == "left") { + var coeff = Math.PI / 2; + var offset = 0; + } else { + var coeff = -Math.PI / 2; + var offset = Math.PI; + } + return coeff / (1 + Math.exp(i - 7)) + offset; + }, + scale: function(i) { + return [1.5 + (Math.random() - 0.5) / 2, 1, 1]; + }, color: 3, yindex: -0.1, zindex: -1 @@ -86,14 +122,15 @@ var featherConfig = { }; var sections = [featherConfig.marginalCoverts, - featherConfig.secondaryCoverts, - featherConfig.secondaries, - featherConfig.alula, - featherConfig.primaryCoverts, - featherConfig.primaries]; + featherConfig.secondaryCoverts, + featherConfig.secondaries, + featherConfig.alula, + featherConfig.primaryCoverts, + featherConfig.primaries +]; function clamp(num, min, max) { - return num <= min ? min : num >= max ? max : num; + return num <= min ? min : num >= max ? max : num; } @@ -106,10 +143,13 @@ function onLoad(framework) { var stats = framework.stats; // Basic Lambert - var lambertWhite = new THREE.MeshLambertMaterial({ color: 0xffffff, side: THREE.DoubleSide }); + var lambertWhite = new THREE.MeshLambertMaterial({ + color: 0xffffff, + side: THREE.DoubleSide + }); // Set light - var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 ); + var directionalLight = new THREE.DirectionalLight(0xffffff, 1); directionalLight.color.setHSL(0.1, 1, 0.95); directionalLight.position.set(1, 3, 2); directionalLight.position.multiplyScalar(10); @@ -122,7 +162,7 @@ function onLoad(framework) { urlPrefix + 'px.jpg', urlPrefix + 'nx.jpg', urlPrefix + 'py.jpg', urlPrefix + 'ny.jpg', urlPrefix + 'pz.jpg', urlPrefix + 'nz.jpg' - ] ); + ]); scene.background = skymap; @@ -130,85 +170,100 @@ function onLoad(framework) { var objLoader = new THREE.OBJLoader(); objLoader.load('/geo/feather.obj', function(obj) { var featherGeo = obj.children[0].geometry; - for (var s = 0; s < sections.length; s++) { - var config = sections[s]; - for (var l = 0; l < settings.numLayers; l++) { - for (var i = 0; i < settings.density; i++) { - var fi = 10 * i / settings.density; - var featherMesh = new THREE.Mesh(featherGeo, lambertWhite); - featherMesh.name = featherConfig.getName(config.segment, config.region, i, l); - featherMesh.rotation.y = config.yaw(fi); - var scale = config.scale(fi); - featherMesh.scale.set(scale[0], scale[1], scale[2]); - scene.add(featherMesh); + + ["left", "right"].forEach(function(value, index, array) { + var side = value; + for (var s = 0; s < sections.length; s++) { + var config = sections[s]; + for (var l = 0; l < settings.numLayers; l++) { + for (var i = 0; i < settings.density; i++) { + var fi = 10 * i / settings.density; + var featherMesh = new THREE.Mesh(featherGeo, lambertWhite); + featherMesh.name = featherConfig.getName(config.segment, config.region, side, i, l); + featherMesh.rotation.y = config.yaw(fi, side); + var scale = config.scale(fi); + featherMesh.scale.set(scale[0], scale[1], scale[2]); + scene.add(featherMesh); + } } } - } - + }); // tail for (var i = 5; i < 15; i++) { var featherMesh = new THREE.Mesh(featherGeo, lambertWhite); var fi = 10 * i / 20; - featherMesh.name = featherConfig.getName("tail", "tail", i, 0); + featherMesh.name = featherConfig.getName("tail", "tail", "center", i, 0); featherMesh.rotation.y = 3 * fi / 10; - featherMesh.position.set(0,-0.25,0); - featherMesh.scale.set(1,1,1); + featherMesh.position.set(0, -0.25, 0); + featherMesh.scale.set(1, 1, 1); scene.add(featherMesh); } }); - var geometry = new THREE.BoxGeometry(0,0,0 ); - var material = new THREE.MeshBasicMaterial( {color: 0xCB2400} ); - var shoulder = new THREE.Mesh( geometry, material ); - shoulder.position.set(0,0,5); + var geometry = new THREE.BoxGeometry(0, 0, 0); + var material = new THREE.MeshBasicMaterial({ + color: 0xCB2400 + }); + var shoulder = new THREE.Mesh(geometry, material); + shoulder.position.set(0, 0, 5); shoulder.name = "shoulder"; - scene.add( shoulder ); + scene.add(shoulder); - var geometry = new THREE.BoxGeometry( 0,0,0); - var material = new THREE.MeshBasicMaterial( {color: 0xC67563} ); - var elbow = new THREE.Mesh( geometry, material ); - elbow.position.set(3,-3,5); + var geometry = new THREE.BoxGeometry(0, 0, 0); + var material = new THREE.MeshBasicMaterial({ + color: 0xC67563 + }); + var elbow = new THREE.Mesh(geometry, material); + elbow.position.set(3, -3, 5); elbow.name = "elbow"; - scene.add( elbow ); + scene.add(elbow); - var geometry = new THREE.BoxGeometry(0,0,0 ); - var material = new THREE.MeshBasicMaterial( {color: 0xCAA8A1} ); - var wrist = new THREE.Mesh( geometry, material ); - wrist.position.set(7,-7,5); + var geometry = new THREE.BoxGeometry(0, 0, 0); + var material = new THREE.MeshBasicMaterial({ + color: 0xCAA8A1 + }); + var wrist = new THREE.Mesh(geometry, material); + wrist.position.set(7, -7, 5); wrist.name = "wrist"; - scene.add( wrist ); + scene.add(wrist); // beak - var geometry = new THREE.CylinderGeometry( 0.01, 0.5, 2, 5 ); - var material = new THREE.MeshBasicMaterial( {color: 0xffff00} ); - var cylinder = new THREE.Mesh( geometry, material ); - cylinder.position.set(0,0,6); + var geometry = new THREE.CylinderGeometry(0.01, 0.5, 2, 5); + var material = new THREE.MeshBasicMaterial({ + color: 0xffff00 + }); + var cylinder = new THREE.Mesh(geometry, material); + cylinder.position.set(0, 0, 6); cylinder.rotation.x = 2; - scene.add( cylinder ); + scene.add(cylinder); // head - var geometry = new THREE.CylinderGeometry( 0.7, 0.8, 1, 5 ); - var material = new THREE.MeshBasicMaterial( {color: 0xf7f4ef} ); - var cylinder = new THREE.Mesh( geometry, material ); - cylinder.position.set(0,0.5,5.5); + var geometry = new THREE.CylinderGeometry(0.7, 0.8, 1, 5); + var material = new THREE.MeshBasicMaterial({ + color: 0xf7f4ef + }); + var cylinder = new THREE.Mesh(geometry, material); + cylinder.position.set(0, 0.5, 5.5); cylinder.rotation.x = 1.8; - scene.add( cylinder ); + scene.add(cylinder); // body - var geometry = new THREE.CylinderGeometry( 1, 0.8, 6, 5 ); - var material = new THREE.MeshBasicMaterial( {color: 0x2d251a} ); - var cylinder = new THREE.Mesh( geometry, material ); - cylinder.position.set(0,-0.5,2); + var geometry = new THREE.CylinderGeometry(1, 0.8, 6, 5); + var material = new THREE.MeshBasicMaterial({ + color: 0x2d251a + }); + var cylinder = new THREE.Mesh(geometry, material); + cylinder.position.set(0, -0.5, 2); cylinder.rotation.x = 1.4; cylinder.name = "body"; - scene.add( cylinder ); + scene.add(cylinder); // set camera position camera.position.set(0, 10, 10); - camera.lookAt(new THREE.Vector3(0,0,0)); + camera.lookAt(new THREE.Vector3(0, 0, 0)); // scene.add(lambertCube); scene.add(directionalLight); @@ -225,28 +280,28 @@ function onLoad(framework) { gui.addColor(settings, 'secondaryColor'); gui.addColor(settings, 'tertiaryColor'); - gui.add(settings, 'elbowX',0, 10).onChange(function(newVal) { + gui.add(settings, 'elbowX', 0, 10).onChange(function(newVal) { var elbow = framework.scene.getObjectByName("elbow"); if (elbow !== undefined) { elbow.position.set(newVal, elbow.position.y, elbow.position.z); } }); - gui.add(settings, 'elbowZ',0, 10).onChange(function(newVal) { + gui.add(settings, 'elbowZ', 0, 10).onChange(function(newVal) { var elbow = framework.scene.getObjectByName("elbow"); if (elbow !== undefined) { elbow.position.set(elbow.position.x, elbow.position.y, newVal); } }); - gui.add(settings, 'wristX',0, 10).onChange(function(newVal) { + gui.add(settings, 'wristX', 0, 10).onChange(function(newVal) { var wrist = framework.scene.getObjectByName("wrist"); if (wrist !== undefined) { wrist.position.set(newVal, wrist.position.y, wrist.position.z); } }); - gui.add(settings, 'wristZ',0, 10).onChange(function(newVal) { + gui.add(settings, 'wristZ', 0, 10).onChange(function(newVal) { var wrist = framework.scene.getObjectByName("wrist"); if (wrist !== undefined) { elbow.position.set(wrist.position.x, wrist.position.y, newVal); @@ -260,9 +315,9 @@ function onLoad(framework) { var elbow = framework.scene.getObjectByName("elbow"); if (elbow !== undefined) { if (newVal) { - var geometry = new THREE.BoxGeometry(1,1,1); + var geometry = new THREE.BoxGeometry(1, 1, 1); } else { - var geometry = new THREE.BoxGeometry(0,0,0); + var geometry = new THREE.BoxGeometry(0, 0, 0); } elbow.geometry = geometry; } @@ -270,9 +325,9 @@ function onLoad(framework) { var wrist = framework.scene.getObjectByName("wrist"); if (wrist !== undefined) { if (newVal) { - var geometry = new THREE.BoxGeometry(1,1,1); + var geometry = new THREE.BoxGeometry(1, 1, 1); } else { - var geometry = new THREE.BoxGeometry(0,0,0); + var geometry = new THREE.BoxGeometry(0, 0, 0); } wrist.geometry = geometry; } @@ -284,14 +339,23 @@ function onLoad(framework) { // called on frame updates function onUpdate(framework) { - var primaryColor = new THREE.Color(settings.primaryColor[0]/255, settings.primaryColor[1]/255, settings.primaryColor[2]/255); - var secondaryColor = new THREE.Color(settings.secondaryColor[0]/255, settings.secondaryColor[1]/255, settings.secondaryColor[2]/255); - var tertiaryColor = new THREE.Color(settings.tertiaryColor[0]/255, settings.tertiaryColor[1]/255, settings.tertiaryColor[2]/255); - var lambertPrimary = new THREE.MeshLambertMaterial({ color: primaryColor, side: THREE.DoubleSide }); - var lambertSecondary = new THREE.MeshLambertMaterial({ color: secondaryColor, side: THREE.DoubleSide }); - var lambertTertiary = new THREE.MeshLambertMaterial({ color: tertiaryColor, side: THREE.DoubleSide }); + var primaryColor = new THREE.Color(settings.primaryColor[0] / 255, settings.primaryColor[1] / 255, settings.primaryColor[2] / 255); + var secondaryColor = new THREE.Color(settings.secondaryColor[0] / 255, settings.secondaryColor[1] / 255, settings.secondaryColor[2] / 255); + var tertiaryColor = new THREE.Color(settings.tertiaryColor[0] / 255, settings.tertiaryColor[1] / 255, settings.tertiaryColor[2] / 255); + var lambertPrimary = new THREE.MeshLambertMaterial({ + color: primaryColor, + side: THREE.DoubleSide + }); + var lambertSecondary = new THREE.MeshLambertMaterial({ + color: secondaryColor, + side: THREE.DoubleSide + }); + var lambertTertiary = new THREE.MeshLambertMaterial({ + color: tertiaryColor, + side: THREE.DoubleSide + }); - var v = new THREE.Vector3(0,0,0); + var v = new THREE.Vector3(0, 0, 0); // increment the state every timeDelta milliseconds // and set the lerp alpha to equal the percentage of time elapsed between state changes @@ -311,7 +375,7 @@ function onUpdate(framework) { var shoulder = framework.scene.getObjectByName("shoulder"); var elbow = framework.scene.getObjectByName("elbow"); if (elbow !== undefined) { - elbow.position.set(elbow.position.x, 3 * Math.sin(curTime+1 + 0.5 * Math.sin(curTime+1)), elbow.position.z); + elbow.position.set(elbow.position.x, 3 * Math.sin(curTime + 1 + 0.5 * Math.sin(curTime + 1)), elbow.position.z); } var wrist = framework.scene.getObjectByName("wrist"); @@ -319,57 +383,69 @@ function onUpdate(framework) { wrist.position.set(wrist.position.x, 6 * Math.sin(curTime + 0.5 * Math.sin(curTime)), wrist.position.z); } - for (var s = 0; s < sections.length; s++) { - var config = sections[s]; - for (var l = 0; l < settings.numLayers; l++) { - for (var i = 0; i < settings.maxDensity; i++) { - var fi = 10 * i / settings.density; - var name = featherConfig.getName(config.segment, config.region, i, l); - var feather = framework.scene.getObjectByName(name); - if (feather !== undefined) { - - if (i < settings.density) { - if (config.segment == "se") { - var start = shoulder; - var end = elbow; - } else if (config.segment == "ew") { - var start = elbow; - var end = wrist; - } - - var newPos = v.lerpVectors(start.position, end.position, (fi+1)/10); - var direction = newPos.y - feather.position.y; - feather.position.set(newPos.x, newPos.y+config.yindex, newPos.z+config.zindex); - feather.rotation.z = clamp(-direction, -1, 1); - feather.rotation.x = 0.3 * Math.random(); - feather.visible = true; - - switch (config.color) { - case 1: - feather.material = lambertPrimary; - break; - case 2: - feather.material = lambertSecondary; - break; - case 3: - feather.material = lambertTertiary; - break; + ["left", "right"].forEach(function(value, index, array) { + var side = value; + for (var s = 0; s < sections.length; s++) { + var config = sections[s]; + for (var l = 0; l < settings.numLayers; l++) { + for (var i = 0; i < settings.maxDensity; i++) { + var fi = 10 * i / settings.density; + var name = featherConfig.getName(config.segment, config.region, side, i, l); + var feather = framework.scene.getObjectByName(name); + if (feather !== undefined) { + + if (i < settings.density) { + + if (config.segment == "se") { + var start = shoulder; + var end = elbow; + } else if (config.segment == "ew") { + var start = elbow; + var end = wrist; + } + + if (side == "right") { + var coeff = -1; + } else { + var coeff = 1; + } + + + var newPos = v.lerpVectors(start.position, end.position, (fi + 1) / 10); + var direction = newPos.y - feather.position.y; + feather.position.set(coeff * newPos.x, newPos.y + config.yindex, newPos.z + config.zindex); + feather.rotation.z = clamp(-direction, -1, 1); + feather.rotation.x = 0.3 * Math.random(); + feather.visible = true; + + switch (config.color) { + case 1: + feather.material = lambertPrimary; + break; + case 2: + feather.material = lambertSecondary; + break; + case 3: + feather.material = lambertTertiary; + break; + } + } else { + feather.visible = false; } } else { - feather.visible = false; + console.log("undefined feather: " + name); } - } else { - console.log("undefined feather: " + name); } } } - } + }); + // tail for (var i = 5; i < 15; i++) { var fi = 10 * i / 20; - var name = featherConfig.getName("tail", "tail", i, 0); + var name = featherConfig.getName("tail", "tail", "center", i, 0); var feather = framework.scene.getObjectByName(name); if (feather !== undefined) { feather.rotation.x = 0.05 * Math.random(); From f61c2cce4286a81c80fb9b795f94c9e5c578fc09 Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Tue, 31 Jan 2017 10:34:21 -0500 Subject: [PATCH 09/18] add body movement --- src/main.js | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/main.js b/src/main.js index 3ed715a..b45d8d0 100755 --- a/src/main.js +++ b/src/main.js @@ -250,7 +250,7 @@ function onLoad(framework) { scene.add(cylinder); // body - var geometry = new THREE.CylinderGeometry(1, 0.8, 6, 5); + var geometry = new THREE.CylinderGeometry(1.2, 0.8, 6, 5); var material = new THREE.MeshBasicMaterial({ color: 0x2d251a }); @@ -375,7 +375,24 @@ function onUpdate(framework) { var shoulder = framework.scene.getObjectByName("shoulder"); var elbow = framework.scene.getObjectByName("elbow"); if (elbow !== undefined) { - elbow.position.set(elbow.position.x, 3 * Math.sin(curTime + 1 + 0.5 * Math.sin(curTime + 1)), elbow.position.z); + var newY = 3 * Math.sin(curTime + 1 + 0.5 * Math.sin(curTime + 1)); + var delta = 0.05 * (newY - elbow.position.y); + elbow.position.set(elbow.position.x, newY, elbow.position.z); + var body = framework.scene.getObjectByName("body"); + if (body !== undefined) { + body.position.set(body.position.x, body.position.y - delta, body.position.z); + } + + // tail + for (var i = 5; i < 15; i++) { + var fi = 10 * i / 20; + var name = featherConfig.getName("tail", "tail", "center", i, 0); + var feather = framework.scene.getObjectByName(name); + if (feather !== undefined) { + feather.rotation.x = 0.05 * Math.random(); + feather.position.set(feather.position.x, feather.position.y - delta, feather.position.z); + } + } } var wrist = framework.scene.getObjectByName("wrist"); @@ -439,18 +456,6 @@ function onUpdate(framework) { } } }); - - - - // tail - for (var i = 5; i < 15; i++) { - var fi = 10 * i / 20; - var name = featherConfig.getName("tail", "tail", "center", i, 0); - var feather = framework.scene.getObjectByName(name); - if (feather !== undefined) { - feather.rotation.x = 0.05 * Math.random(); - } - } } // when the scene is done initializing, it will call onLoad, then on frame updates, call onUpdate From a7efa4caeb966a5d0ac64d886e1d028d4e8f5b4c Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Tue, 31 Jan 2017 11:35:31 -0500 Subject: [PATCH 10/18] fix run deploy --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c80e8a3..566ab25 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,8 @@ "scripts": { "start": "webpack-dev-server --hot --inline", "build": "webpack", - "deploy": "rm -rf npm-debug.log && git checkout master && git commit -am 'update' && gh-pages-deploy" - }, + "deploy": "gh-pages-deploy" + } "gh-pages-deploy": { "prep": [ "build" From 15ebb3291322aa1ebb61e83491066ee1047660a1 Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Tue, 31 Jan 2017 11:37:21 -0500 Subject: [PATCH 11/18] fix run deploy --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 566ab25..cde25c8 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "start": "webpack-dev-server --hot --inline", "build": "webpack", "deploy": "gh-pages-deploy" - } + }, "gh-pages-deploy": { "prep": [ "build" From 16af06b2385e9a2e565ab58cf05c87e1d4a17fb6 Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Tue, 31 Jan 2017 12:00:51 -0500 Subject: [PATCH 12/18] remove leading slash on resources --- src/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.js b/src/main.js index b45d8d0..702bc3a 100755 --- a/src/main.js +++ b/src/main.js @@ -156,7 +156,7 @@ function onLoad(framework) { // set skybox var loader = new THREE.CubeTextureLoader(); - var urlPrefix = '/images/skymap/'; + var urlPrefix = 'images/skymap/'; var skymap = new THREE.CubeTextureLoader().load([ urlPrefix + 'px.jpg', urlPrefix + 'nx.jpg', From bd0c8b0a587e6a1f99b6d70da7323fa96928becd Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Tue, 31 Jan 2017 13:28:27 -0500 Subject: [PATCH 13/18] remove leading slash for obj --- src/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.js b/src/main.js index 702bc3a..fc60e30 100755 --- a/src/main.js +++ b/src/main.js @@ -168,7 +168,7 @@ function onLoad(framework) { // load a simple obj mesh var objLoader = new THREE.OBJLoader(); - objLoader.load('/geo/feather.obj', function(obj) { + objLoader.load('geo/feather.obj', function(obj) { var featherGeo = obj.children[0].geometry; ["left", "right"].forEach(function(value, index, array) { From d741c960caebb9199bec322b430b4cd8e6a5b16b Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Tue, 31 Jan 2017 14:38:09 -0500 Subject: [PATCH 14/18] Update README.md --- README.md | 84 +++++++++++-------------------------------------------- 1 file changed, 17 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 1410c30..c5ef0e2 100644 --- a/README.md +++ b/README.md @@ -1,82 +1,32 @@ # [Project2: Toolbox Functions](https://github.com/CIS700-Procedural-Graphics/Project2-Toolbox-Functions) -## Overview +## Wing Structure +Consists of three joints (shoulder, elbow, wrist). The shoulder joint is stationary within the body but the wrist and elbow are located at a fixed distance (in the x and z direction) from the body. Feathers are placed on an interpolated line between each pair of joints. Each region of feathers is created by offsetting from this interpolated line. -The objective of this assignment is to procedurally model and animate a bird wing. Let's get creative! +## Wing Animation +My goal was to emulate a motion like this: -Start by forking and then cloning [this repository](https://github.com/CIS700-Procedural-Graphics/Project2-Toolbox-Functions) +![Flapping Motion](https://i.imgur.com/F0Ms1qz.png) -## Modeling +Given that the shoulder joint (green) is stationary, the relative y position of the elbow (red) and wrist (blue) looks something like this: -##### Reference images +![Joint Displacements](https://i.imgur.com/vb2zfz0.png) -Search for three or more images of a bird wing (or any flying creature, really) in order to provide yourself reference material, as you're going to base your modeling and animation from these images. For the more artistic minds, feel free to sketch your own concept. +The first thing to note is that the falling edge on each oscillation takes longer than the rising edge, simulating the the longer downstroke[\[1\]](http://www.brendanbody.co.uk/flight_tutorial/). This asymmetric sine wave is achieved using some variation of this equation: sin(x + a * sin(x))[\[2\]](https://www.quora.com/How-can-I-draw-this-irregular-Sine-function-in-MATLAB-Should-I-add-multiple-the-Sine-function-to-another-term). -##### Make wing curve -Begin with a 3D curve for your basic wing shape. Three.js provides classes to create many different types of curves, so you may use whatever type of curve you prefer. +The next feature is that the elbow displacement must reach its highest and lowest points slightly before the wrist does. It's important that this is a translation of the function and not a stretch or else the periods will go out of sync. -##### Distribute feathers +Lastly, the amplitude of the elbow displacement is less than that of the wrist. -We have provided a simple feather model from which to begin. You are not required to use this model if you have others that you prefer. From this base, you must duplicate the feather to model a complete wing, and your wing should consist of at least thirty feathers. Distribute points along the curve you created previously; you will append the feather primitives to the curve at these points. Make sure that you modify the size, orientation, and color of your feathers depending on their location on the wing. +## Demo +Demo: https://iambrian.github.io/Project2-Toolbox-Functions/ -Feel free to diversify your wings by using multiple base feather models. +![Demo](https://i.imgur.com/VuYbEaP.gif) -## Animation +## References +Bird wing motion: http://www.brendanbody.co.uk/flight_tutorial/ -Add a wind force to your scene, and parameterize its direction and speed. You will use this wind force to animate the feathers of your wing by vibrating them slightly. Using Dat.GUI, allow the user to modify these wind parameters. Please note that we don't care about your feather motion being physically accurate, as long as it looks nice. +Baseline sine function: https://www.quora.com/How-can-I-draw-this-irregular-Sine-function-in-MATLAB-Should-I-add-multiple-the-Sine-function-to-another-term -Additionally, animate the control points of your wing curve to make the wing flap, and allow the user to control the speed of the wing flapping. - -## Interactivity - -Using Dat.GUI and the examples provided in the reference code, allow the user to adjust the following controls: - -1. The curvature of the wing's basic shape -2. Feather distribution -3. Feather size -4. Feather color -5. Feather orientation -6. Flapping speed -7. Flapping motion - -## For the Overachievers - -Suggestions: -- Make a pretty iridescent or otherwise feather appropriate shader. -- Otherwise, going the extra mile for this assignment is really in the polish! - -## Submission - -- Create a folder called `references` to include your reference images. - -- Update `README.md` to contain a solid description of your project - -- Publish your project to gh-pages. `npm run deploy`. It should now be visible at http://username.github.io/repo-name - -- Create a [pull request](https://help.github.com/articles/creating-a-pull-request/) to this repository, and in the comment, include a link to your published project. - -- Submit the link to your pull request on Canvas. - -## Getting Started - -1. [Install Node.js](https://nodejs.org/en/download/). Node.js is a JavaScript runtime. It basically allows you to run JavaScript when not in a browser. For our purposes, this is not necessary. The important part is that with it comes `npm`, the Node Package Manager. This allows us to easily declare and install external dependencies such as [three.js](https://threejs.org/), [dat.GUI](https://workshop.chromeexperiments.com/examples/gui/#1--Basic-Usage), and [glMatrix](http://glmatrix.net/). Some other packages we'll be using make it significantly easier to develop your code and create modules for better code reuse and clarity. These tools make it _signficantly_ easier to write code in multiple `.js` files without globally defining everything. - -2. Fork and clone your repository. - -3. In the root directory of your project, run `npm install`. This will download all of those dependencies. - -4. Do either of the following (but I highly recommend the first one for reasons I will explain later). - - a. Run `npm start` and then go to `localhost:7000` in your web browser - - b. Run `npm run build` and then go open `index.html` in your web browser - - You should hopefully see the framework code with a 3D cube at the center of the screen! - - -## Developing Your Code -All of the JavaScript code is living inside the `src` directory. The main file that gets executed when you load the page as you may have guessed is `main.js`. Here, you can make any changes you want, import functions from other files, etc. The reason that I highly suggest you build your project with `npm start` is that doing so will start a process that watches for any changes you make to your code. If it detects anything, it'll automagically rebuild your project and then refresh your browser window for you. Wow. That's cool. If you do it the other way, you'll need to run `npm build` and then refresh your page every time you want to test something. - -## Publishing Your Code -We highly suggest that you put your code on GitHub. One of the reasons we chose to make this course using JavaScript is that the Web is highly accessible and making your awesome work public and visible can be a huge benefit when you're looking to score a job or internship. To aid you in this process, running `npm run deploy` will automatically build your project and push it to `gh-pages` where it will be visible at `username.github.io/repo-name`. \ No newline at end of file +Graphing: http://www.iquilezles.org/apps/graphtoy/ From dcdb7f374eb833d221edd97b403612012587f536 Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Tue, 31 Jan 2017 15:29:04 -0500 Subject: [PATCH 15/18] use spline --- src/main.js | 84 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 19 deletions(-) diff --git a/src/main.js b/src/main.js index fc60e30..6a71bfc 100755 --- a/src/main.js +++ b/src/main.js @@ -20,6 +20,8 @@ var settings = { numLayers: 1, maxDensity: 40, density: 40, + windSpeed: 0.3, + windDirection: 0.0, showCtrlPts: false } @@ -201,34 +203,53 @@ function onLoad(framework) { } }); - var geometry = new THREE.BoxGeometry(0, 0, 0); + var geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5); var material = new THREE.MeshBasicMaterial({ color: 0xCB2400 }); var shoulder = new THREE.Mesh(geometry, material); shoulder.position.set(0, 0, 5); shoulder.name = "shoulder"; + shoulder.visible = settings.showCtrlPts; scene.add(shoulder); - var geometry = new THREE.BoxGeometry(0, 0, 0); + var geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5); var material = new THREE.MeshBasicMaterial({ color: 0xC67563 }); var elbow = new THREE.Mesh(geometry, material); elbow.position.set(3, -3, 5); elbow.name = "elbow"; + elbow.visible = settings.showCtrlPts; scene.add(elbow); - var geometry = new THREE.BoxGeometry(0, 0, 0); + var geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5); var material = new THREE.MeshBasicMaterial({ color: 0xCAA8A1 }); var wrist = new THREE.Mesh(geometry, material); wrist.position.set(7, -7, 5); wrist.name = "wrist"; + wrist.visible = settings.showCtrlPts; scene.add(wrist); + // spline + var curve = new THREE.SplineCurve3( [ + shoulder.position, + elbow.position, + wrist.position + ] ); + var path = new THREE.Path( curve.getPoints( 50 ) ); + var geometry = path.createPointsGeometry( 50 ); + var material = new THREE.LineBasicMaterial( { color : 0xff0000 } ); + + // Create the final object to add to the scene + var splineObject = new THREE.Line( geometry, material ); + splineObject.name = "spline"; + splineObject.visible = settings.showCtrlPts; + scene.add(splineObject); + // beak var geometry = new THREE.CylinderGeometry(0.01, 0.5, 2, 5); var material = new THREE.MeshBasicMaterial({ @@ -312,27 +333,30 @@ function onLoad(framework) { gui.add(settings, 'showCtrlPts').onChange(function(newVal) { var shoulder = framework.scene.getObjectByName("shoulder"); + if (shoulder !== undefined) { + shoulder.visible = newVal; + } + var elbow = framework.scene.getObjectByName("elbow"); if (elbow !== undefined) { - if (newVal) { - var geometry = new THREE.BoxGeometry(1, 1, 1); - } else { - var geometry = new THREE.BoxGeometry(0, 0, 0); - } - elbow.geometry = geometry; + elbow.visible = newVal; } var wrist = framework.scene.getObjectByName("wrist"); if (wrist !== undefined) { - if (newVal) { - var geometry = new THREE.BoxGeometry(1, 1, 1); - } else { - var geometry = new THREE.BoxGeometry(0, 0, 0); - } - wrist.geometry = geometry; + wrist.visible = newVal; } + + var spline = framework.scene.getObjectByName("spline"); + if (spline !== undefined) { + spline.visible = newVal; + } + }); + gui.add(settings, 'windSpeed', 0.0, 1.0); + gui.add(settings, 'windDirection', -1.0, 1.0); + startTime = (new Date).getTime(); } @@ -372,6 +396,7 @@ function onUpdate(framework) { var curTime = (new Date).getTime() * settings.speed; var freq = settings.speed; + // joints var shoulder = framework.scene.getObjectByName("shoulder"); var elbow = framework.scene.getObjectByName("elbow"); if (elbow !== undefined) { @@ -389,7 +414,7 @@ function onUpdate(framework) { var name = featherConfig.getName("tail", "tail", "center", i, 0); var feather = framework.scene.getObjectByName(name); if (feather !== undefined) { - feather.rotation.x = 0.05 * Math.random(); + feather.rotation.x = settings.windSpeed * 0.1 * Math.random(); feather.position.set(feather.position.x, feather.position.y - delta, feather.position.z); } } @@ -400,6 +425,24 @@ function onUpdate(framework) { wrist.position.set(wrist.position.x, 6 * Math.sin(curTime + 0.5 * Math.sin(curTime)), wrist.position.z); } + // spline + + // Create the final object to add to the scene + var splineObject = framework.scene.getObjectByName("spline"); + if (splineObject !== undefined) { + var curve = new THREE.SplineCurve3( [ + shoulder.position, + elbow.position, + wrist.position + ] ); + var path = new THREE.Path( curve.getPoints( 50 ) ); + var geometry = path.createPointsGeometry( 50 ); + splineObject.geometry = geometry; + splineObject.position.set(shoulder.position.x, shoulder.position.y, shoulder.position.z); + } + + + // feathers ["left", "right"].forEach(function(value, index, array) { var side = value; for (var s = 0; s < sections.length; s++) { @@ -416,9 +459,11 @@ function onUpdate(framework) { if (config.segment == "se") { var start = shoulder; var end = elbow; + var t = fi / 10 * 0.5; } else if (config.segment == "ew") { var start = elbow; var end = wrist; + var t = fi / 10 * 0.5 + 0.5; } if (side == "right") { @@ -427,12 +472,13 @@ function onUpdate(framework) { var coeff = 1; } - - var newPos = v.lerpVectors(start.position, end.position, (fi + 1) / 10); + // var newPos = v.lerpVectors(start.position, end.position, (fi + 1) / 10); + var newPos = curve.getPoint(t); var direction = newPos.y - feather.position.y; feather.position.set(coeff * newPos.x, newPos.y + config.yindex, newPos.z + config.zindex); feather.rotation.z = clamp(-direction, -1, 1); - feather.rotation.x = 0.3 * Math.random(); + feather.rotation.x = settings.windSpeed * Math.random(); + feather.rotation.y = config.yaw(fi, side) - settings.windDirection; feather.visible = true; switch (config.color) { From e75d67f5e8624f5ae11384f86f87b91d5e3e1254 Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Tue, 31 Jan 2017 15:32:52 -0500 Subject: [PATCH 16/18] add spline toggle --- src/main.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main.js b/src/main.js index 6a71bfc..94e0d87 100755 --- a/src/main.js +++ b/src/main.js @@ -22,7 +22,8 @@ var settings = { density: 40, windSpeed: 0.3, windDirection: 0.0, - showCtrlPts: false + showCtrlPts: false, + toggleSpline: true } var featherConfig = { @@ -357,6 +358,8 @@ function onLoad(framework) { gui.add(settings, 'windSpeed', 0.0, 1.0); gui.add(settings, 'windDirection', -1.0, 1.0); + gui.add(settings, 'toggleSpline'); + startTime = (new Date).getTime(); } @@ -472,8 +475,11 @@ function onUpdate(framework) { var coeff = 1; } - // var newPos = v.lerpVectors(start.position, end.position, (fi + 1) / 10); - var newPos = curve.getPoint(t); + if (settings.toggleSpline) { + var newPos = curve.getPoint(t); + } else { + var newPos = v.lerpVectors(start.position, end.position, (fi + 1) / 10); + } var direction = newPos.y - feather.position.y; feather.position.set(coeff * newPos.x, newPos.y + config.yindex, newPos.z + config.zindex); feather.rotation.z = clamp(-direction, -1, 1); From c7762f9fa61c3407464824c2cec14f26fcb5aa76 Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Tue, 31 Jan 2017 15:35:40 -0500 Subject: [PATCH 17/18] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c5ef0e2..ff865ae 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # [Project2: Toolbox Functions](https://github.com/CIS700-Procedural-Graphics/Project2-Toolbox-Functions) ## Wing Structure -Consists of three joints (shoulder, elbow, wrist). The shoulder joint is stationary within the body but the wrist and elbow are located at a fixed distance (in the x and z direction) from the body. Feathers are placed on an interpolated line between each pair of joints. Each region of feathers is created by offsetting from this interpolated line. +Consists of three joints (shoulder, elbow, wrist). The shoulder joint is stationary within the body but the wrist and elbow are located at a fixed distance (in the x and z direction) from the body. Feathers are placed on a spline with control points at each joint or simply linearly interpolated between pairs of joints (use toggleSpline). Each region of feathers is created by offsetting from this interpolated line. ## Wing Animation My goal was to emulate a motion like this: From ae8598e35c1e5b2e3e4eb9f41e47800e8d7456e9 Mon Sep 17 00:00:00 2001 From: Brian Tong Date: Tue, 31 Jan 2017 15:44:05 -0500 Subject: [PATCH 18/18] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ff865ae..cb2a5dc 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,11 @@ Given that the shoulder joint (green) is stationary, the relative y position of ![Joint Displacements](https://i.imgur.com/vb2zfz0.png) -The first thing to note is that the falling edge on each oscillation takes longer than the rising edge, simulating the the longer downstroke[\[1\]](http://www.brendanbody.co.uk/flight_tutorial/). This asymmetric sine wave is achieved using some variation of this equation: sin(x + a * sin(x))[\[2\]](https://www.quora.com/How-can-I-draw-this-irregular-Sine-function-in-MATLAB-Should-I-add-multiple-the-Sine-function-to-another-term). +This pair of functions has a couple of key characteristics: +The falling edge on each oscillation should take longer than the rising edge. This makes the wing motion more realistic as the upstroke is about twice as fast as the downstroke[\[1\]](http://www.brendanbody.co.uk/flight_tutorial/). This asymmetric sine wave is achieved using some variation of this function: sin(x + a * sin(x))[\[2\]](https://www.quora.com/How-can-I-draw-this-irregular-Sine-function-in-MATLAB-Should-I-add-multiple-the-Sine-function-to-another-term). -The next feature is that the elbow displacement must reach its highest and lowest points slightly before the wrist does. It's important that this is a translation of the function and not a stretch or else the periods will go out of sync. +The elbow displacement function must reach its high and low peaks slightly before the wrist does. It's important that this is a translation of the function or else the periods will go out of sync. Lastly, the amplitude of the elbow displacement is less than that of the wrist.