Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# [Project2: Toolbox Functions](https://github.com/CIS700-Procedural-Graphics/Project2-Toolbox-Functions)

##### Stauffer submission

Alas, still not enough time to do all the magic. I am happy at least I got the rotations worked out so the feathers stay in the plane of the wing as it flaps.







## Overview

The objective of this assignment is to procedurally model and animate a bird wing. Let's get creative!
Expand Down
Binary file added bird-wing-diagram-w-skeleton.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added bird-wing-diagram.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions src/framework.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,24 @@ function init(callback, update) {
framework.camera = camera;
framework.renderer = renderer;

// my parameters
var stauff = {
numFeathers: 50,
featherIds: [], //array of feather object id's
controlPointsUp: [
new THREE.Vector3( 0, 0, 0 ),
new THREE.Vector3( 0, 4, 5 ),
new THREE.Vector3( -1.5, 1, 10 )
],
controlPointsDown: [
new THREE.Vector3( 0, 0, 0 ),
new THREE.Vector3( 0, -1.8, 5 ),
new THREE.Vector3( 1, -1.2, 10 )
]
};
framework.stauff = stauff;


// begin the animation loop
(function tick() {
stats.begin();
Expand Down
127 changes: 114 additions & 13 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ function onLoad(framework) {
var renderer = framework.renderer;
var gui = framework.gui;
var stats = framework.stats;

var stauff = framework.stauff;

// Basic Lambert white
var lambertWhite = new THREE.MeshLambertMaterial({ color: 0xaaaaaa, side: THREE.DoubleSide });

Expand All @@ -21,7 +22,7 @@ function onLoad(framework) {
directionalLight.position.set(1, 3, 2);
directionalLight.position.multiplyScalar(10);

// set skybox
// set skybox background
var loader = new THREE.CubeTextureLoader();
var urlPrefix = '/images/skymap/';

Expand All @@ -40,14 +41,33 @@ 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 f = 0; f < stauff.numFeathers; f++ ){
var featherMesh = new THREE.Mesh(featherGeo, lambertWhite);
featherMesh.name = "feather" + featherMesh.id;
stauff.featherIds.push(featherMesh.id);
scene.add(featherMesh);
}
});

//// curve
stauff.curveUp = new THREE.CatmullRomCurve3( stauff.controlPointsUp );
stauff.curveDown = new THREE.CatmullRomCurve3( stauff.controlPointsDown )

var curve = new THREE.CatmullRomCurve3( stauff.controlPointsUp );
var geometry = new THREE.Geometry();
geometry.vertices = stauff.curveUp.getPoints( 50 );

var material = new THREE.LineBasicMaterial( { color : 0xff0000 } );

// Create the final object to add to the scene if we want to see it
var curveObject = new THREE.Line( geometry, material );
//scene.add(curveObject);

//// curve -end

// set camera position
camera.position.set(0, 1, 5);
camera.lookAt(new THREE.Vector3(0,0,0));
camera.position.set(7, 7, 5);
camera.lookAt(new THREE.Vector3(0,0,5));

// scene.add(lambertCube);
scene.add(directionalLight);
Expand All @@ -59,14 +79,95 @@ function onLoad(framework) {
});
}

///// tweening

function lerp( v0, v1, t ){
return (1 - t) * v0 + t * v1;
}

function powerlerp( v0, v1, t, exp ){
t = Math.pow( t, exp );
return (1 - t) * v0 + t * v1;
}

function triangle( t ){
if( t < 0.5 )
return t * 2;
return ( 1 - t ) * 2;
}

function smootherstep( x ){
return 6 * Math.pow(x, 5) - 15 * Math.pow(x, 4) + 10 * Math.pow(x, 3);
}

/////

// called on frame updates
function onUpdate(framework) {
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 stauff = framework.stauff; //**NOTE** this is ref assignment, not a copy
var date = new Date();

//Determine the curve for this frame
//Interpolate control points for up and down positions of wing
var period = 3000; //milliseconds for full up/down cycle
var phase = triangle( ( date.getTime() % period ) / period ); //getTime returns msec since 1970
phase = smootherstep( phase );
var pointsInterp = []; //can't simply assign stauff.curveUp to get right size, cuz it'll be a ref and not a separte object
for( var v = 0; v < stauff.controlPointsUp.length; v++ ){
pointsInterp.push( new THREE.Vector3() )
for (var i = 0; i < 3; i++)
pointsInterp[v].setComponent(i, lerp( stauff.controlPointsUp[v].getComponent(i), stauff.controlPointsDown[v].getComponent(i), phase ) );
//console.log('pI: ', pointsInterp[v]);
}
var curveInterp = new THREE.CatmullRomCurve3( pointsInterp );

//Draw the feathers
for( var f = 0; f < stauff.numFeathers; f ++ ){
var feather = framework.scene.getObjectById(stauff.featherIds[f]);

if (feather !== undefined) {
// Simply flap wing
//feather.rotateY( 1 * Math.PI / 180 ); //*increments* rotation

//Get the feather's position along the spine/curve
var curveStep = Math.pow(f / (stauff.numFeathers - 1), 1.1);
var p = curveInterp.getPointAt( curveStep );
feather.position.set( p.x, p.y, p.z );

//first align along x
var axis = new THREE.Vector3(0,1,0);
var angleDeg = 0;
feather.setRotationFromAxisAngle( axis, angleDeg * Math.PI / 180 ); //sets fixed rotation

//Find the home orientation of feather so that it's always
// aligned with surface of the wing
//Assuming that the wing's neutral/flat position is in xz-plane, then normal
// along spine of wing is along +y
//
//get the tangent along the curve at this feather's attachment point
var tangent = curveInterp.getTangentAt( curveStep ); //unit length
//cross with the tangent in neutral position (0,1,0) to get angle and axis of its rotation into new curve
// orientation. Empirically, the tangent along a straight-line curve along +z axis is positive
var tangent0 = new THREE.Vector3(0,0,1); //unit length
var cross = new THREE.Vector3();
cross.crossVectors( tangent0, tangent ); //is this t0 x t, or t x t0?
var angle = Math.asin( cross.length() );
//rotate feather into plane of wing surface
feather.rotateOnAxis( cross.normalize(), angle );

//rotate furthest feathers outwards
//
//rotate the neutral position normal around the cross product vector to
// get the new normal orientation
var norm = new THREE.Vector3(0,1,0);
norm.applyAxisAngle( norm, angle );
var maxAngleRad = -90 * Math.PI / 180;
//rotate the feather around the normal
var rotAngle = powerlerp( 0, maxAngleRad, curveStep, 3.5 );
feather.rotateOnAxis( norm.normalize(), rotAngle );

}
}
}

// when the scene is done initializing, it will call onLoad, then on frame updates, call onUpdate
Expand Down