UNPKG

buffered-interpolation

Version:

A class for handling interpolation of networked THREE.js objects.

221 lines (191 loc) 7.33 kB
"use strict"; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /* global THREE */ var INITIALIZING = 0; var BUFFERING = 1; var PLAYING = 2; var MODE_LERP = 0; var MODE_HERMITE = 1; var vectorPool = []; var quatPool = []; var framePool = []; var getPooledVector = function getPooledVector() { return vectorPool.shift() || new THREE.Vector3(); }; var getPooledQuaternion = function getPooledQuaternion() { return quatPool.shift() || new THREE.Quaternion(); }; var getPooledFrame = function getPooledFrame() { var frame = framePool.pop(); if (!frame) { frame = { position: new THREE.Vector3(), velocity: new THREE.Vector3(), scale: new THREE.Vector3(), quaternion: new THREE.Quaternion(), time: 0 }; } return frame; }; var freeFrame = function freeFrame(f) { return framePool.push(f); }; var InterpolationBuffer = function () { function InterpolationBuffer() { var mode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : MODE_LERP; var bufferTime = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.15; _classCallCheck(this, InterpolationBuffer); this.state = INITIALIZING; this.buffer = []; this.bufferTime = bufferTime * 1000; this.time = 0; this.mode = mode; this.originFrame = getPooledFrame(); this.position = new THREE.Vector3(); this.quaternion = new THREE.Quaternion(); this.scale = new THREE.Vector3(1, 1, 1); } _createClass(InterpolationBuffer, [{ key: "hermite", value: function hermite(target, t, p1, p2, v1, v2) { var t2 = t * t; var t3 = t * t * t; var a = 2 * t3 - 3 * t2 + 1; var b = -2 * t3 + 3 * t2; var c = t3 - 2 * t2 + t; var d = t3 - t2; target.copy(p1.multiplyScalar(a)); target.add(p2.multiplyScalar(b)); target.add(v1.multiplyScalar(c)); target.add(v2.multiplyScalar(d)); } }, { key: "lerp", value: function lerp(target, v1, v2, alpha) { target.lerpVectors(v1, v2, alpha); } }, { key: "slerp", value: function slerp(target, r1, r2, alpha) { THREE.Quaternion.slerp(r1, r2, target, alpha); } }, { key: "updateOriginFrameToBufferTail", value: function updateOriginFrameToBufferTail() { freeFrame(this.originFrame); this.originFrame = this.buffer.shift(); } }, { key: "appendBuffer", value: function appendBuffer(position, velocity, quaternion, scale) { var tail = this.buffer.length > 0 ? this.buffer[this.buffer.length - 1] : null; // update the last entry in the buffer if this is the same frame if (tail && tail.time === this.time) { if (position) { tail.position.copy(position); } if (velocity) { tail.velocity.copy(velocity); } if (quaternion) { tail.quaternion.copy(quaternion); } if (scale) { tail.scale.copy(scale); } } else { var priorFrame = tail || this.originFrame; var newFrame = getPooledFrame(); newFrame.position.copy(position || priorFrame.position); newFrame.velocity.copy(velocity || priorFrame.velocity); newFrame.quaternion.copy(quaternion || priorFrame.quaternion); newFrame.scale.copy(scale || priorFrame.scale); newFrame.time = this.time; this.buffer.push(newFrame); } } }, { key: "setTarget", value: function setTarget(position, velocity, quaternion, scale) { this.appendBuffer(position, velocity, quaternion, scale); } }, { key: "setPosition", value: function setPosition(position, velocity) { this.appendBuffer(position, velocity, null, null); } }, { key: "setQuaternion", value: function setQuaternion(quaternion) { this.appendBuffer(null, null, quaternion, null); } }, { key: "setScale", value: function setScale(scale) { this.appendBuffer(null, null, null, scale); } }, { key: "update", value: function update(delta) { if (this.state === INITIALIZING) { if (this.buffer.length > 0) { this.updateOriginFrameToBufferTail(); this.position.copy(this.originFrame.position); this.quaternion.copy(this.originFrame.quaternion); this.scale.copy(this.originFrame.scale); this.state = BUFFERING; } } if (this.state === BUFFERING) { if (this.buffer.length > 0 && this.time > this.bufferTime) { this.state = PLAYING; } } if (this.state === PLAYING) { var mark = this.time - this.bufferTime; //Purge this.buffer of expired frames while (this.buffer.length > 0 && mark > this.buffer[0].time) { //if this is the last frame in the buffer, just update the time and reuse it if (this.buffer.length > 1) { this.updateOriginFrameToBufferTail(); } else { this.originFrame.position.copy(this.buffer[0].position); this.originFrame.velocity.copy(this.buffer[0].velocity); this.originFrame.quaternion.copy(this.buffer[0].quaternion); this.originFrame.scale.copy(this.buffer[0].scale); this.originFrame.time = this.buffer[0].time; this.buffer[0].time = this.time + delta; } } if (this.buffer.length > 0 && this.buffer[0].time > 0) { var targetFrame = this.buffer[0]; var delta_time = targetFrame.time - this.originFrame.time; var alpha = (mark - this.originFrame.time) / delta_time; if (this.mode === MODE_LERP) { this.lerp(this.position, this.originFrame.position, targetFrame.position, alpha); } else if (this.mode === MODE_HERMITE) { this.hermite(this.position, alpha, this.originFrame.position, targetFrame.position, this.originFrame.velocity.multiplyScalar(delta_time), targetFrame.velocity.multiplyScalar(delta_time)); } this.slerp(this.quaternion, this.originFrame.quaternion, targetFrame.quaternion, alpha); this.lerp(this.scale, this.originFrame.scale, targetFrame.scale, alpha); } } if (this.state !== INITIALIZING) { this.time += delta; } } }, { key: "getPosition", value: function getPosition() { return this.position; } }, { key: "getQuaternion", value: function getQuaternion() { return this.quaternion; } }, { key: "getScale", value: function getScale() { return this.scale; } }]); return InterpolationBuffer; }(); module.exports = InterpolationBuffer;