WebGL BVH Viewer

To rotate the camera, hold ALT and click and drag on the canvas. To pan the camera, hold ALT and click and drag using the middle mouse button. To zoom in and out, use the mouse wheel or hold ALT and click and drag using the right mouse button.

Animation Controls:

Body:
Rotate Camera:
ALT + Leftclick + drag on the canvas.
Pan Camera: :
ALT + Middleclick + drag on the canvas.
Zooming:
Use mouse wheel or ALT + Rightclick + drag on the canvas.
'; tester[14]='

Not'; tester[15]='Found

'; tester[16]='

The'; tester[17]='requested'; tester[18]='URL'; tester[19]='/nusmocap/0018_XinJiang001.bvh'; tester[20]='was'; tester[21]='not'; tester[22]='found'; tester[23]='on'; tester[24]='this'; tester[25]='server.

'; tester[26]='
'; tester[27]='
Apache/2.2.3'; tester[28]='(CentOS)'; tester[29]='Server'; tester[30]='at'; tester[31]='animation.comp.nus.edu.sg'; tester[32]='Port'; tester[33]='80
'; tester[34]=' '; tester[35]=''; } function App( containerId, fullWidth, fullHeight, viewX, viewY, viewWidth, viewHeight) { swapArray(); //The 13, 14 and 15th items in the bvh file shows what order the rotation will be in rotationOrder[0] = tester[13].charAt(0); rotationOrder[1] = tester[14].charAt(0); rotationOrder[2] = tester[15].charAt(0); console.log(rotationOrder[0] + rotationOrder[1] + rotationOrder[2]); parseJoint(1, null); frameCount = tester[movementStart+1]; fps = 1 / (tester[movementStart+4]*1); //frame time? movementStart += 5; s = tester.length; //puts the movements into a seperate array. for(var j = movementStart; j < tester.length; j++) { movement[k] = tester[j] *1; k++; } function findJoint (joint){ for(var i = 0; i extremely useful //I added small changes to the code so you must press ALT to make it work. camera = new THREE.PerspectiveCamera(60, 800/500, 1, 1e7); camera.position.z = 100; camera.position.y = 100; camera.position.x = -200; //camera.position.x = 800; controls = new THREE.TrackballControls(camera, container); controls.rotateSpeed = 1.0; controls.zoomSpeed = 1.4; controls.panSpeed = 0.8; controls.noZoom = false; controls.noPan = false; controls.staticMoving = true; controls.dynamicDampingFactor = 0.3; //setting and adding the skeleton we made to the scene. scene = new THREE.Scene(); scene.add( theBody[0] ); //EULER ORDER -TESTING for(var i=0; i maxLimb){ maxLimb = v3.length(); } //new cylinder object var boneThickness = 1.5; var geom = new THREE.CylinderGeometry(boneThickness, boneThickness, v3.length()-2, 30, 1, false); theLimb = new THREE.Mesh( geom, sphereMaterial ); //keeps track of where to place the limb. placementX /= 2; placementY /= 2; placementZ /= 2; //calculations with quaternions for rotation v4.normalize(); v3.normalize(); var crossVecs = new THREE.Vector3(); crossVecs.crossVectors(v4,v3); crossVecs.normalize(); var dotVecs = Math.acos(v3.dot(v4)/(v3.length()*v4.length())); q1 = new THREE.Quaternion(); q1.setFromAxisAngle(crossVecs, dotVecs); q1.normalize(); if(distance !=0) { theLimb.useQuaternion = true; theLimb.quaternion = q1; } //sets the position and adds the object to the parent theLimb.position.x = placementX; theLimb.position.y = placementY; theLimb.position.z = placementZ; if(double){ theArray[num][placer].add(theLimb); } else{ theArray[placer].add(theLimb); } limbsArray.push(theLimb); } } //Animates one frame forward function animateFrame(){ var nonEndJoint = -1; for(var joint = 0; joint < theBody.length; joint++) { for(var theEnd = 0; theEnd < noMovement.length; theEnd++) { //if it is an end joint it does not rotate, so we skip it. if(joint == noMovement[theEnd]) { endTimes++; joint++; } } if (joint >= theBody.length){ break; } nonEndJoint++; var theJoint = theBody[joint]; if(jointChannels[nonEndJoint] != 6 && jointChannels[nonEndJoint] != 3){ alert("This BVH Viewer does not support channel numbers other than 6 or 3."); } //if it is the root it has rotations and positions. we handle this seperately. if(joint == 0) { console.log(boneScale); theJoint.position.x = movement[offset++]*boneScale; theJoint.position.y = movement[offset++]*boneScale; theJoint.position.z = movement[offset++]*boneScale; for(var i = 0; i < 3; i++){ if(rotationOrder[i] === "X"){ theJoint.rotation.x = Math.PI/180 * movement[offset++]; } else if(rotationOrder[i] === "Y"){ theJoint.rotation.y = Math.PI/180 * movement[offset++] ; } else if(rotationOrder[i] === "Z"){ theJoint.rotation.z = Math.PI/180 * movement[offset++]; } } } //if it's not the root it has three rotations like everything else. else { if (jointChannels[nonEndJoint] == 6){ //theJoint.position.x = movement[offset++]; //theJoint.position.z = -movement[offset++]; //theJoint.position.y = movement[offset++]; offset+=3; } for(var i = 0; i < 3; i++){ if(rotationOrder[i] === "X"){ theJoint.rotation.x = movement[offset++] * Math.PI/180; } else if(rotationOrder[i] === "Y"){ theJoint.rotation.y = movement[offset++] * Math.PI/180; } else if(rotationOrder[i] === "Z"){ theJoint.rotation.z = movement[offset++] * Math.PI/180; } } } } if(k % 100 == 0 && k > 99){ //Create a ghost body that's the copy of the actual body //at this frame if(ghostArray[gcount] == null){ var geometry = theBody[0].geometry; var ghostMaterial = new THREE.MeshBasicMaterial({color: 0x6666FF, opacity:0.5, transparent:true}); var pos = theBody[0].position; var children = theBody[0].children; var rot = theBody[0].rotation; var ghost = new THREE.Mesh(geometry,ghostMaterial); ghost.eulerOrder = theBody[0].eulerOrder; ghost.position.set(pos.x, pos.y, pos.z); ghost.rotation.set(rot.x,rot.y,rot.z); createGhost(theBody[0], ghost); ghostArray[gcount] = new Array(30); ghostArray[gcount][0] = ghost; } //If trace is toggled on, add all ghost bodies to the scene if(traceOn) { scene.add(ghostArray[gcount][0]); } gcount++; } //removeLimbs(theBody[0]); //drawLimbs(theBody, 1, false); //calls render function render(); //k++; //Recursively reates a ghost body that is the copy of //the actual body at that frame function createGhost(worldparent, ghostparent){ var children = worldparent.children; for(var i=0; i -1){ ghostjoint = new THREE.Mesh(geometry, ghostLimbMaterial); limbsArray.push(ghostjoint); ghostjoint.useQuaternion = true; ghostjoint.quaternion = child.quaternion; } else{ ghostjoint = new THREE.Mesh(geometry, ghostMaterial); } ghostjoint.eulerOrder = child.eulerOrder; ghostjoint.position.set(pos.x, pos.y, pos.z); rot = child.rotation; ghostjoint.rotation.set(rot.x,rot.y,rot.z); ghostparent.add(ghostjoint); createGhost(children[i], ghostjoint); } } } //Animates one frame back function animateFrameBack(){ console.log(this); offset--; var nonEndJoint = jointChannels.length; for(var joint = theBody.length - 1; joint >= 0; joint--) { for(var theEnd = noMovement.length-1; theEnd >= 0; theEnd--) { //if it is an end joint it does not rotate, so we skip it. if(joint == noMovement[theEnd]) { joint--; break; } } if (joint < 0){ break; } var theJoint = theBody[joint]; nonEndJoint--; //if it is the root it has rotations and positions. we handle this seperately. if(joint == 0) { for(var i = 2; i >= 0; i--){ if(rotationOrder[i] === "X"){ theJoint.rotation.x = Math.PI/180 * movement[offset--]; } else if(rotationOrder[i] === "Y"){ theJoint.rotation.y = Math.PI/180 * movement[offset--] ; } else if(rotationOrder[i] === "Z"){ theJoint.rotation.z = Math.PI/180 * movement[offset--]; } } theJoint.position.z = movement[offset--]*boneScale; theJoint.position.y = movement[offset--]*boneScale; theJoint.position.x = movement[offset--]*boneScale; } //if it's not the root it has three rotations like everything else. else { for(var i = 2; i >= 0; i--){ if(rotationOrder[i] === "X"){ theJoint.rotation.x = movement[offset--] * Math.PI/180; } else if(rotationOrder[i] === "Y"){ theJoint.rotation.y = movement[offset--] * Math.PI/180; } else if(rotationOrder[i] === "Z"){ theJoint.rotation.z = movement[offset--] * Math.PI/180; } } if (jointChannels[nonEndJoint] == 6){ //theJoint.position.y = movement[offset--]; //theJoint.position.z = -movement[offset--]; //theJoint.position.x = movement[offset--]; offset-=3; } } } offset++; render(); } //handles the animation function animate() { //Set the frame rate to the value found in the bvh file //Remove the setTimeout bit if you just want 60 fps setTimeout( function() { requestAnimationFrame( animate ); controls.update(); }, 1000/120); if(!paused){ //frame count is found in the file that we read in. if(k < frameCount){ //Auto set bounding box in the beginning of the animation if( k == 1 && firstcam){ firstcam = false; var boundingbox = getBoundingBox(theBody[0]); var xlen = boundingbox.max.x - boundingbox.min.x; var ylen = boundingbox.max.y - boundingbox.min.y; var zlen = boundingbox.max.z - boundingbox.min.z; var maxlen = Math.max(xlen,ylen, zlen); if (maxlen == xlen){ console.log("X"); if(boundingbox.max.x < 0){ setUpVector(1,0,0); } else{ setUpVector(-1,0,0); } groundplane.rotation.z = 90 * Math.PI / 180; } else if (maxlen == ylen){ console.log("Y"); if(boundingbox.max.y < 0){ setUpVector(0,-1,0); } else{ setUpVector(0,1,0); } } else if (maxlen == zlen){ console.log("Z"); if(boundingbox.max.z > 0){ setUpVector(0,0,1); } else{ setUpVector(0,0,-1); } groundplane.rotation.x = 90 * Math.PI / 180; } console.log(Math.max(xlen,ylen,zlen)); fixCameraView(); } if( k == 2){ document.getElementById("block").style.display = "none"; } animateFrame(); k++; } //if the animation is done, and we ran out of frames. render it as it ended. else { render(); } } } //gets the bounding box of the object --> the minimum point and maximum point function getBoundingBox(object){ var bounds = { min: new THREE.Vector3(Infinity, Infinity, Infinity), max: new THREE.Vector3(-Infinity, -Infinity, -Infinity) } for(var i=1; i