Skip to content

Instantly share code, notes, and snippets.

@lykkin
Created September 22, 2015 17:14
Show Gist options
  • Save lykkin/9e26ba88f627822e8025 to your computer and use it in GitHub Desktop.
Save lykkin/9e26ba88f627822e8025 to your computer and use it in GitHub Desktop.
wiggling boxes
var WIDTH = window.innerWidth - 20,
HEIGHT = window.innerHeight - 20;
var VIEW_ANGLE = 45,
ASPECT = WIDTH/HEIGHT,
NEAR = 0.1,
FAR = 10000;
var camera =
new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR);
camera.position.z = 0;
camera.position.x = -200;
camera.position.y = 150;
camera.up = new THREE.Vector3(0,0,1);
var projector = new THREE.Projector();
var renderer = new THREE.SVGRenderer();
renderer.setSize(WIDTH, HEIGHT);
var objects = [];
var scene = new THREE.Scene();
var logoGen = function(){
var res = {
newVerts: [],
oldVerts: [],
curVerts: [],
/*
5____4
1/___0/|
| 6__|_7
2/___3/
*/
adjacentVerts : [ //0 if not connected, the axis of connection if they are
[ 0 , 'x', 0 , 'y', 'z', 0 , 0 , 0 ],
[ 'x', 0 , 'y', 0 , 0 , 'z', 0 , 0 ],
[ 0 , 'y', 0 , 'x', 0 , 0 , 'z', 0 ],
[ 'y', 0 , 'x', 0 , 0 , 0 , 0 , 'z' ],
[ 'z', 0 , 0 , 0 , 0 , 'x', 0 , 'y' ],
[ 0 , 'z', 0 , 0 , 'x', 0 , 'y', 0 ],
[ 0 , 0 , 'z', 0 , 0 , 'y', 0 , 'x' ],
[ 0 , 0 , 0 , 'z' , 'y', 0 , 'x', 0 ],
],
lengthRules: {
counter: 0,
isValid: false,
rules: 0,
getRules: function(){
this.counter += 1;
this.isValid = this.counter % 3 === 0;
this.rules = this.isValid ? this.valid : this.invalid;
return this.rules;
},
invalid: [
{
first:0, second:4,
minLen:0, dLen:10,
locked: false
},
{
first:1, second:5,
minLen:0, dLen:10,
locked: false
},
{
first:2, second:6,
minLen:0, dLen:10,
locked: false
},
{
first:3, second:7,
minLen:0, dLen:10,
locked: false
},
{
first:1, second:0,
minLen:0, dLen:10,
locked: false
},
{
first:2, second:1,
minLen:0, dLen:10,
locked: false
},
{
first:2, second:3,
minLen:0, dLen:10,
locked: false
},
{
first: 3, second: 0,
minLen: 0, dLen: 10,
locked: false
},
{
first:5, second:4,
minLen:0, dLen:10,
locked: false
},
{
first:6, second:5,
minLen:0, dLen:10,
locked: false
},
{
first:7, second:6,
minLen:0, dLen:10,
locked: false
},
{
first:7, second:4,
minLen:0, dLen:10,
locked: false
},
],
valid: [
// {
// first: int, second: int - vertices of the line, order
// matters
//
// minLen: int, dLen: int - minimum and delta line length
//
// locked: bool - line length is perserved across vertex
// movement
//
// inequality: [int] - indices to sides this side can't be
// the same as -- soon to come
// }
{
first:0, second:4,
minLen:3, dLen:0,
locked: true
},
{
first:1, second:5,
minLen:4, dLen:3,
locked: true
},
{
first:2, second:6,
minLen:8, dLen:0,
locked: true
},
{
first:3, second:7,
minLen:4, dLen:3,
locked: true
},
{
first:1, second:0,
minLen:7, dLen:0,
locked: false
},
{
first:2, second:1,
minLen:2, dLen:10,
locked: true
},
{
first:2, second:3,
minLen:7, dLen:0,
locked: false
},
{
first: 3, second: 0,
minLen: 2, dLen: 10,
locked: true
},
{
first:5, second:4,
minLen:7, dLen:0,
locked: false
},
{
first:6, second:5,
minLen:7, dLen:0,
locked: false
},
{
first:7, second:6,
minLen:7, dLen:0,
locked: false
},
{
first:7, second:4,
minLen:7, dLen:0,
locked: false
},
],
},
templateVerts: 0,
unit: 10,
animationTime: 2000,
cube: 0,
counter: 0,
scene: scene,
generateCoord: function(i){
return {
val: this.templateVerts[i],
neighbor: false,
locked: false,
visited: false,
};
},
generateVert: function(i){
return {
x: this.generateCoord(i),
y: this.generateCoord(i),
z: this.generateCoord(i),
move: function(dels){
this.x.visited = true;
if(this.x.locked && !this.x.neighbor.x.visited){
this.x.neighbor.move(dels);
}
this.x.val += dels.x;
this.y.visited = true;
if(this.y.locked && !this.y.neighbor.y.visited){
this.y.neighbor.move(dels);
}
this.y.val += dels.y;
this.z.visited = true;
if(this.z.locked && !this.z.neighbor.z.visited){
this.z.neighbor.move(dels);
}
this.z.val += dels.z;
}
};
},
generateKeyFrame: function(){
if (this.oldVerts.length === 0){
this.primeVerts();
}
this.newVerts = [];
for(var i = 0; i < 43; i += 6){
this.newVerts.push(this.generateVert(i));
}
for(var i = 0; i < 8; i++){
for(var j = i; j < 8; j++){
if(this.adjacentVerts[i][j] !== 0){
this.newVerts[i][this.adjacentVerts[i][j]].neighbor = this.newVerts[j];
this.newVerts[j][this.adjacentVerts[i][j]].neighbor = this.newVerts[i];
}
}
}
this.vetKeyFrame();
this.centerFrame();
this.start = new Date();
},
centerFrame: function(){
for(var i = 0; i < 8; i++){
var v = this.newVerts[i];
var dist = 0;
if(!v.x.visited){
dist = Math.abs(v.x.val - v.x.neighbor.x.val)/2;
if(v.x.val < v.x.neighbor.x.val){
v.x.val = -dist;
v.x.neighbor.x.val = dist;
} else {
v.x.val = dist;
v.x.neighbor.x.val = -dist;
}
v.x.visited = true;
v.x.neighbor.x.visited = true;
}
if(!v.y.visited){
dist = Math.abs(v.y.val - v.y.neighbor.y.val)/2;
if(v.y.val < v.y.neighbor.y.val){
v.y.val = -dist;
v.y.neighbor.y.val = dist;
} else {
v.y.val = dist;
v.y.neighbor.y.val = -dist;
}
v.y.visited = true;
v.y.neighbor.y.visited = true;
}
if(!v.z.visited){
dist = Math.abs(v.z.val - v.z.neighbor.z.val)/2;
if(v.z.val < v.z.neighbor.z.val){
v.z.val = -dist;
v.z.neighbor.z.val = dist;
} else {
v.z.val = dist;
v.z.neighbor.z.val = -dist;
}
v.z.visited = true;
v.z.neighbor.z.visited = true;
}
}
},
generatePoint: function(x,y,z){
return {
x: x,
y: y,
z: z
};
},
getDist: function(a, b){
return Math.sqrt((a.x.val-b.x.val)*(a.x.val-b.x.val) + (a.y.val-b.y.val)*(a.y.val-b.y.val) + (a.z.val-b.z.val)*(a.z.val-b.z.val));
},
resizeSide: function(to, from, lenRule){
switch(this.adjacentVerts[lenRule.first][lenRule.second]){
case 0:
console.error('attempted to lock vertices that are not adjacent\nPlease remove the rule from: ' + Number(a.first).toString() + ' to ' + Number(a.second).toString());
break;
case 'x':
to.move(this.generatePoint(from.x.val - to.x.val + (lenRule.minLen + Math.floor(lenRule.dLen*Math.random()))*this.unit, from.y.val - to.y.val, from.z.val - to.z.val));
to.x.locked = lenRule.locked;
from.x.locked = lenRule.locked;
break;
case 'y':
to.move(this.generatePoint(from.x.val - to.x.val, from.y.val - to.y.val + (lenRule.minLen + Math.floor(lenRule.dLen*Math.random()))*this.unit, from.z.val - to.z.val));
to.y.locked = lenRule.locked;
from.y.locked = lenRule.locked;
break;
case 'z':
to.move(this.generatePoint(from.x.val - to.x.val, from.y.val - to.y.val, from.z.val - to.z.val + (lenRule.minLen + Math.floor(lenRule.dLen*Math.random()))*this.unit));
to.z.locked = lenRule.locked;
from.z.locked = lenRule.locked;
break;
}
this.newVerts.forEach(function(vert){
vert.x.visited = false;
vert.y.visited = false;
vert.z.visited = false;
});
},
vetKeyFrame: function(){
this.lengthRules.getRules().forEach(
(function(a){
this.resizeSide(this.newVerts[a.first], this.newVerts[a.second], a);
}).bind(this)
);
},
animate: function(){
if(this.newVerts.length === 0){
this.generateKeyFrame();
}
var delta = new Date() - this.start;
if(this.counter + delta >= this.animationTime){
delta = this.animationTime - this.counter;
this.counter = 0;
} else {
this.counter += delta;
}
var ratio = delta/this.animationTime;
if(this.counter === 0){
this.primeVerts();
this.generateKeyFrame();
} else {
//advance current verts
for(var k = 0; k < 8; k++){
this.curVerts[k].x = this.curVerts[k].x + (this.newVerts[k].x.val - this.oldVerts[k].x)*ratio;
this.curVerts[k].y = this.curVerts[k].y + (this.newVerts[k].y.val - this.oldVerts[k].y)*ratio;
this.curVerts[k].z = this.curVerts[k].z + (this.newVerts[k].z.val - this.oldVerts[k].z)*ratio;
}
this.start = new Date();
}
this.step();
},
step: function(){
/*
there has to be a better way!
taken from BoxHelper in the threejs source
x,y,z pairs for start-end of the lines along the boxes
5____4
1/___0/|
| 6__|_7
2/___3/
*/
var pos = this.cube.geometry.attributes.position;
var posArray = pos.array;
//0 to 1
posArray[0] = this.curVerts[0].x; posArray[1] = this.curVerts[0].y; posArray[2] = this.curVerts[0].z;
posArray[3] = this.curVerts[1].x; posArray[4] = this.curVerts[1].y; posArray[5] = this.curVerts[1].z;
//1 to 2
posArray[6] = this.curVerts[1].x; posArray[7] = this.curVerts[1].y; posArray[8] = this.curVerts[1].z;
posArray[9] = this.curVerts[2].x; posArray[10] = this.curVerts[2].y; posArray[11] = this.curVerts[2].z;
//2 to 3
posArray[12] = this.curVerts[2].x; posArray[13] = this.curVerts[2].y; posArray[14] = this.curVerts[2].z;
posArray[15] = this.curVerts[3].x; posArray[16] = this.curVerts[3].y; posArray[17] = this.curVerts[3].z;
//3 to 0
posArray[18] = this.curVerts[3].x; posArray[19] = this.curVerts[3].y; posArray[20] = this.curVerts[3].z;
posArray[21] = this.curVerts[0].x; posArray[22] = this.curVerts[0].y; posArray[23] = this.curVerts[0].z;
//
//4 to 5
posArray[24] = this.curVerts[4].x; posArray[25] = this.curVerts[4].y; posArray[26] = this.curVerts[4].z;
posArray[27] = this.curVerts[5].x; posArray[28] = this.curVerts[5].y; posArray[29] = this.curVerts[5].z;
//5 to 6
posArray[30] = this.curVerts[5].x; posArray[31] = this.curVerts[5].y; posArray[32] = this.curVerts[5].z;
posArray[33] = this.curVerts[6].x; posArray[34] = this.curVerts[6].y; posArray[35] = this.curVerts[6].z;
//6 to 7
posArray[36] = this.curVerts[6].x; posArray[37] = this.curVerts[6].y; posArray[38] = this.curVerts[6].z;
posArray[39] = this.curVerts[7].x; posArray[40] = this.curVerts[7].y; posArray[41] = this.curVerts[7].z;
//7 to 4
posArray[42] = this.curVerts[7].x; posArray[43] = this.curVerts[7].y; posArray[44] = this.curVerts[7].z;
posArray[45] = this.curVerts[4].x; posArray[46] = this.curVerts[4].y; posArray[47] = this.curVerts[4].z;
//
//0 to 4
posArray[48] = this.curVerts[0].x; posArray[49] = this.curVerts[0].y; posArray[50] = this.curVerts[0].z;
posArray[51] = this.curVerts[4].x; posArray[52] = this.curVerts[4].y; posArray[53] = this.curVerts[4].z;
//1 to 5
posArray[54] = this.curVerts[1].x; posArray[55] = this.curVerts[1].y; posArray[56] = this.curVerts[1].z;
posArray[57] = this.curVerts[5].x; posArray[58] = this.curVerts[5].y; posArray[59] = this.curVerts[5].z;
//2 to 6
posArray[60] = this.curVerts[2].x; posArray[61] = this.curVerts[2].y; posArray[62] = this.curVerts[2].z;
posArray[63] = this.curVerts[6].x; posArray[64] = this.curVerts[6].y; posArray[65] = this.curVerts[6].z;
//3 to 7
posArray[66] = this.curVerts[3].x; posArray[67] = this.curVerts[3].y; posArray[68] = this.curVerts[3].z;
posArray[69] = this.curVerts[7].x; posArray[70] = this.curVerts[7].y; posArray[71] = this.curVerts[7].z;
},
generateCube: function(){
var x = this.unit*20;
var y = this.unit*20;
var z = this.unit*20;
this.cube = new THREE.BoxHelper(new THREE.Mesh(new THREE.BoxGeometry(x,y,z), new THREE.MeshNormalMaterial()));
this.templateVerts = new THREE.BoxHelper(new THREE.Mesh(new THREE.BoxGeometry(x, y, z), new THREE.MeshNormalMaterial())).geometry.attributes.position.array;
this.cube.material.linewidth = 10;
this.cube.material.color.set(0x00000000);
this.scene.add(this.cube);
},
primeVerts: function(){
if(this.templateVerts === 0){
this.generateCube();
}
if(this.newVerts.length === 0){
for(var i = 0; i < 43; i += 6){
this.oldVerts.push({
x: this.templateVerts[i],
y: this.templateVerts[i+1],
z: this.templateVerts[i+2]
});
this.curVerts.push({
x: this.templateVerts[i],
y: this.templateVerts[i+1],
z: this.templateVerts[i+2]
});
}
} else {
//poor man's deep copy
this.curVerts = [];
for(var i = 0; i < 8; i++){
this.curVerts.push({
x: this.newVerts[i].x.val,
y: this.newVerts[i].y.val,
z: this.newVerts[i].z.val
});
}
this.oldVerts = [];
for(var i = 0; i < 8; i++){
this.oldVerts.push({
x: this.newVerts[i].x.val,
y: this.newVerts[i].y.val,
z: this.newVerts[i].z.val
});
}
}
}
};
return res;
};
$(document).ready(function(){
logogen = logoGen();
var render = function(){
renderer.render(scene, camera);
logogen.animate();
requestAnimationFrame(render);
};
render();
controls = new THREE.OrbitControls( camera );
$('body').append(renderer.domElement);
});
//this is awful, get a backend for this shit
//kinda only works for chrome, firefox would need another
//blobbuilder
var snap = function () {
var XMLS, svgfile;
XMLS = new XMLSerializer();
blob = new window.Blob([XMLS.serializeToString(renderer.domElement)]);
saveAs(blob, 'test.svg');
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment