import Cartesian3 from '../Core/Cartesian3.js'; import ComponentDatatype from '../Core/ComponentDatatype.js'; import defaultValue from '../Core/defaultValue.js'; import defined from '../Core/defined.js'; import LinearSpline from '../Core/LinearSpline.js'; import Matrix4 from '../Core/Matrix4.js'; import Quaternion from '../Core/Quaternion.js'; import QuaternionSpline from '../Core/QuaternionSpline.js'; import WebGLConstants from '../Core/WebGLConstants.js'; import WeightSpline from '../Core/WeightSpline.js'; import getAccessorByteStride from '../ThirdParty/GltfPipeline/getAccessorByteStride.js'; import numberOfComponentsForType from '../ThirdParty/GltfPipeline/numberOfComponentsForType.js'; import AttributeType from './AttributeType.js'; /** * @private */ function ModelAnimationCache() { } var dataUriRegex = /^data\:/i; function getAccessorKey(model, accessor) { var gltf = model.gltf; var buffers = gltf.buffers; var bufferViews = gltf.bufferViews; var bufferView = bufferViews[accessor.bufferView]; var buffer = buffers[bufferView.buffer]; var byteOffset = bufferView.byteOffset + accessor.byteOffset; var byteLength = accessor.count * numberOfComponentsForType(accessor.type); var uriKey = dataUriRegex.test(buffer.uri) ? '' : buffer.uri; return model.cacheKey + '//' + uriKey + '/' + byteOffset + '/' + byteLength; } var cachedAnimationParameters = { }; ModelAnimationCache.getAnimationParameterValues = function(model, accessor) { var key = getAccessorKey(model, accessor); var values = cachedAnimationParameters[key]; if (!defined(values)) { // Cache miss var gltf = model.gltf; var buffers = gltf.buffers; var bufferViews = gltf.bufferViews; var bufferView = bufferViews[accessor.bufferView]; var bufferId = bufferView.buffer; var buffer = buffers[bufferId]; var source = buffer.extras._pipeline.source; var componentType = accessor.componentType; var type = accessor.type; var numberOfComponents = numberOfComponentsForType(type); var count = accessor.count; var byteStride = getAccessorByteStride(gltf, accessor); values = new Array(count); var accessorByteOffset = defaultValue(accessor.byteOffset, 0); var byteOffset = bufferView.byteOffset + accessorByteOffset; for (var i = 0; i < count; i++) { var typedArrayView = ComponentDatatype.createArrayBufferView(componentType, source.buffer, source.byteOffset + byteOffset, numberOfComponents); if (type === 'SCALAR') { values[i] = typedArrayView[0]; } else if (type === 'VEC3') { values[i] = Cartesian3.fromArray(typedArrayView); } else if (type === 'VEC4') { values[i] = Quaternion.unpack(typedArrayView); } byteOffset += byteStride; } // GLTF_SPEC: Support more parameter types when glTF supports targeting materials. https://github.com/KhronosGroup/glTF/issues/142 if (defined(model.cacheKey)) { // Only cache when we can create a unique id cachedAnimationParameters[key] = values; } } return values; }; var cachedAnimationSplines = { }; function getAnimationSplineKey(model, animationName, samplerName) { return model.cacheKey + '//' + animationName + '/' + samplerName; } function ConstantSpline(value) { this._value = value; } ConstantSpline.prototype.evaluate = function(time, result) { return this._value; }; ConstantSpline.prototype.wrapTime = function(time) { return 0.0; }; ConstantSpline.prototype.clampTime = function(time) { return 0.0; }; ModelAnimationCache.getAnimationSpline = function(model, animationName, animation, samplerName, sampler, input, path, output) { var key = getAnimationSplineKey(model, animationName, samplerName); var spline = cachedAnimationSplines[key]; if (!defined(spline)) { var times = input; var controlPoints = output; if ((times.length === 1) && (controlPoints.length === 1)) { spline = new ConstantSpline(controlPoints[0]); } else if (sampler.interpolation === 'LINEAR') { if (path === 'translation' || path === 'scale') { spline = new LinearSpline({ times : times, points : controlPoints }); } else if (path === 'rotation') { spline = new QuaternionSpline({ times : times, points : controlPoints }); } else if (path === 'weights') { spline = new WeightSpline({ times : times, weights : controlPoints }); } // GLTF_SPEC: Support more parameter types when glTF supports targeting materials. https://github.com/KhronosGroup/glTF/issues/142 } if (defined(model.cacheKey)) { // Only cache when we can create a unique id cachedAnimationSplines[key] = spline; } } return spline; }; var cachedSkinInverseBindMatrices = { }; ModelAnimationCache.getSkinInverseBindMatrices = function(model, accessor) { var key = getAccessorKey(model, accessor); var matrices = cachedSkinInverseBindMatrices[key]; if (!defined(matrices)) { // Cache miss var gltf = model.gltf; var buffers = gltf.buffers; var bufferViews = gltf.bufferViews; var bufferViewId = accessor.bufferView; var bufferView = bufferViews[bufferViewId]; var bufferId = bufferView.buffer; var buffer = buffers[bufferId]; var source = buffer.extras._pipeline.source; var componentType = accessor.componentType; var type = accessor.type; var count = accessor.count; var byteStride = getAccessorByteStride(gltf, accessor); var byteOffset = bufferView.byteOffset + accessor.byteOffset; var numberOfComponents = numberOfComponentsForType(type); matrices = new Array(count); if ((componentType === WebGLConstants.FLOAT) && (type === AttributeType.MAT4)) { for (var i = 0; i < count; ++i) { var typedArrayView = ComponentDatatype.createArrayBufferView(componentType, source.buffer, source.byteOffset + byteOffset, numberOfComponents); matrices[i] = Matrix4.fromArray(typedArrayView); byteOffset += byteStride; } } cachedSkinInverseBindMatrices[key] = matrices; } return matrices; }; export default ModelAnimationCache;