ModelAnimationCache.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*global define*/
  2. define([
  3. '../Core/Cartesian3',
  4. '../Core/defaultValue',
  5. '../Core/defined',
  6. '../Core/LinearSpline',
  7. '../Core/Matrix4',
  8. '../Core/Quaternion',
  9. '../Core/QuaternionSpline',
  10. './getModelAccessor'
  11. ], function(
  12. Cartesian3,
  13. defaultValue,
  14. defined,
  15. LinearSpline,
  16. Matrix4,
  17. Quaternion,
  18. QuaternionSpline,
  19. getModelAccessor) {
  20. "use strict";
  21. /*global WebGLRenderingContext*/
  22. /**
  23. * @private
  24. */
  25. var ModelAnimationCache = function() {
  26. };
  27. function getAccessorKey(model, accessor) {
  28. var gltf = model.gltf;
  29. var buffers = gltf.buffers;
  30. var bufferViews = gltf.bufferViews;
  31. var bufferView = bufferViews[accessor.bufferView];
  32. var buffer = buffers[bufferView.buffer];
  33. var byteOffset = bufferView.byteOffset + accessor.byteOffset;
  34. var byteLength = accessor.count * getModelAccessor(accessor).componentsPerAttribute;
  35. // buffer.path will be undefined when animations are embedded.
  36. return model.cacheKey + '//' + defaultValue(buffer.path, '') + '/' + byteOffset + '/' + byteLength;
  37. }
  38. var cachedAnimationParameters = {
  39. };
  40. var axisScratch = new Cartesian3();
  41. ModelAnimationCache.getAnimationParameterValues = function(model, accessor) {
  42. var key = getAccessorKey(model, accessor);
  43. var values = cachedAnimationParameters[key];
  44. if (!defined(values)) {
  45. // Cache miss
  46. var buffers = model._loadResources.buffers;
  47. var gltf = model.gltf;
  48. var bufferViews = gltf.bufferViews;
  49. var bufferView = bufferViews[accessor.bufferView];
  50. var componentType = accessor.componentType;
  51. var type = accessor.type;
  52. var count = accessor.count;
  53. // Convert typed array to Cesium types
  54. var typedArray = getModelAccessor(accessor).createArrayBufferView(buffers[bufferView.buffer], bufferView.byteOffset + accessor.byteOffset, count);
  55. var i;
  56. if ((componentType === WebGLRenderingContext.FLOAT) && (type === 'SCALAR')) {
  57. values = typedArray;
  58. }
  59. else if ((componentType === WebGLRenderingContext.FLOAT) && (type === 'VEC3')) {
  60. values = new Array(count);
  61. for (i = 0; i < count; ++i) {
  62. values[i] = Cartesian3.fromArray(typedArray, 3 * i);
  63. }
  64. } else if ((componentType === WebGLRenderingContext.FLOAT) && (type === 'VEC4')) {
  65. values = new Array(count);
  66. for (i = 0; i < count; ++i) {
  67. var byteOffset = 4 * i;
  68. values[i] = Quaternion.fromAxisAngle(Cartesian3.fromArray(typedArray, byteOffset, axisScratch), typedArray[byteOffset + 3]);
  69. }
  70. }
  71. // GLTF_SPEC: Support more parameter types when glTF supports targeting materials. https://github.com/KhronosGroup/glTF/issues/142
  72. if (defined(model.cacheKey)) {
  73. // Only cache when we can create a unique id
  74. cachedAnimationParameters[key] = values;
  75. }
  76. }
  77. return values;
  78. };
  79. var cachedAnimationSplines = {
  80. };
  81. function getAnimationSplineKey(model, animationName, samplerName) {
  82. return model.cacheKey + '//' + animationName + '/' + samplerName;
  83. }
  84. // GLTF_SPEC: https://github.com/KhronosGroup/glTF/issues/185
  85. var ConstantSpline = function(value) {
  86. this._value = value;
  87. };
  88. ConstantSpline.prototype.evaluate = function(time, result) {
  89. return this._value;
  90. };
  91. // END GLTF_SPEC
  92. ModelAnimationCache.getAnimationSpline = function(model, animationName, animation, samplerName, sampler, parameterValues) {
  93. var key = getAnimationSplineKey(model, animationName, samplerName);
  94. var spline = cachedAnimationSplines[key];
  95. if (!defined(spline)) {
  96. var times = parameterValues[sampler.input];
  97. var accessor = model.gltf.accessors[animation.parameters[sampler.output]];
  98. var controlPoints = parameterValues[sampler.output];
  99. // GLTF_SPEC: https://github.com/KhronosGroup/glTF/issues/185
  100. if ((times.length === 1) && (controlPoints.length === 1)) {
  101. spline = new ConstantSpline(controlPoints[0]);
  102. } else {
  103. // END GLTF_SPEC
  104. var componentType = accessor.componentType;
  105. var type = accessor.type;
  106. if (sampler.interpolation === 'LINEAR') {
  107. if ((componentType === WebGLRenderingContext.FLOAT) && (type === 'VEC3')) {
  108. spline = new LinearSpline({
  109. times : times,
  110. points : controlPoints
  111. });
  112. } else if ((componentType === WebGLRenderingContext.FLOAT) && (type === 'VEC4')) {
  113. spline = new QuaternionSpline({
  114. times : times,
  115. points : controlPoints
  116. });
  117. }
  118. // GLTF_SPEC: Support more parameter types when glTF supports targeting materials. https://github.com/KhronosGroup/glTF/issues/142
  119. }
  120. // GLTF_SPEC: Support new interpolators. https://github.com/KhronosGroup/glTF/issues/156
  121. }
  122. if (defined(model.cacheKey)) {
  123. // Only cache when we can create a unique id
  124. cachedAnimationSplines[key] = spline;
  125. }
  126. }
  127. return spline;
  128. };
  129. var cachedSkinInverseBindMatrices = {
  130. };
  131. ModelAnimationCache.getSkinInverseBindMatrices = function(model, accessor) {
  132. var key = getAccessorKey(model, accessor);
  133. var matrices = cachedSkinInverseBindMatrices[key];
  134. if (!defined(matrices)) {
  135. // Cache miss
  136. var buffers = model._loadResources.buffers;
  137. var gltf = model.gltf;
  138. var bufferViews = gltf.bufferViews;
  139. var bufferView = bufferViews[accessor.bufferView];
  140. var componentType = accessor.componentType;
  141. var type = accessor.type;
  142. var count = accessor.count;
  143. var typedArray = getModelAccessor(accessor).createArrayBufferView(buffers[bufferView.buffer], bufferView.byteOffset + accessor.byteOffset, count);
  144. matrices = new Array(count);
  145. if ((componentType === WebGLRenderingContext.FLOAT) && (type === 'MAT4')) {
  146. for (var i = 0; i < count; ++i) {
  147. matrices[i] = Matrix4.fromArray(typedArray, 16 * i);
  148. }
  149. }
  150. cachedSkinInverseBindMatrices[key] = matrices;
  151. }
  152. return matrices;
  153. };
  154. return ModelAnimationCache;
  155. });