UNPKG

three-stdlib

Version:

stand-alone library of threejs examples

1 lines 15.1 kB
{"version":3,"file":"BVHLoader.cjs","sources":["../../src/loaders/BVHLoader.js"],"sourcesContent":["import {\n AnimationClip,\n Bone,\n FileLoader,\n Loader,\n Quaternion,\n QuaternionKeyframeTrack,\n Skeleton,\n Vector3,\n VectorKeyframeTrack,\n} from 'three'\n\n/**\n * Description: reads BVH files and outputs a single Skeleton and an AnimationClip\n *\n * Currently only supports bvh files containing a single root.\n *\n */\n\nclass BVHLoader extends Loader {\n constructor(manager) {\n super(manager)\n\n this.animateBonePositions = true\n this.animateBoneRotations = true\n }\n\n load(url, onLoad, onProgress, onError) {\n const scope = this\n\n const loader = new FileLoader(scope.manager)\n loader.setPath(scope.path)\n loader.setRequestHeader(scope.requestHeader)\n loader.setWithCredentials(scope.withCredentials)\n loader.load(\n url,\n function (text) {\n try {\n onLoad(scope.parse(text))\n } catch (e) {\n if (onError) {\n onError(e)\n } else {\n console.error(e)\n }\n\n scope.manager.itemError(url)\n }\n },\n onProgress,\n onError,\n )\n }\n\n parse(text) {\n /*\n\t\t\treads a string array (lines) from a BVH file\n\t\t\tand outputs a skeleton structure including motion data\n\n\t\t\treturns thee root node:\n\t\t\t{ name: '', channels: [], children: [] }\n\t\t*/\n function readBvh(lines) {\n // read model structure\n\n if (nextLine(lines) !== 'HIERARCHY') {\n console.error('THREE.BVHLoader: HIERARCHY expected.')\n }\n\n const list = [] // collects flat array of all bones\n const root = readNode(lines, nextLine(lines), list)\n\n // read motion data\n\n if (nextLine(lines) !== 'MOTION') {\n console.error('THREE.BVHLoader: MOTION expected.')\n }\n\n // number of frames\n\n let tokens = nextLine(lines).split(/[\\s]+/)\n const numFrames = parseInt(tokens[1])\n\n if (isNaN(numFrames)) {\n console.error('THREE.BVHLoader: Failed to read number of frames.')\n }\n\n // frame time\n\n tokens = nextLine(lines).split(/[\\s]+/)\n const frameTime = parseFloat(tokens[2])\n\n if (isNaN(frameTime)) {\n console.error('THREE.BVHLoader: Failed to read frame time.')\n }\n\n // read frame data line by line\n\n for (let i = 0; i < numFrames; i++) {\n tokens = nextLine(lines).split(/[\\s]+/)\n readFrameData(tokens, i * frameTime, root)\n }\n\n return list\n }\n\n /*\n\t\t\tRecursively reads data from a single frame into the bone hierarchy.\n\t\t\tThe passed bone hierarchy has to be structured in the same order as the BVH file.\n\t\t\tkeyframe data is stored in bone.frames.\n\n\t\t\t- data: splitted string array (frame values), values are shift()ed so\n\t\t\tthis should be empty after parsing the whole hierarchy.\n\t\t\t- frameTime: playback time for this keyframe.\n\t\t\t- bone: the bone to read frame data from.\n\t\t*/\n function readFrameData(data, frameTime, bone) {\n // end sites have no motion data\n\n if (bone.type === 'ENDSITE') return\n\n // add keyframe\n\n const keyframe = {\n time: frameTime,\n position: new Vector3(),\n rotation: new Quaternion(),\n }\n\n bone.frames.push(keyframe)\n\n const quat = new Quaternion()\n\n const vx = new Vector3(1, 0, 0)\n const vy = new Vector3(0, 1, 0)\n const vz = new Vector3(0, 0, 1)\n\n // parse values for each channel in node\n\n for (let i = 0; i < bone.channels.length; i++) {\n switch (bone.channels[i]) {\n case 'Xposition':\n keyframe.position.x = parseFloat(data.shift().trim())\n break\n case 'Yposition':\n keyframe.position.y = parseFloat(data.shift().trim())\n break\n case 'Zposition':\n keyframe.position.z = parseFloat(data.shift().trim())\n break\n case 'Xrotation':\n quat.setFromAxisAngle(vx, (parseFloat(data.shift().trim()) * Math.PI) / 180)\n keyframe.rotation.multiply(quat)\n break\n case 'Yrotation':\n quat.setFromAxisAngle(vy, (parseFloat(data.shift().trim()) * Math.PI) / 180)\n keyframe.rotation.multiply(quat)\n break\n case 'Zrotation':\n quat.setFromAxisAngle(vz, (parseFloat(data.shift().trim()) * Math.PI) / 180)\n keyframe.rotation.multiply(quat)\n break\n default:\n console.warn('THREE.BVHLoader: Invalid channel type.')\n }\n }\n\n // parse child nodes\n\n for (let i = 0; i < bone.children.length; i++) {\n readFrameData(data, frameTime, bone.children[i])\n }\n }\n\n /*\n\t\t Recursively parses the HIERACHY section of the BVH file\n\n\t\t - lines: all lines of the file. lines are consumed as we go along.\n\t\t - firstline: line containing the node type and name e.g. 'JOINT hip'\n\t\t - list: collects a flat list of nodes\n\n\t\t returns: a BVH node including children\n\t\t*/\n function readNode(lines, firstline, list) {\n const node = { name: '', type: '', frames: [] }\n list.push(node)\n\n // parse node type and name\n\n let tokens = firstline.split(/[\\s]+/)\n\n if (tokens[0].toUpperCase() === 'END' && tokens[1].toUpperCase() === 'SITE') {\n node.type = 'ENDSITE'\n node.name = 'ENDSITE' // bvh end sites have no name\n } else {\n node.name = tokens[1]\n node.type = tokens[0].toUpperCase()\n }\n\n if (nextLine(lines) !== '{') {\n console.error('THREE.BVHLoader: Expected opening { after type & name')\n }\n\n // parse OFFSET\n\n tokens = nextLine(lines).split(/[\\s]+/)\n\n if (tokens[0] !== 'OFFSET') {\n console.error('THREE.BVHLoader: Expected OFFSET but got: ' + tokens[0])\n }\n\n if (tokens.length !== 4) {\n console.error('THREE.BVHLoader: Invalid number of values for OFFSET.')\n }\n\n const offset = new Vector3(parseFloat(tokens[1]), parseFloat(tokens[2]), parseFloat(tokens[3]))\n\n if (isNaN(offset.x) || isNaN(offset.y) || isNaN(offset.z)) {\n console.error('THREE.BVHLoader: Invalid values of OFFSET.')\n }\n\n node.offset = offset\n\n // parse CHANNELS definitions\n\n if (node.type !== 'ENDSITE') {\n tokens = nextLine(lines).split(/[\\s]+/)\n\n if (tokens[0] !== 'CHANNELS') {\n console.error('THREE.BVHLoader: Expected CHANNELS definition.')\n }\n\n const numChannels = parseInt(tokens[1])\n node.channels = tokens.splice(2, numChannels)\n node.children = []\n }\n\n // read children\n\n while (true) {\n const line = nextLine(lines)\n\n if (line === '}') {\n return node\n } else {\n node.children.push(readNode(lines, line, list))\n }\n }\n }\n\n /*\n\t\t\trecursively converts the internal bvh node structure to a Bone hierarchy\n\n\t\t\tsource: the bvh root node\n\t\t\tlist: pass an empty array, collects a flat list of all converted THREE.Bones\n\n\t\t\treturns the root Bone\n\t\t*/\n function toTHREEBone(source, list) {\n const bone = new Bone()\n list.push(bone)\n\n bone.position.add(source.offset)\n bone.name = source.name\n\n if (source.type !== 'ENDSITE') {\n for (let i = 0; i < source.children.length; i++) {\n bone.add(toTHREEBone(source.children[i], list))\n }\n }\n\n return bone\n }\n\n /*\n\t\t\tbuilds a AnimationClip from the keyframe data saved in each bone.\n\n\t\t\tbone: bvh root node\n\n\t\t\treturns: a AnimationClip containing position and quaternion tracks\n\t\t*/\n function toTHREEAnimation(bones) {\n const tracks = []\n\n // create a position and quaternion animation track for each node\n\n for (let i = 0; i < bones.length; i++) {\n const bone = bones[i]\n\n if (bone.type === 'ENDSITE') continue\n\n // track data\n\n const times = []\n const positions = []\n const rotations = []\n\n for (let j = 0; j < bone.frames.length; j++) {\n const frame = bone.frames[j]\n\n times.push(frame.time)\n\n // the animation system animates the position property,\n // so we have to add the joint offset to all values\n\n positions.push(frame.position.x + bone.offset.x)\n positions.push(frame.position.y + bone.offset.y)\n positions.push(frame.position.z + bone.offset.z)\n\n rotations.push(frame.rotation.x)\n rotations.push(frame.rotation.y)\n rotations.push(frame.rotation.z)\n rotations.push(frame.rotation.w)\n }\n\n if (scope.animateBonePositions) {\n tracks.push(new VectorKeyframeTrack('.bones[' + bone.name + '].position', times, positions))\n }\n\n if (scope.animateBoneRotations) {\n tracks.push(new QuaternionKeyframeTrack('.bones[' + bone.name + '].quaternion', times, rotations))\n }\n }\n\n return new AnimationClip('animation', -1, tracks)\n }\n\n /*\n\t\t\treturns the next non-empty line in lines\n\t\t*/\n function nextLine(lines) {\n let line\n // skip empty lines\n while ((line = lines.shift().trim()).length === 0) {}\n\n return line\n }\n\n const scope = this\n\n const lines = text.split(/[\\r\\n]+/g)\n\n const bones = readBvh(lines)\n\n const threeBones = []\n toTHREEBone(bones[0], threeBones)\n\n const threeClip = toTHREEAnimation(bones)\n\n return {\n skeleton: new Skeleton(threeBones),\n clip: threeClip,\n }\n }\n}\n\nexport { BVHLoader }\n"],"names":["Loader","FileLoader","lines","Vector3","Quaternion","Bone","bones","VectorKeyframeTrack","QuaternionKeyframeTrack","AnimationClip","Skeleton"],"mappings":"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"}