Skip to content

Instantly share code, notes, and snippets.

@gregtatum
Last active August 29, 2015 14:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gregtatum/58c5bbad7b2a4a4660f2 to your computer and use it in GitHub Desktop.
Save gregtatum/58c5bbad7b2a4a4660f2 to your computer and use it in GitHub Desktop.
var ringFunction = function( geometry, radius, segments ) {
var rStep = 2 * Math.PI / segments;
return {
create : function( height, skinIndex, skinWeight ) {
for( var i=0; i < segments; i++ ) {
geometry.vertices.push( new THREE.Vector3(
Math.sin( i * rStep ) * radius,
height,
Math.cos( i * rStep ) * radius
) );
geometry.skinIndices.push( new THREE.Vector4( skinIndex, skinIndex+1, 0, 0 ) );
geometry.skinWeights.push( new THREE.Vector4( 1-skinWeight, skinWeight, 0, 0 ) );
// geometry.skinWeights.push( new THREE.Vector4( 1, 0, 0, 0 ) );
}
},
radius : radius,
segments : segments
};
};
var tubeFunction = function( geometry, segments, ring ) {
return function tube( height, skinIndex, prevRingVerts, baseHeight ) {
var offset, a, b, c, d, r2;
var hStep = height / segments;
var skinWeight1, skinWeight2;
var baseOffset = geometry.vertices.length;
//Create the first segment
ring.create(
baseHeight + hStep * 1, //height
skinIndex, //skinIndex
(1) / (segments) //skinWeight
);
//Connect the previous ring to the this first segment
for( var r=0; r < ring.segments; r++ ) {
offset = baseOffset;
r2 = (r + 1) % ring.segments; // wrap around the last face
a = geometry.vertices.indexOf( prevRingVerts[r] );
b = geometry.vertices.indexOf( prevRingVerts[r2] );
c = baseOffset + r;
d = baseOffset + r2;
geometry.faces.push( new THREE.Face3( a, b, c ) );
geometry.faces.push( new THREE.Face3( d, c, b ) );
}
//Create the rest of the segments
for( var h=2; h <= segments; h++ ) {
ring.create(
baseHeight + h * hStep, //height
skinIndex, //skinIndex
(h) / (segments) //skinWeight
);
for( r=0; r < ring.segments; r++ ) {
// c___d
// / /
// / / ^
// a___b / direction
offset = baseOffset + (h-2) * ring.segments;
r2 = (r + 1) % ring.segments; // wrap around the last face
a = offset + r;
b = offset + r2;
c = offset + r + ring.segments;
d = offset + r2 + ring.segments;
geometry.faces.push( new THREE.Face3( a, b, c ) );
geometry.faces.push( new THREE.Face3( d, c, a ) );
}
}
};
};
var recursiveTubes = function( tube, ring, height, geometry, depth, targetDepth, ringSlice ) {
if( depth === targetDepth ) return;
tube(
height, //tube length
depth, //skinIndex
ringSlice, //base slice vertices
height * depth //base height
);
geometry.bones.push({
"parent":depth,
"name":"segment",
"pos":[0,height,0],
"rotq":[0,0,0,1]
})
var nextRingSlice = geometry.vertices.slice(geometry.vertices.length - ring.segments, geometry.vertices.length);
for( var i=0; i < 3; i++ ) {
console.log(depth, i);
recursiveTubes( tube, ring, height, geometry, depth + 1, targetDepth, nextRingSlice );
}
}
var createInitialSegment = function( geometry ) {
var height = 50;
var radius = 10;
var rSegments = 12;
var hSegments = 3;
var depth = 3;
var ring = ringFunction( geometry, radius, rSegments );
//Create a base ring
ring.create(
0, //height
0, //skinIndex
0 //skinWeight
);
var ringSlice = geometry.vertices.slice(0, ring.segments);
var tube = tubeFunction( geometry, hSegments, ring );
geometry.bones = [
{
"parent":-1,
"name":"root",
"pos":[0,0,0],
"rotq":[0,0,0,1]
}
];
recursiveTubes( tube, ring, height, geometry, 0, depth, ringSlice );
geometry.computeFaceNormals();
};
var createMesh = function( config, geometry ) {
var mat = new THREE.MeshLambertMaterial({
skinning : true,
emissive : 0xff0000,
wireframe : true
});
mat.side = THREE.DoubleSide;
var mesh = new THREE.SkinnedMesh(
geometry,
mat,
true
);
mesh.skeletonHelper = new THREE.SkeletonHelper( mesh );
mesh.skeletonHelper.material.linewidth = 3;
mesh.add( mesh.skeletonHelper );
return mesh;
};
function recursiveRandom( bone, array, depth ) {
array[depth] = [
Math.random(),
Math.random(),
Math.random()
];
bone.scale.multiplyScalar( 0.8 );
if(bone.children[0]) {
return recursiveRandom( bone.children[0], array, depth + 1 );
} else {
return array;
}
}
function recursiveWriggle( bone, now, depth, ortho, randoms ) {
var r1 = 753.1294 * depth;
var r2 = 255.5854 * ortho;
// bone.rotation.x = Math.sin( (now + r1 + r2 ) ) * 0.5;
// bone.rotation.z = Math.sin( (now + r1 + r2 ) * 0.3 ) * 0.3;
bone.rotation.z = Math.sin( ortho + randoms[depth][0] * now * 0.05 );
bone.rotation.y = Math.sin( ortho + randoms[depth][1] * now * 0.0066 );
bone.rotation.x = Math.sin( ortho + randoms[depth][2] * now * 0.02 );
for( var i=0; i < bone.children.length; i++ ) {
recursiveWriggle( bone.children[i], now, depth + 1, ortho + i, randoms );
}
}
var update = function( mesh ) {
var randoms = recursiveRandom( mesh, [], 0 );
return function( e ) {
var bone = mesh;
mesh.skeletonHelper.update();
var now = e.now * 0.005;
recursiveWriggle( mesh.children[0], now, 0, 0, randoms );
};
};
module.exports = function treeGrowth( poem, properties ) {
var config = _.extend({
speed : 0.5,
subdivideRate : 1 / ( 60 * 3 ),
pinch : 1,
stretch : 10
}, properties );
var geometry = new THREE.Geometry();
var segments = createInitialSegment( geometry );
var mesh = createMesh( config, geometry );
// mesh.scale.multiplyScalar( 1 );
poem.scene.add( mesh );
poem.emitter.on( 'update', update( mesh ) );
return {
mesh : mesh
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment