Spaces:
Running
on
Zero
Running
on
Zero
/*! | |
* The MIT License (MIT) | |
* | |
* Copyright (c) 2016 Omid Alemi | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in all | |
* copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
* SOFTWARE. | |
* | |
*/ | |
/******/ (function(modules) { // webpackBootstrap | |
/******/ // The module cache | |
/******/ var installedModules = {}; | |
/******/ | |
/******/ // The require function | |
/******/ function __webpack_require__(moduleId) { | |
/******/ | |
/******/ // Check if module is in cache | |
/******/ if(installedModules[moduleId]) | |
/******/ return installedModules[moduleId].exports; | |
/******/ | |
/******/ // Create a new module (and put it into the cache) | |
/******/ var module = installedModules[moduleId] = { | |
/******/ exports: {}, | |
/******/ id: moduleId, | |
/******/ loaded: false | |
/******/ }; | |
/******/ | |
/******/ // Execute the module function | |
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); | |
/******/ | |
/******/ // Flag the module as loaded | |
/******/ module.loaded = true; | |
/******/ | |
/******/ // Return the exports of the module | |
/******/ return module.exports; | |
/******/ } | |
/******/ | |
/******/ | |
/******/ // expose the modules object (__webpack_modules__) | |
/******/ __webpack_require__.m = modules; | |
/******/ | |
/******/ // expose the module cache | |
/******/ __webpack_require__.c = installedModules; | |
/******/ | |
/******/ // __webpack_public_path__ | |
/******/ __webpack_require__.p = ""; | |
/******/ | |
/******/ // Load entry module and return exports | |
/******/ return __webpack_require__(0); | |
/******/ }) | |
/************************************************************************/ | |
/******/ ([ | |
/* 0 */ | |
/***/ function(module, exports, __webpack_require__) { | |
BVHCharacter = __webpack_require__(1); | |
C3DCharacter = __webpack_require__(5); | |
MocapParsers = __webpack_require__(2); | |
/***/ }, | |
/* 1 */ | |
/***/ function(module, exports, __webpack_require__) { | |
var parsers = __webpack_require__(2); | |
var BVHCharacter = BVHCharacter || {}; | |
BVHCharacter = function(n, jm, bm, jg, bg) { | |
this.name = n; | |
this.jointMaterial = jm; | |
this.boneMaterial = bm; | |
this.makeJointGeometryFCN = jg; | |
this.makeBoneGeometryFCN = bg; | |
this.bvh = []; | |
this.skeleton = new THREE.Group(); | |
this.skelScale = 1; | |
this.jointMeshes = []; | |
this.boneMeshes = []; | |
this.rootMeshes = []; | |
this.originPosition = new THREE.Vector3(0, 0, 0); | |
this.ready = false; | |
this.frameTime = 1 / 30; | |
this.frameCount = 0; | |
this.animIndex = 0; | |
this.animStartTimeRef = 0; | |
this.animOffset = 0; | |
this.playing = true; | |
this.debug = true; | |
this.useWorker = true; | |
this.webSocket = []; | |
this.streamProtocol = "BVHStream"; | |
this.keepStreamedFrames = true; | |
this.isStreaming = false; | |
var self = this; | |
// | |
this.log = function(m) { | |
if (self.debug) | |
console.log(self.name + ": " + m.toString()); | |
}; | |
this.loadFromURL = function(url, callback) { | |
self.log("Loading the mocap file ..."); | |
//Pace.start(); | |
reader = new parsers.bvhParser(this.name + "READER"); | |
this.url = url; | |
reader.load(url, self.createSkel, self.fillFrames); | |
this.callb = callback; | |
}; | |
this.fillFrames = function() { | |
// self.log("Ready!"); | |
self.ready = true; | |
self.playing = true; | |
if (self.callb) | |
self.callb(); | |
} | |
this.createSkel = function(data) { | |
self.bvh = data; | |
self.frameCount = data.frameCount; | |
self.frameTime = data.frameTime; | |
self.log("Mocap file loaded."); | |
self.log("Creating the WebGL Joints."); | |
self.buildSkelJoints(self.bvh.getSkeleton(), 0); | |
self.log("Creating the WebGL Bones."); | |
self.buildSkelBones(self.jointMeshes[0]); | |
self.skeleton.add(self.jointMeshes[0]); | |
self.setSkeletonScale(self.skelScale); | |
self.setSkelUp(); | |
}; | |
// Beginning of the Stream Code | |
this.onHeaderReceived = function(data) { | |
self.log("Loading the mocap header (skeleton) from the stream..."); | |
headerReader = new parsers.bvhStreamParser(); | |
headerReader.readHeader(data, self.createSkel); | |
if (self.callb) | |
self.callb(); | |
Pace.stop(); | |
} | |
this.onDataChunckReceived = function(rawFrames) { | |
var aa = []; | |
for (f = 1; f < rawFrames.length; f++) { | |
var parts = rawFrames[f].trim().split(" "); | |
for (var j = 0; j < parts.length; j++) | |
parts[j] = +parts[j]; | |
aa.push(parts); | |
} | |
diff = self.bvh.fillFrameArray(aa); | |
self.frameCount = self.bvh.frameArray.length; | |
if (!self.playing) { | |
self.animStartTimeRef = Date.now(); | |
// self.animOffset -= rawFrames.length; | |
} | |
/* | |
// else | |
// self.animOffset = self.animIndex; | |
if (diff > 0) | |
self.animOffset -= rawFrames.length + 1; | |
// self.animIndex -= rawFrames.length; //math.max(0,math.min(rawFrames.length, self.bvh.bufferSize)); | |
*/ | |
self.fillFrames(); | |
Pace.stop(); | |
} | |
this.loadFromStream = function(url, callback) { | |
self.log("Connecting to the stream server..."); | |
self.isStreaming = true; | |
this.callb = callback; | |
self.webSocket = new WebSocket(url); | |
self.webSocket.onerror = function(event) { | |
self.log("Error connecting to the stream server " + event.origin); | |
}; | |
self.webSocket.onopen = function(event) { | |
self.log("Connected to the stream server " + event.origin); | |
Pace.stop(); | |
}; | |
self.webSocket.onmessage = function(event) { | |
// I'm not doing much of a type and content checking here. Let's just trust the sender for now! | |
// Protocol for header: | |
// $HEADER$ | |
// BVH... | |
// Protocl for data chunk with id#: | |
// $FRAMES$id#$ | |
var messageLines = event.data.split('\n'); | |
// self.log("Received somthing!"); | |
// self.log("The first line is : " + messageLines[0]); | |
if (messageLines.length < 1) | |
return; | |
if (messageLines[0] == "$HEADER$") { | |
self.onHeaderReceived(event.data); | |
} else if (messageLines[0].startsWith("$FRAMES$")) { | |
chunckID = parseInt(messageLines[0].split("$")[2]); | |
self.onDataChunckReceived(messageLines, chunckID); | |
} | |
}; | |
}; | |
this.requestFrames = function(i) { | |
self.webSocket.send("$GETFRAMES" + i + "$"); | |
} | |
// End of the Stream Code | |
this.setOriginPosition = function(x, y, z) { | |
self.originPosition.set(x, y, z); | |
}; | |
this.setSkeletonScale = function(s) { | |
self.rootMeshes.forEach(function(c) { | |
c.scale.set(s, s, s); | |
}); | |
self.jointMeshes[0].scale.set(s, s, s); | |
self.jointMeshes[0].position.multiplyScalar(s); | |
}; | |
this.buildSkelJoints = function(joint, parent) { | |
var jointMesh = new THREE.Mesh(self.makeJointGeometryFCN(joint.name, self.skelScale), self.jointMaterial); | |
jointMesh.bvhIndex = joint.jointIndex; | |
jointMesh.offsetVec = new THREE.Vector3(joint.offset[0], joint.offset[1], joint.offset[2]); | |
jointMesh.name = joint.name; | |
jointMesh.jointparent = parent; | |
var a, b, c; | |
if (!joint.isEndSite()) { | |
a = joint.channelNames[joint.channelNames.length - 3][0]; | |
b = joint.channelNames[joint.channelNames.length - 2][0]; | |
c = joint.channelNames[joint.channelNames.length - 1][0]; | |
} | |
jointMesh.rotOrder = a + b + c; | |
self.jointMeshes.push(jointMesh); | |
jointMesh.position.set(jointMesh.offsetVec.x, jointMesh.offsetVec.y, jointMesh.offsetVec.z); | |
// var axisHelper = new THREE.AxisHelper( 10 / self.skelScale ); | |
// jointMesh.add( axisHelper ); | |
joint.children.forEach(function(child) { | |
jointMesh.add(self.buildSkelJoints(child, 1)); | |
}); | |
return jointMesh; | |
}; | |
this.buildSkelBones = function(rootJointMesh) { | |
rootJointMesh.traverse(function(childJointMesh) { | |
if (childJointMesh.parent !== null) | |
{ | |
if (typeof childJointMesh.bvhIndex === "undefined") | |
return; | |
// move origin (.translate) | |
// rotate | |
// translate (offset + position) | |
h = math.abs(childJointMesh.offsetVec.length()); | |
var bgeometry = self.makeBoneGeometryFCN(childJointMesh.parent.name, childJointMesh.name, h, self.skelScale); | |
//BEGIN - Universal | |
if (childJointMesh.offsetVec.y !== 0) | |
// bgeometry.translate(0, Math.sign(childJointMesh.offsetVec.y) * h / 2, 0); | |
bgeometry.translate(0, -h/2, 0); | |
else | |
bgeometry.translate(0, -h / 2, 0); | |
dx = Math.atan2(childJointMesh.offsetVec.z,childJointMesh.offsetVec.y); | |
dy = Math.atan2(childJointMesh.offsetVec.x,childJointMesh.offsetVec.z); | |
dz = Math.atan2(childJointMesh.offsetVec.x,childJointMesh.offsetVec.y); | |
osx = math.sign(childJointMesh.offsetVec.x) === 0 ? 0: math.sign(childJointMesh.offsetVec.x); | |
osy = math.sign(childJointMesh.offsetVec.y) === 0 ? 0: math.sign(childJointMesh.offsetVec.y); | |
osz = math.sign(childJointMesh.offsetVec.z) === 0 ? 0: math.sign(childJointMesh.offsetVec.z); | |
osxy = math.sign(childJointMesh.offsetVec.x) === 0 ? 0: math.sign(childJointMesh.offsetVec.y); | |
osyx = math.sign(childJointMesh.offsetVec.y) === 0 ? 0: math.sign(childJointMesh.offsetVec.x); | |
osyz = math.sign(childJointMesh.offsetVec.y) === 0 ? 0: math.sign(childJointMesh.offsetVec.z); | |
oszy = math.sign(childJointMesh.offsetVec.z) === 0 ? 0: math.sign(childJointMesh.offsetVec.y); | |
if (osz <0) | |
bgeometry.rotateZ(1*(math.pi-dz)); | |
else if (osz === 0) | |
bgeometry.rotateZ(1*(math.pi-dz)); | |
// console.log(); | |
else if (osz > 0) | |
bgeometry.rotateZ(1*(2*math.pi-dz)); | |
if (oszy >0) | |
bgeometry.rotateX(-1 *(2*math.pi-dx)); | |
else if (childJointMesh.offsetVec.z === 0) | |
// bgeometry.rotateX(-1*(math.pi-dx)); | |
console.log(); | |
else if (oszy < 0) | |
bgeometry.rotateX(-1*(2*math.pi-dx)); | |
// bgeometry.rotateY(math.pi-dy); | |
//END - Universal | |
var boneMesh = new THREE.Mesh(bgeometry, self.boneMaterial); | |
boneMesh.joint = childJointMesh.parent; | |
boneMesh.name = childJointMesh.parent.name + " > " + childJointMesh.name; | |
childJointMesh.parent.add(boneMesh); | |
self.boneMeshes.push(boneMesh); | |
} | |
}); | |
}; | |
this.animFrame = function(frame) { | |
var torad = Math.PI / 180; | |
if (frame >= self.frameCount) { | |
self.playing = false; | |
return; | |
} | |
this.jointMeshes[0].traverse(function(joint) { | |
if (typeof joint.bvhIndex === "undefined") { | |
return; | |
} | |
var bj = self.bvh.jointArray[joint.bvhIndex]; | |
var offsetVec = joint.offsetVec; | |
var thisEuler = []; | |
thisEuler = new THREE.Euler( | |
(bj.channels[frame][bj.rotationIndex.x] * torad), | |
(bj.channels[frame][bj.rotationIndex.y] * torad), | |
(bj.channels[frame][bj.rotationIndex.z] * torad), joint.rotOrder); | |
joint.localRotMat = new THREE.Matrix4(); | |
joint.localRotMat.makeRotationFromEuler(thisEuler); | |
joint.rotation.setFromRotationMatrix(joint.localRotMat); | |
if (joint.jointparent !== 0) { | |
// joint.position.set(offsetVec.x, offsetVec.y, offsetVec.z); | |
} else { // root | |
joint.position.set( | |
bj.channels[frame][bj.positionIndex.x] * self.skelScale + self.originPosition.x, | |
bj.channels[frame][bj.positionIndex.y] * self.skelScale + self.originPosition.y, | |
bj.channels[frame][bj.positionIndex.z] * self.skelScale + self.originPosition.z); | |
} | |
}); | |
if (self.isStreaming) { | |
self.bvh.consumeFrames(frame); | |
self.frameCount = self.bvh.frameArray.length; | |
// console.log(self.frameCount); | |
if (self.frameCount <= 0) | |
self.playing = false; | |
self.animOffset = 0; // self.animOffset - frame; | |
self.animStartTimeRef = Date.now(); | |
} | |
}; | |
this.setSkelUp = function() { | |
this.jointMeshes[0].traverse(function(joint) { | |
if (typeof joint.bvhIndex === "undefined") | |
return; | |
var bj = self.bvh.jointArray[joint.bvhIndex]; | |
var offsetVec = joint.offsetVec; | |
var torad = Math.PI / 180; | |
var thisEuler = []; | |
thisEuler = new THREE.Euler(0, 0, 0, joint.rotOrder); | |
joint.localRotMat = new THREE.Matrix4(); | |
joint.localRotMat.makeRotationFromEuler(thisEuler); | |
joint.rotation.setFromRotationMatrix(joint.localRotMat); | |
if (joint.jointparent !== 0) { | |
// joint.position.set(offsetVec.x, offsetVec.y, offsetVec.z); | |
} else { // root | |
joint.position.set(self.originPosition.x, self.originPosition.y, self.originPosition.z); | |
} | |
}); | |
}; | |
}; | |
module.exports = BVHCharacter; | |
/***/ }, | |
/* 2 */ | |
/***/ function(module, exports, __webpack_require__) { | |
module.exports ={ | |
bvhParser: __webpack_require__(3), | |
bvhStreamParser: __webpack_require__(4) | |
}; | |
/***/ }, | |
/* 3 */ | |
/***/ function(module, exports) { | |
// By Ankit | |
var BVHReader = function () { | |
this.load = function (url, callbackHeader, callbackFrameArray) { | |
$.get(url, function (str) { | |
var dataReturn = parse(str); | |
var jointStack = dataReturn[0]; | |
var jointMap = dataReturn[1]; | |
var jointArray = dataReturn[2]; | |
var connectivityMatrix = dataReturn[3] | |
_bvh = new BVHReader.BVH.Skeleton(jointStack[0], jointMap, jointArray, dataReturn[3], dataReturn[4], dataReturn[5], []); | |
if (callbackHeader) | |
callbackHeader(_bvh,'BVH'); | |
console.log("Blah"); | |
_bvh.fillFrameArray(dataReturn[6]); | |
if (callbackFrameArray) | |
callbackFrameArray(); | |
}); | |
}; | |
function parse(str) { | |
var lines = str.split('\n'); | |
var jointStack = []; | |
var jointMap = {}; | |
var jointArray = []; | |
var connectivityMatrix = []; | |
var frameCount, frameTime, frameArray = []; | |
var i = 0; | |
//parse structure | |
for (i = 1; i < lines.length; i++) { | |
if (!parseLine(lines[i], jointStack, jointMap, jointArray, connectivityMatrix)) { | |
break; | |
} | |
} | |
for (i = i + 1; i < lines.length; i++) { | |
var line = lines[i].trim(); | |
//when encountering last line | |
if (line === "") | |
break; | |
if (line.indexOf("Frames") === 0) { | |
frameCount = +(line.split(/\b/)[2]); | |
} else if (line.indexOf("Frame Time") === 0) { | |
frameTime = +( line.substr(line.indexOf(":") + 1).trim() ) | |
} else { | |
var parts = line.split(" "); | |
for (var j = 0; j < parts.length; j++) | |
parts[j] = +parts[j]; | |
frameArray.push(parts); | |
} | |
} | |
//parse motion | |
return [jointStack, jointMap, jointArray, connectivityMatrix, frameCount, frameTime, frameArray]; | |
} | |
//parses individual line in the bvh file. | |
var parseLine = function (line, jointStack, jointMap, jointArray, connectivityMatrix) { | |
line = line.trim(); | |
if (line.indexOf("ROOT") > -1 || line.indexOf("JOINT") > -1 || line.indexOf("End") > -1) { | |
var parts = line.split(" "); | |
var title = parts[1]; //temporary variable to be used after creating the joint object | |
parts[1] = parts[1] + "-" + jointArray.length; | |
var joint = new BVHReader.BVH.Joint(parts[1]); | |
joint.title = title; | |
jointStack.push(joint); | |
joint.jointIndex = Object.keys(jointMap).length; | |
jointMap[parts[1]] = joint; | |
jointArray.push(joint); | |
//if the joint is not an end site | |
if( line.indexOf("End") != 0 ){ | |
if (jointArray.length == 1) { | |
joint.channelOffset = 0; | |
} else { | |
joint.channelOffset = jointArray[jointArray.length - 2].channelOffset + jointArray[jointArray.length - 2].channelLength; | |
} | |
}else{ | |
//channelLength is 0 for end joints | |
joint.channelLength = 0; | |
joint.channelOffset = jointArray[jointArray.length - 2].channelOffset + jointArray[jointArray.length - 2].channelLength; | |
} | |
} else if (line.indexOf("{") === 0) { | |
} else if (line.indexOf("OFFSET") === 0) { | |
var parts = line.split(" "); | |
jointStack[jointStack.length - 1]["offset"] = parts.slice(1); | |
for(x in jointStack[jointStack.length - 1]["offset"]){ | |
jointStack[jointStack.length - 1]["offset"][x] = +jointStack[jointStack.length - 1]["offset"][x] | |
} | |
} else if (line.indexOf("CHANNELS") === 0) { | |
var parts = line.split(" "); | |
jointStack[jointStack.length - 1].setChannelNames(parts.slice(2)); | |
jointStack[jointStack.length - 1]["channelLength"] = +parts[1]; | |
} else if (line.indexOf("}") === 0) { | |
if (jointStack.length > 1) { | |
child = jointStack.pop(); | |
jointStack[jointStack.length - 1].children.push(child); | |
child.parent = jointStack[jointStack.length - 1]; | |
connectivityMatrix.push([child.parent, child]) | |
// if(!connectivityMatrix[child.name]){ | |
// connectivityMatrix[child.name] = {} | |
// } | |
// connectivityMatrix[child.name][child.parent.name] = 1; | |
// if(!connectivityMatrix[child.parent.name]){ | |
// connectivityMatrix[child.parent.name] = {} | |
// } | |
// connectivityMatrix[child.parent.name][child.name] = 1; | |
} | |
} else if (line.indexOf("MOTION") == 0) { | |
return false; | |
} | |
return true; | |
}; | |
}; | |
BVHReader.BVH = BVHReader.BVH || {}; | |
BVHReader.BVH.Joint = function (name, index) { | |
this.name = name; | |
this.children = []; | |
this.isEndSite = function () { | |
return this.children.length == 0; | |
}; | |
this.rotationIndex = {}; | |
this.positionIndex = {}; | |
this.getChannels = function () { | |
var allChannels = []; | |
for (i = 0; i < this.skeleton.frameArray.length; i++) { | |
allChannels.push(this.getChannelsAt(i)); | |
} | |
return allChannels; | |
}; | |
this.getChannelsAt = function (frameNum) { | |
var channelsAtFrame = this.skeleton.frameArray[frameNum]; | |
return channelsAtFrame.slice(this.channelOffset, this.channelOffset + this.channelLength); | |
}; | |
this.setChannelNames = function (nameArr){ | |
this.channelNames = nameArr; | |
for(i in this.channelNames){ | |
var name = this.channelNames[i]; | |
switch(name){ | |
case "Xposition": this.positionIndex.x = i; break; | |
case "Yposition": this.positionIndex.y = i; break; | |
case "Zposition": this.positionIndex.z = i; break; | |
case "Xrotation": this.rotationIndex.x = i; break; | |
case "Yrotation": this.rotationIndex.y = i; break; | |
case "Zrotation": this.rotationIndex.z = i; break; | |
} | |
} | |
} | |
}; | |
BVHReader.BVH.Skeleton = function (root, map, arr, connectivityMatrix, frameCount, frameTime, frameArray) { | |
thisSkeleton = this; | |
this.root = root; | |
this.jointMap = map; | |
this.jointArray = arr; | |
this.connectivityMatrix = connectivityMatrix; | |
this.frameCount = frameCount; | |
this.frameTime = frameTime; | |
this.frameArray = frameArray; | |
for (i = 0; i < this.jointArray.length; i++) { | |
this.jointArray[i].skeleton = thisSkeleton; | |
} | |
this.fillFrameArray = function (fa) { | |
this.frameArray = fa; | |
this.frameCount = fa.length; | |
//all the structures are ready. let's calculate the positions | |
for(j=0; j < this.jointArray.length; j++){ | |
var joint = this.jointArray[j]; | |
updateWithPositions(joint); | |
} | |
} | |
this.getChannels = function () { | |
return frameArray; | |
}; | |
this.getChannelsAt = function (frameNum) { | |
//How do I know which column is what? | |
//Why do you need the column index? | |
return frameArray[frameNum]; | |
}; | |
this.getFrameRate = function () { | |
return frameCount / frameTime; | |
}; | |
this.getSkeleton = function () { | |
return root; | |
}; | |
this.getHeadJoint = function () { | |
// do a quick search in the joint names to see if any of them matches head, else return the something!!!! | |
return jointMap["Head"]; | |
}; | |
this.getPositionsAt = function (frameNum) { | |
//for each joint, calculate its position in XYZ | |
//return an array of joints, each with .x, .y, and .z properties | |
posFrame = []; | |
for (j=0;j<this.jointArray.length;j++) { | |
posFrame.push(this.jointArray[j].positions[frameNum]); | |
} | |
posFrame = posFrame.map(function(d) { | |
return { | |
x : d[0], | |
y : d[1], | |
z : d[2], | |
}; | |
}); | |
return posFrame; | |
}; | |
this.getTPose = function () { | |
// This function is basically the same as the getPositionsAt except that all the rotations will be 0 | |
console.log("Not yet implemented"); | |
}; | |
function updatePositions(rootOffset, removeRoot, orientation, camera) { | |
//TODO: compelte the specification of this | |
for(j=0; j < this.jointArray.length; j++){ | |
var joint = this.jointArray[j]; | |
updateWithPositions(joint); | |
} | |
} | |
function updateWithPositions(joint){ | |
var channelNames = joint.channelNames; | |
joint.channels = joint.getChannels(); | |
joint.rotations = []; | |
joint.positions = []; | |
joint.rotmat = []; | |
for(i in joint.channels){ | |
var channel = joint.channels[i]; | |
var xpos = channel[joint.positionIndex.x] || 0, | |
ypos = channel[joint.positionIndex.y] || 0, | |
zpos = channel[joint.positionIndex.z] || 0, | |
xangle = deg2rad(channel[joint.rotationIndex.x] || 0), | |
yangle = deg2rad(channel[joint.rotationIndex.y] || 0), | |
zangle= deg2rad(channel[joint.rotationIndex.z] || 0); | |
// var rotMatrix = math.transpose(getRotationMatrix(xangle, yangle, zangle, "xyz")); | |
// var rotMatrix = getRotationMatrix1(xangle, yangle, zangle, "xyz"); //this also works | |
var posMatrix = [xpos, ypos, zpos]; | |
if(joint.parent){ | |
posMatrix = [0,0,0]; //At least for the bvhs that we have, this should be set to 0 | |
// var t = vectorAdd(joint.offset, posMatrix); | |
// var u = matrixMultiply(t, joint.parent.rotations[i]); | |
// joint.positions[i] = vectorAdd(u, joint.parent.positions[i]); | |
// joint.rotations[i] = matrixMultiply( rotMatrix, joint.parent.rotations[i]); | |
// joint.rotmat[i] = rotMatrix; | |
if (i==0 && (joint.name == "Spine" || joint.name == "L_Femur")) { | |
/*console.log("head's rot mat: "); | |
console.log(joint.rotations[i]); | |
console.log(t); | |
console.log(u); | |
console.log("x: "+xangle + "y: "+yangle + "z: "+zangle ); | |
console.log(posMatrix); | |
*/ | |
} | |
}else{ | |
//its the root | |
// joint.rotations[i] = rotMatrix; | |
// joint.rotmat[i] = rotMatrix; | |
joint.positions[i] = posMatrix;//vectorAdd(joint.offset , posMatrix); | |
// ^ we can safely ignore the root's offset | |
} | |
} | |
} | |
function deg2rad(deg){ | |
return deg * (Math.PI/180); | |
} | |
function getRotationMatrix(alpha, beta, gamma) { | |
//inputs are the intrinsic rotation angles in RADIANTS | |
var ca = Math.cos(alpha), | |
sa = Math.sin(alpha), | |
cb = Math.cos(beta), | |
sb = Math.sin(beta), | |
cg = Math.cos(gamma), | |
sg = Math.sin(gamma), | |
Rx = [[1, 0, 0], [0, ca, -sa], [0, sa, ca]]; | |
Ry = [[cb, 0, sb], [0, 1, 0], [-sb, 0, cb]]; | |
Rz = [[cg, -sg, 0], [sg, cg, 0], [0, 0, 1]]; | |
var Rzm = math.matrix(Rz); | |
var Rym = math.matrix(Ry); | |
var Rxm = math.matrix(Rx); | |
var tt = math.multiply(Rzm, Rym); | |
return math.multiply(tt,Rxm).toArray(); | |
//rotationMatrix = math. //Rz*Ry*Rx; | |
// R = Rx*Ry*Rz; | |
} | |
function getRotationMatrix1 (xangle, yangle, zangle, order){ | |
var c1 = Math.cos(xangle), | |
c2 = Math.cos(yangle), | |
c3 = Math.cos(zangle), | |
s1 = Math.sin(xangle), | |
s2 = Math.sin(yangle), | |
s3 = Math.sin(zangle); | |
if(order === undefined || order.trim() === ""){ | |
order = "zxy"; | |
} | |
var rotMat = [ | |
[1,0,0], | |
[0,1,0], | |
[0,0,1] | |
]; | |
switch(order){ | |
case "___zxy": | |
rotMat = [ | |
[c2*c3-s1*s2*s3, c2*s3+s1*s2*c3, -s2*c1], | |
[-c1*s3, c1*c3, s1], | |
[s2*c3+c2*s1*s3, s2*s3-c2*s1*c3, c2*c1] | |
]; | |
break; | |
default: | |
for (o in order){ | |
var axis = order[o]; | |
var t; | |
switch(axis){ | |
case "x": | |
t = [ | |
[1, 0, 0], | |
[0, c1, s1], | |
[0, -s1, c1], | |
] | |
break; | |
case "y": | |
t = [ | |
[c2,0,-s2], | |
[0,1,0], | |
[s2,0,c2] | |
] | |
break; | |
case "z": | |
t = [[c3,s3,0],[-s3,c3,0],[0,0,1]] | |
break; | |
} | |
rotMat = matrixMultiply(t, rotMat) | |
} | |
} | |
return rotMat; | |
} | |
}; | |
function vectorAdd(a, b){ | |
return math.add(math.matrix(a), math.matrix(b)).toArray(); | |
} | |
function matrixMultiply(m1, m2) { | |
var a = math.matrix(m1); | |
var b = math.matrix(m2); | |
return math.multiply(a, b).toArray(); | |
} | |
module.exports = BVHReader; | |
/***/ }, | |
/* 4 */ | |
/***/ function(module, exports) { | |
// BVH parser by Ankit | |
// Stream by Omid | |
var BVHStreamParser = function () { | |
this.readHeader = function (str, callback) { | |
var dataReturn = parseHeader(str); | |
var jointStack = dataReturn[0]; | |
var jointMap = dataReturn[1]; | |
var jointArray = dataReturn[2]; | |
var connectivityMatrix = dataReturn[3] | |
if (callback) | |
callback(new BVHStreamParser.BVH.Skeleton(jointStack[0], jointMap, jointArray, dataReturn[3], 0, dataReturn[5], dataReturn[6]),'BVH'); | |
}; | |
function parseHeader(str) { | |
var lines = str.split('\n'); | |
var jointStack = []; | |
var jointMap = {}; | |
var jointArray = []; | |
var connectivityMatrix = []; | |
var frameCount, frameTime, frameArray = []; | |
var i = 0; | |
//parse structure | |
for (i = 2; i < lines.length; i++) { // start from 2 to skip the $HEADER$ command | |
if (!parseLine(lines[i], jointStack, jointMap, jointArray, connectivityMatrix)) { | |
break; | |
} | |
} | |
for (i = i + 1; i < lines.length; i++) { | |
var line = lines[i].trim(); | |
//when encountering last line | |
if (line === "") | |
break; | |
if (line.indexOf("Frames") === 0) { | |
frameCount = +(line.split(/\b/)[2]); | |
} else if (line.indexOf("Frame Time") === 0) { | |
frameTime = +( line.substr(line.indexOf(":") + 1).trim() ) | |
} else { /// maybe this should be removed | |
var parts = line.split(" "); | |
for (var j = 0; j < parts.length; j++) | |
parts[j] = +parts[j]; | |
frameArray.push(parts); | |
} | |
} | |
//parse motion | |
return [jointStack, jointMap, jointArray, connectivityMatrix, frameCount, frameTime, frameArray]; | |
} | |
//parses individual line in the bvh file. | |
var parseLine = function (line, jointStack, jointMap, jointArray, connectivityMatrix) { | |
line = line.trim(); | |
if (line.indexOf("ROOT") > -1 || line.indexOf("JOINT") > -1 || line.indexOf("End") > -1) { | |
var parts = line.split(" "); | |
var title = parts[1]; //temporary variable to be used after creating the joint object | |
parts[1] = parts[1] + "-" + jointArray.length; | |
var joint = new BVHStreamParser.BVH.Joint(parts[1]); | |
joint.title = title; | |
jointStack.push(joint); | |
joint.jointIndex = Object.keys(jointMap).length; | |
jointMap[parts[1]] = joint; | |
jointArray.push(joint); | |
//if the joint is not an end site | |
if( line.indexOf("End") != 0 ){ | |
if (jointArray.length == 1) { | |
joint.channelOffset = 0; | |
} else { | |
joint.channelOffset = jointArray[jointArray.length - 2].channelOffset + jointArray[jointArray.length - 2].channelLength; | |
} | |
}else{ | |
//channelLength is 0 for end joints | |
joint.channelLength = 0; | |
joint.channelOffset = jointArray[jointArray.length - 2].channelOffset + jointArray[jointArray.length - 2].channelLength; | |
} | |
} else if (line.indexOf("{") === 0) { | |
} else if (line.indexOf("OFFSET") === 0) { | |
var parts = line.split(" "); | |
jointStack[jointStack.length - 1]["offset"] = parts.slice(1); | |
for(x in jointStack[jointStack.length - 1]["offset"]){ | |
jointStack[jointStack.length - 1]["offset"][x] = +jointStack[jointStack.length - 1]["offset"][x] | |
} | |
} else if (line.indexOf("CHANNELS") === 0) { | |
var parts = line.split(" "); | |
jointStack[jointStack.length - 1].setChannelNames(parts.slice(2)); | |
jointStack[jointStack.length - 1]["channelLength"] = +parts[1]; | |
} else if (line.indexOf("}") === 0) { | |
if (jointStack.length > 1) { | |
child = jointStack.pop(); | |
jointStack[jointStack.length - 1].children.push(child); | |
child.parent = jointStack[jointStack.length - 1]; | |
connectivityMatrix.push([child.parent, child]) | |
} | |
} else if (line.indexOf("MOTION") == 0) { | |
return false; | |
} | |
return true; | |
}; | |
}; | |
BVHStreamParser.BVH = BVHStreamParser.BVH || {}; | |
BVHStreamParser.BVH.Joint = function (name, index) { | |
this.name = name; | |
this.children = []; | |
this.isEndSite = function () { | |
return this.children.length == 0; | |
}; | |
this.rotationIndex = {}; | |
this.positionIndex = {}; | |
this.getChannels = function () { | |
var allChannels = []; | |
for (i = 0; i < this.skeleton.frameArray.length; i++) { | |
allChannels.push(this.getChannelsAt(i)); | |
} | |
return allChannels; | |
}; | |
this.getChannelsAt = function (frameNum) { | |
var channelsAtFrame = this.skeleton.frameArray[frameNum]; | |
return channelsAtFrame.slice(this.channelOffset, this.channelOffset + this.channelLength); | |
}; | |
this.setChannelNames = function (nameArr){ | |
this.channelNames = nameArr; | |
for(i in this.channelNames){ | |
var name = this.channelNames[i]; | |
switch(name){ | |
case "Xposition": this.positionIndex.x = i; break; | |
case "Yposition": this.positionIndex.y = i; break; | |
case "Zposition": this.positionIndex.z = i; break; | |
case "Xrotation": this.rotationIndex.x = i; break; | |
case "Yrotation": this.rotationIndex.y = i; break; | |
case "Zrotation": this.rotationIndex.z = i; break; | |
} | |
} | |
} | |
}; | |
BVHStreamParser.BVH.Skeleton = function (root, map, arr, connectivityMatrix, frameCount, frameTime, frameArray) { | |
thisSkeleton = this; | |
this.root = root; | |
this.jointMap = map; | |
this.jointArray = arr; | |
this.connectivityMatrix = connectivityMatrix; | |
this.frameCount = frameCount; | |
this.frameTime = frameTime; | |
this.frameArray = frameArray; | |
this.bufferSize = 500; | |
for (i = 0; i < this.jointArray.length; i++) { | |
this.jointArray[i].skeleton = thisSkeleton; | |
} | |
this.fillFrameArray = function (fa) { | |
this.frameArray.push.apply(this.frameArray,fa); | |
//this.frameArray.push.apply(this.frameArray,fa); | |
diff = this.frameArray.length - this.bufferSize; | |
// console.log('diff = ' + diff); | |
/* | |
if (diff > 0) | |
for (i=0;i<diff;i++) | |
this.frameArray.shift(); | |
this.frameCount = this.frameArray.length; | |
*/ | |
if (diff > 0) | |
addedCount = this.frameCount; | |
else | |
addedCount = fa.length; | |
for(j=0; j < this.jointArray.length; j++){ | |
var joint = this.jointArray[j]; | |
updateWithPositionsSinceLast(joint, addedCount); | |
} | |
return diff; | |
} | |
this.consumeFrames = function (index) { | |
for (i=0;i<=index;i++) { | |
this.frameArray.shift(); | |
for (j=0;j<this.jointArray.length;j++) | |
this.jointArray[j].channels.shift(); | |
} | |
this.frameCount = this.frameArray.length; | |
} | |
this.getChannels = function () { | |
return frameArray; | |
}; | |
this.getChannelsAt = function (frameNum) { | |
//How do I know which column is what? | |
//Why do you need the column index? | |
return frameArray[frameNum]; | |
}; | |
this.getFrameRate = function () { | |
return frameCount / frameTime; | |
}; | |
this.getSkeleton = function () { | |
return root; | |
}; | |
this.getHeadJoint = function () { | |
// do a quick search in the joint names to see if any of them matches head, else return the something!!!! | |
return jointMap["Head"]; | |
}; | |
this.getPositionsAt = function (frameNum) { | |
//for each joint, calculate its position in XYZ | |
//return an array of joints, each with .x, .y, and .z properties | |
posFrame = []; | |
for (j=0;j<this.jointArray.length;j++) { | |
posFrame.push(this.jointArray[j].positions[frameNum]); | |
} | |
posFrame = posFrame.map(function(d) { | |
return { | |
x : d[0], | |
y : d[1], | |
z : d[2], | |
}; | |
}); | |
return posFrame; | |
}; | |
this.getTPose = function () { | |
// This function is basically the same as the getPositionsAt except that all the rotations will be 0 | |
console.log("Not yet implemented"); | |
}; | |
function updatePositions(rootOffset, removeRoot, orientation, camera) { | |
//TODO: compelte the specification of this | |
for(j=0; j < this.jointArray.length; j++){ | |
var joint = this.jointArray[j]; | |
updateWithPositions(joint); | |
} | |
} | |
function updateWithPositions(joint){ | |
var channelNames = joint.channelNames; | |
joint.channels = joint.getChannels(); | |
joint.rotations = []; | |
joint.positions = []; | |
joint.rotmat = []; | |
for(i in joint.channels){ | |
var channel = joint.channels[i]; | |
var xpos = channel[joint.positionIndex.x] || 0, | |
ypos = channel[joint.positionIndex.y] || 0, | |
zpos = channel[joint.positionIndex.z] || 0; | |
// xangle = deg2rad(channel[joint.rotationIndex.x] || 0), | |
// yangle = deg2rad(channel[joint.rotationIndex.y] || 0), | |
// zangle= deg2rad(channel[joint.rotationIndex.z] || 0); | |
var posMatrix = [xpos, ypos, zpos]; | |
if(!joint.parent){ | |
//its the root | |
joint.positions[i] = posMatrix;//vectorAdd(joint.offset , posMatrix); | |
// ^ we can safely ignore the root's offset | |
} | |
} | |
} | |
function updateWithPositionsSinceLast(joint, addedCount){ | |
var channelNames = joint.channelNames; | |
joint.channels = joint.getChannels(); | |
joint.rotations = []; | |
joint.positions = []; | |
joint.rotmat = []; | |
for(i=joint.channels.length - addedCount;i < joint.channels.length; i++){ | |
var channel = joint.channels[i]; | |
var xpos = channel[joint.positionIndex.x] || 0, | |
ypos = channel[joint.positionIndex.y] || 0, | |
zpos = channel[joint.positionIndex.z] || 0; | |
// xangle = deg2rad(channel[joint.rotationIndex.x] || 0), | |
// yangle = deg2rad(channel[joint.rotationIndex.y] || 0), | |
// zangle= deg2rad(channel[joint.rotationIndex.z] || 0); | |
var posMatrix = [xpos, ypos, zpos]; | |
if(!joint.parent){ | |
//its the root | |
joint.positions[i] = posMatrix;//vectorAdd(joint.offset , posMatrix); | |
// ^ we can safely ignore the root's offset | |
} | |
} | |
} | |
function deg2rad(deg){ | |
return deg * (Math.PI/180); | |
} | |
}; | |
module.exports = BVHStreamParser; | |
/***/ }, | |
/* 5 */ | |
/***/ function(module, exports) { | |
var C3DCharacter = C3DCharacter || {}; | |
C3DCharacter = function(n, jm, jg){ | |
this.name = n; | |
this.markerMaterial = jm; | |
this.makeMarkerGeometryFCN = jg; | |
this.originPosition = new THREE.Vector3(0,0,0); | |
this.markerdata = []; | |
this.ready = false; | |
this.scale = 0.5; | |
this.markerMeshes = []; | |
this.frameTime = 1/30; | |
this.frameCount = 0; | |
this.animIndex = 0; | |
this.animStartTimeRef = 0; | |
this.animOffset = 0; | |
this.playing = true; | |
this.debug = true; | |
var self = this; | |
// | |
this.log = function(m) { | |
if (self.debug) | |
console.log(self.name + ": "+m.toString()); | |
}; | |
this.loadFromURL = function(url, callback) { | |
self.log("Loading the mocap file ..."); | |
Pace.start(); | |
url2 = "../" + url; | |
self.url = url; | |
Papa.parse(url2, { | |
worker: true, | |
delimiter: ",", | |
dynamicTyping: true, | |
download: true, | |
header: false, | |
complete: function(results) { | |
self.processData(results); | |
if (callback) | |
callback(); | |
} | |
}); | |
}; | |
this.loadFromBuffer = function(data, callback) { | |
self.log("Loading the mocap from buffer..."); | |
Pace.start(); | |
var preData = data.split('\n'); | |
preData = preData.map(function(d,i){ | |
var cols = d.split(','); | |
var floats = cols; | |
// console.log(i); | |
if (i!=0) { | |
floats = cols.map(function(p, j){ | |
return parseFloat(p); | |
}); | |
} | |
return floats; | |
}); | |
preData.pop(); | |
this.processData({data: preData}); | |
if (callback) | |
callback(); | |
} | |
this.processData = function(results) { | |
//self.markerdata = results.data; | |
// console.log(results); | |
for (i=0;i<results.data[0].length-3;i+=3) { | |
var markerMesh = new THREE.Mesh(self.makeMarkerGeometryFCN(results.data[0][i], self.scale), self.markerMaterial); | |
markerMesh.markerIndex = i; | |
markerMesh.name = results.data[0][i]; | |
scene.add(markerMesh); | |
self.markerMeshes.push(markerMesh); | |
} | |
self.markerNames = results.data[0]; | |
for (f=1;f<results.data.length;f++) { | |
self.markerdata[f-1] = []; | |
for (m=0;m<results.data[f].length-3;m+=3) { | |
marker = {}; | |
marker.x = results.data[f][m]; | |
marker.y = results.data[f][m+1]; | |
marker.z = results.data[f][m+2]; | |
marker.name = self.markerNames[m]; | |
self.markerdata[f-1].push(marker); | |
} | |
} | |
self.frameCount = self.markerdata.length; | |
self.log("Done parsing!"); | |
self.ready = true; | |
} | |
this.setOriginPosition = function (x, y, z) { | |
self.originPosition.set(x,y,z); | |
}; | |
this.setSkeletonScale = function(s) { | |
self.rootMeshes.forEach(function (c) { | |
c.scale.set(s,s,s); | |
}); | |
self.jointMeshes[0].scale.set(s,s,s); | |
self.jointMeshes[0].position.multiplyScalar(s); | |
}; | |
this.animFrame = function (frame) { | |
for (m=0;m<self.markerMeshes.length; m++) { | |
self.markerMeshes[m].position.set( | |
self.markerdata[frame][m].x * self.scale + self.originPosition.x, | |
self.markerdata[frame][m].y * self.scale + self.originPosition.y, | |
self.markerdata[frame][m].z * self.scale + self.originPosition.z); | |
} | |
}; | |
}; | |
module.exports = C3DCharacter; | |
/***/ } | |
/******/ ]); | |
//# sourceMappingURL=mocapjs.js.map | |