ModelAnimationCache.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. import Cartesian3 from "../Core/Cartesian3.js";
  2. import ComponentDatatype from "../Core/ComponentDatatype.js";
  3. import defaultValue from "../Core/defaultValue.js";
  4. import defined from "../Core/defined.js";
  5. import LinearSpline from "../Core/LinearSpline.js";
  6. import Matrix4 from "../Core/Matrix4.js";
  7. import Quaternion from "../Core/Quaternion.js";
  8. import QuaternionSpline from "../Core/QuaternionSpline.js";
  9. import Spline from "../Core/Spline.js";
  10. import WebGLConstants from "../Core/WebGLConstants.js";
  11. import WeightSpline from "../Core/WeightSpline.js";
  12. import getAccessorByteStride from "../ThirdParty/GltfPipeline/getAccessorByteStride.js";
  13. import numberOfComponentsForType from "../ThirdParty/GltfPipeline/numberOfComponentsForType.js";
  14. import AttributeType from "./AttributeType.js";
  15. /**
  16. * @private
  17. */
  18. function ModelAnimationCache() {}
  19. var dataUriRegex = /^data\:/i;
  20. function getAccessorKey(model, accessor) {
  21. var gltf = model.gltf;
  22. var buffers = gltf.buffers;
  23. var bufferViews = gltf.bufferViews;
  24. var bufferView = bufferViews[accessor.bufferView];
  25. var buffer = buffers[bufferView.buffer];
  26. var byteOffset = bufferView.byteOffset + accessor.byteOffset;
  27. var byteLength = accessor.count * numberOfComponentsForType(accessor.type);
  28. var uriKey = dataUriRegex.test(buffer.uri) ? "" : buffer.uri;
  29. return model.cacheKey + "//" + uriKey + "/" + byteOffset + "/" + byteLength;
  30. }
  31. var cachedAnimationParameters = {};
  32. ModelAnimationCache.getAnimationParameterValues = function (model, accessor) {
  33. var key = getAccessorKey(model, accessor);
  34. var values = cachedAnimationParameters[key];
  35. if (!defined(values)) {
  36. // Cache miss
  37. var gltf = model.gltf;
  38. var buffers = gltf.buffers;
  39. var bufferViews = gltf.bufferViews;
  40. var bufferView = bufferViews[accessor.bufferView];
  41. var bufferId = bufferView.buffer;
  42. var buffer = buffers[bufferId];
  43. var source = buffer.extras._pipeline.source;
  44. var componentType = accessor.componentType;
  45. var type = accessor.type;
  46. var numberOfComponents = numberOfComponentsForType(type);
  47. var count = accessor.count;
  48. var byteStride = getAccessorByteStride(gltf, accessor);
  49. values = new Array(count);
  50. var accessorByteOffset = defaultValue(accessor.byteOffset, 0);
  51. var byteOffset = bufferView.byteOffset + accessorByteOffset;
  52. for (var i = 0; i < count; i++) {
  53. var typedArrayView = ComponentDatatype.createArrayBufferView(
  54. componentType,
  55. source.buffer,
  56. source.byteOffset + byteOffset,
  57. numberOfComponents
  58. );
  59. if (type === "SCALAR") {
  60. values[i] = typedArrayView[0];
  61. } else if (type === "VEC3") {
  62. values[i] = Cartesian3.fromArray(typedArrayView);
  63. } else if (type === "VEC4") {
  64. values[i] = Quaternion.unpack(typedArrayView);
  65. }
  66. byteOffset += byteStride;
  67. }
  68. // GLTF_SPEC: Support more parameter types when glTF supports targeting materials. https://github.com/KhronosGroup/glTF/issues/142
  69. if (defined(model.cacheKey)) {
  70. // Only cache when we can create a unique id
  71. cachedAnimationParameters[key] = values;
  72. }
  73. }
  74. return values;
  75. };
  76. var cachedAnimationSplines = {};
  77. function getAnimationSplineKey(model, animationName, samplerName) {
  78. return model.cacheKey + "//" + animationName + "/" + samplerName;
  79. }
  80. function ConstantSpline(value) {
  81. this._value = value;
  82. }
  83. ConstantSpline.prototype.evaluate = function (time, result) {
  84. return this._value;
  85. };
  86. ConstantSpline.prototype.wrapTime = function (time) {
  87. return 0.0;
  88. };
  89. ConstantSpline.prototype.clampTime = function (time) {
  90. return 0.0;
  91. };
  92. function SteppedSpline(backingSpline) {
  93. this._spline = backingSpline;
  94. this._lastTimeIndex = 0;
  95. }
  96. SteppedSpline.prototype.findTimeInterval = Spline.prototype.findTimeInterval;
  97. SteppedSpline.prototype.evaluate = function (time, result) {
  98. var i = (this._lastTimeIndex = this.findTimeInterval(
  99. time,
  100. this._lastTimeIndex
  101. ));
  102. var times = this._spline.times;
  103. var steppedTime = time >= times[i + 1] ? times[i + 1] : times[i];
  104. return this._spline.evaluate(steppedTime, result);
  105. };
  106. Object.defineProperties(SteppedSpline.prototype, {
  107. times: {
  108. get: function () {
  109. return this._spline.times;
  110. },
  111. },
  112. });
  113. SteppedSpline.prototype.wrapTime = function (time) {
  114. return this._spline.wrapTime(time);
  115. };
  116. SteppedSpline.prototype.clampTime = function (time) {
  117. return this._spline.clampTime(time);
  118. };
  119. ModelAnimationCache.getAnimationSpline = function (
  120. model,
  121. animationName,
  122. animation,
  123. samplerName,
  124. sampler,
  125. input,
  126. path,
  127. output
  128. ) {
  129. var key = getAnimationSplineKey(model, animationName, samplerName);
  130. var spline = cachedAnimationSplines[key];
  131. if (!defined(spline)) {
  132. var times = input;
  133. var controlPoints = output;
  134. if (times.length === 1 && controlPoints.length === 1) {
  135. spline = new ConstantSpline(controlPoints[0]);
  136. } else if (
  137. sampler.interpolation === "LINEAR" ||
  138. sampler.interpolation === "STEP"
  139. ) {
  140. if (path === "translation" || path === "scale") {
  141. spline = new LinearSpline({
  142. times: times,
  143. points: controlPoints,
  144. });
  145. } else if (path === "rotation") {
  146. spline = new QuaternionSpline({
  147. times: times,
  148. points: controlPoints,
  149. });
  150. } else if (path === "weights") {
  151. spline = new WeightSpline({
  152. times: times,
  153. weights: controlPoints,
  154. });
  155. }
  156. if (defined(spline) && sampler.interpolation === "STEP") {
  157. spline = new SteppedSpline(spline);
  158. }
  159. }
  160. if (defined(model.cacheKey)) {
  161. // Only cache when we can create a unique id
  162. cachedAnimationSplines[key] = spline;
  163. }
  164. }
  165. return spline;
  166. };
  167. var cachedSkinInverseBindMatrices = {};
  168. ModelAnimationCache.getSkinInverseBindMatrices = function (model, accessor) {
  169. var key = getAccessorKey(model, accessor);
  170. var matrices = cachedSkinInverseBindMatrices[key];
  171. if (!defined(matrices)) {
  172. // Cache miss
  173. var gltf = model.gltf;
  174. var buffers = gltf.buffers;
  175. var bufferViews = gltf.bufferViews;
  176. var bufferViewId = accessor.bufferView;
  177. var bufferView = bufferViews[bufferViewId];
  178. var bufferId = bufferView.buffer;
  179. var buffer = buffers[bufferId];
  180. var source = buffer.extras._pipeline.source;
  181. var componentType = accessor.componentType;
  182. var type = accessor.type;
  183. var count = accessor.count;
  184. var byteStride = getAccessorByteStride(gltf, accessor);
  185. var byteOffset = bufferView.byteOffset + accessor.byteOffset;
  186. var numberOfComponents = numberOfComponentsForType(type);
  187. matrices = new Array(count);
  188. if (componentType === WebGLConstants.FLOAT && type === AttributeType.MAT4) {
  189. for (var i = 0; i < count; ++i) {
  190. var typedArrayView = ComponentDatatype.createArrayBufferView(
  191. componentType,
  192. source.buffer,
  193. source.byteOffset + byteOffset,
  194. numberOfComponents
  195. );
  196. matrices[i] = Matrix4.fromArray(typedArrayView);
  197. byteOffset += byteStride;
  198. }
  199. }
  200. cachedSkinInverseBindMatrices[key] = matrices;
  201. }
  202. return matrices;
  203. };
  204. export default ModelAnimationCache;