GltfLoaderUtil.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import Cartesian2 from "../Core/Cartesian2.js";
  2. import Check from "../Core/Check.js";
  3. import defaultValue from "../Core/defaultValue.js";
  4. import defined from "../Core/defined.js";
  5. import Matrix3 from "../Core/Matrix3.js";
  6. import Sampler from "../Renderer/Sampler.js";
  7. import TextureMagnificationFilter from "../Renderer/TextureMagnificationFilter.js";
  8. import TextureMinificationFilter from "../Renderer/TextureMinificationFilter.js";
  9. import TextureWrap from "../Renderer/TextureWrap.js";
  10. import ModelComponents from "./ModelComponents.js";
  11. /**
  12. * glTF loading utilities.
  13. *
  14. * @namespace GltfLoaderUtil
  15. *
  16. * @private
  17. */
  18. const GltfLoaderUtil = {};
  19. /**
  20. * Get the image ID referenced by a texture.
  21. * <p>
  22. * When the texture has the EXT_texture_webp extension and the browser supports
  23. * WebP images the WebP image ID is returned.
  24. * </p>
  25. *
  26. * @param {Object} options Object with the following properties:
  27. * @param {Object} options.gltf The glTF JSON.
  28. * @param {Number} options.textureId The texture ID.
  29. * @param {SupportedImageFormats} options.supportedImageFormats The supported image formats.
  30. *
  31. * @returns {Number} The image ID.
  32. * @private
  33. */
  34. GltfLoaderUtil.getImageIdFromTexture = function (options) {
  35. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  36. const gltf = options.gltf;
  37. const textureId = options.textureId;
  38. const supportedImageFormats = options.supportedImageFormats;
  39. //>>includeStart('debug', pragmas.debug);
  40. Check.typeOf.object("options.gltf", gltf);
  41. Check.typeOf.number("options.textureId", textureId);
  42. Check.typeOf.object("options.supportedImageFormats", supportedImageFormats);
  43. //>>includeEnd('debug');
  44. const texture = gltf.textures[textureId];
  45. const extensions = texture.extensions;
  46. if (defined(extensions)) {
  47. if (supportedImageFormats.webp && defined(extensions.EXT_texture_webp)) {
  48. return extensions.EXT_texture_webp.source;
  49. } else if (
  50. supportedImageFormats.basis &&
  51. defined(extensions.KHR_texture_basisu)
  52. ) {
  53. return extensions.KHR_texture_basisu.source;
  54. }
  55. }
  56. return texture.source;
  57. };
  58. /**
  59. * Create a sampler for a texture.
  60. *
  61. * @param {Object} options Object with the following properties:
  62. * @param {Object} options.gltf The glTF JSON.
  63. * @param {Object} options.textureInfo The texture info object.
  64. * @param {Boolean} [options.compressedTextureNoMipmap=false] True when the texture is compressed and does not have an embedded mipmap.
  65. *
  66. * @returns {Sampler} The sampler.
  67. * @private
  68. */
  69. GltfLoaderUtil.createSampler = function (options) {
  70. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  71. const gltf = options.gltf;
  72. const textureInfo = options.textureInfo;
  73. const compressedTextureNoMipmap = defaultValue(
  74. options.compressedTextureNoMipmap,
  75. false
  76. );
  77. //>>includeStart('debug', pragmas.debug);
  78. Check.typeOf.object("options.gltf", gltf);
  79. Check.typeOf.object("options.textureInfo", textureInfo);
  80. //>>includeEnd('debug');
  81. // Default sampler properties
  82. let wrapS = TextureWrap.REPEAT;
  83. let wrapT = TextureWrap.REPEAT;
  84. let minFilter = TextureMinificationFilter.LINEAR;
  85. let magFilter = TextureMagnificationFilter.LINEAR;
  86. const textureId = textureInfo.index;
  87. const texture = gltf.textures[textureId];
  88. const samplerId = texture.sampler;
  89. if (defined(samplerId)) {
  90. const sampler = gltf.samplers[samplerId];
  91. wrapS = defaultValue(sampler.wrapS, wrapS);
  92. wrapT = defaultValue(sampler.wrapT, wrapT);
  93. minFilter = defaultValue(sampler.minFilter, minFilter);
  94. magFilter = defaultValue(sampler.magFilter, magFilter);
  95. }
  96. let usesTextureTransform = false;
  97. const extensions = textureInfo.extensions;
  98. if (defined(extensions) && defined(extensions.KHR_texture_transform)) {
  99. usesTextureTransform = true;
  100. }
  101. if (
  102. (compressedTextureNoMipmap || usesTextureTransform) &&
  103. minFilter !== TextureMinificationFilter.LINEAR &&
  104. minFilter !== TextureMinificationFilter.NEAREST
  105. ) {
  106. if (
  107. minFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST ||
  108. minFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR
  109. ) {
  110. minFilter = TextureMinificationFilter.NEAREST;
  111. } else {
  112. minFilter = TextureMinificationFilter.LINEAR;
  113. }
  114. }
  115. return new Sampler({
  116. wrapS: wrapS,
  117. wrapT: wrapT,
  118. minificationFilter: minFilter,
  119. magnificationFilter: magFilter,
  120. });
  121. };
  122. const defaultScale = new Cartesian2(1.0, 1.0);
  123. /**
  124. * Create a model texture reader.
  125. *
  126. * @param {Object} options Object with the following properties:
  127. * @param {Object} options.textureInfo The texture info JSON.
  128. * @param {String} [options.channels] The texture channels to read from.
  129. * @param {Texture} [options.texture] The texture object.
  130. *
  131. * @returns {ModelComponents.TextureReader} The texture reader for this model.
  132. */
  133. GltfLoaderUtil.createModelTextureReader = function (options) {
  134. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  135. const textureInfo = options.textureInfo;
  136. const channels = options.channels;
  137. const texture = options.texture;
  138. //>>includeStart('debug', pragmas.debug);
  139. Check.typeOf.object("options.textureInfo", textureInfo);
  140. //>>includeEnd('debug');
  141. let texCoord = defaultValue(textureInfo.texCoord, 0);
  142. let transform;
  143. const textureTransform = defaultValue(
  144. textureInfo.extensions,
  145. defaultValue.EMPTY_OBJECT
  146. ).KHR_texture_transform;
  147. if (defined(textureTransform)) {
  148. texCoord = defaultValue(textureTransform.texCoord, texCoord);
  149. const offset = defined(textureTransform.offset)
  150. ? Cartesian2.unpack(textureTransform.offset)
  151. : Cartesian2.ZERO;
  152. let rotation = defaultValue(textureTransform.rotation, 0.0);
  153. const scale = defined(textureTransform.scale)
  154. ? Cartesian2.unpack(textureTransform.scale)
  155. : defaultScale;
  156. // glTF assumes UV coordinates start with (0, 0) in the top left corner
  157. // (y-down) unlike WebGL which puts (0, 0) in the bottom left corner (y-up).
  158. // This means rotations are reversed since the angle from x to y is now
  159. // clockwise instead of CCW. Translations and scales are not impacted by
  160. // this.
  161. rotation = -rotation;
  162. // prettier-ignore
  163. transform = new Matrix3(
  164. Math.cos(rotation) * scale.x, -Math.sin(rotation) * scale.y, offset.x,
  165. Math.sin(rotation) * scale.x, Math.cos(rotation) * scale.y, offset.y,
  166. 0.0, 0.0, 1.0
  167. );
  168. }
  169. const modelTextureReader = new ModelComponents.TextureReader();
  170. modelTextureReader.index = textureInfo.index;
  171. modelTextureReader.texture = texture;
  172. modelTextureReader.texCoord = texCoord;
  173. modelTextureReader.transform = transform;
  174. modelTextureReader.channels = channels;
  175. return modelTextureReader;
  176. };
  177. export default GltfLoaderUtil;