updateVersion.js 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937
  1. import addExtensionsUsed from './addExtensionsUsed.js'
  2. import addToArray from './addToArray.js'
  3. import findAccessorMinMax from './findAccessorMinMax.js'
  4. import ForEach from './ForEach.js'
  5. import getAccessorByteStride from './getAccessorByteStride.js'
  6. import numberOfComponentsForType from './numberOfComponentsForType.js'
  7. import moveTechniqueRenderStates from './moveTechniqueRenderStates.js'
  8. import moveTechniquesToExtension from './moveTechniquesToExtension.js'
  9. import removeUnusedElements from './removeUnusedElements.js'
  10. import updateAccessorComponentTypes from './updateAccessorComponentTypes.js'
  11. import Cartesian3 from '../../Core/Cartesian3.js'
  12. import Cartesian4 from '../../Core/Cartesian4.js'
  13. import clone from '../../Core/clone.js'
  14. import ComponentDatatype from '../../Core/ComponentDatatype.js'
  15. import defaultValue from '../../Core/defaultValue.js'
  16. import defined from '../../Core/defined.js'
  17. import isArray from '../../Core/isArray.js'
  18. import Matrix4 from '../../Core/Matrix4.js'
  19. import Quaternion from '../../Core/Quaternion.js'
  20. import WebGLConstants from '../../Core/WebGLConstants.js'
  21. var updateFunctions = {
  22. '0.8': glTF08to10,
  23. '1.0': glTF10to20,
  24. '2.0': undefined
  25. };
  26. /**
  27. * Update the glTF version to the latest version (2.0), or targetVersion if specified.
  28. * Applies changes made to the glTF spec between revisions so that the core library
  29. * only has to handle the latest version.
  30. *
  31. * @param {Object} gltf A javascript object containing a glTF asset.
  32. * @param {Object} [options] Options for updating the glTF.
  33. * @param {String} [options.targetVersion] The glTF will be upgraded until it hits the specified version.
  34. * @returns {Object} The updated glTF asset.
  35. *
  36. * @private
  37. */
  38. function updateVersion(gltf, options) {
  39. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  40. var targetVersion = options.targetVersion;
  41. var version = gltf.version;
  42. gltf.asset = defaultValue(gltf.asset, {
  43. version: '1.0'
  44. });
  45. gltf.asset.version = defaultValue(gltf.asset.version, '1.0');
  46. version = defaultValue(version, gltf.asset.version).toString();
  47. // Invalid version
  48. if (!Object.prototype.hasOwnProperty.call(updateFunctions, version)) {
  49. // Try truncating trailing version numbers, could be a number as well if it is 0.8
  50. if (defined(version)) {
  51. version = version.substring(0, 3);
  52. }
  53. // Default to 1.0 if it cannot be determined
  54. if (!Object.prototype.hasOwnProperty.call(updateFunctions, version)) {
  55. version = '1.0';
  56. }
  57. }
  58. var updateFunction = updateFunctions[version];
  59. while (defined(updateFunction)) {
  60. if (version === targetVersion) {
  61. break;
  62. }
  63. updateFunction(gltf, options);
  64. version = gltf.asset.version;
  65. updateFunction = updateFunctions[version];
  66. }
  67. return gltf;
  68. }
  69. function updateInstanceTechniques(gltf) {
  70. var materials = gltf.materials;
  71. for (var materialId in materials) {
  72. if (Object.prototype.hasOwnProperty.call(materials, materialId)) {
  73. var material = materials[materialId];
  74. var instanceTechnique = material.instanceTechnique;
  75. if (defined(instanceTechnique)) {
  76. material.technique = instanceTechnique.technique;
  77. material.values = instanceTechnique.values;
  78. delete material.instanceTechnique;
  79. }
  80. }
  81. }
  82. }
  83. function setPrimitiveModes(gltf) {
  84. var meshes = gltf.meshes;
  85. for (var meshId in meshes) {
  86. if (Object.prototype.hasOwnProperty.call(meshes, meshId)) {
  87. var mesh = meshes[meshId];
  88. var primitives = mesh.primitives;
  89. if (defined(primitives)) {
  90. var primitivesLength = primitives.length;
  91. for (var i = 0; i < primitivesLength; ++i) {
  92. var primitive = primitives[i];
  93. var defaultMode = defaultValue(primitive.primitive, WebGLConstants.TRIANGLES);
  94. primitive.mode = defaultValue(primitive.mode, defaultMode);
  95. delete primitive.primitive;
  96. }
  97. }
  98. }
  99. }
  100. }
  101. function updateNodes(gltf) {
  102. var nodes = gltf.nodes;
  103. var axis = new Cartesian3();
  104. var quat = new Quaternion();
  105. for (var nodeId in nodes) {
  106. if (Object.prototype.hasOwnProperty.call(nodes, nodeId)) {
  107. var node = nodes[nodeId];
  108. if (defined(node.rotation)) {
  109. var rotation = node.rotation;
  110. Cartesian3.fromArray(rotation, 0, axis);
  111. Quaternion.fromAxisAngle(axis, rotation[3], quat);
  112. node.rotation = [quat.x, quat.y, quat.z, quat.w];
  113. }
  114. var instanceSkin = node.instanceSkin;
  115. if (defined(instanceSkin)) {
  116. node.skeletons = instanceSkin.skeletons;
  117. node.skin = instanceSkin.skin;
  118. node.meshes = instanceSkin.meshes;
  119. delete node.instanceSkin;
  120. }
  121. }
  122. }
  123. }
  124. function updateAnimations(gltf) {
  125. var animations = gltf.animations;
  126. var accessors = gltf.accessors;
  127. var bufferViews = gltf.bufferViews;
  128. var buffers = gltf.buffers;
  129. var updatedAccessors = {};
  130. var axis = new Cartesian3();
  131. var quat = new Quaternion();
  132. for (var animationId in animations) {
  133. if (Object.prototype.hasOwnProperty.call(animations, animationId)) {
  134. var animation = animations[animationId];
  135. var channels = animation.channels;
  136. var parameters = animation.parameters;
  137. var samplers = animation.samplers;
  138. if (defined(channels)) {
  139. var channelsLength = channels.length;
  140. for (var i = 0; i < channelsLength; ++i) {
  141. var channel = channels[i];
  142. if (channel.target.path === 'rotation') {
  143. var accessorId = parameters[samplers[channel.sampler].output];
  144. if (defined(updatedAccessors[accessorId])) {
  145. continue;
  146. }
  147. updatedAccessors[accessorId] = true;
  148. var accessor = accessors[accessorId];
  149. var bufferView = bufferViews[accessor.bufferView];
  150. var buffer = buffers[bufferView.buffer];
  151. var source = buffer.extras._pipeline.source;
  152. var byteOffset = source.byteOffset + bufferView.byteOffset + accessor.byteOffset;
  153. var componentType = accessor.componentType;
  154. var count = accessor.count;
  155. var componentsLength = numberOfComponentsForType(accessor.type);
  156. var length = accessor.count * componentsLength;
  157. var typedArray = ComponentDatatype.createArrayBufferView(componentType, source.buffer, byteOffset, length);
  158. for (var j = 0; j < count; j++) {
  159. var offset = j * componentsLength;
  160. Cartesian3.unpack(typedArray, offset, axis);
  161. var angle = typedArray[offset + 3];
  162. Quaternion.fromAxisAngle(axis, angle, quat);
  163. Quaternion.pack(quat, typedArray, offset);
  164. }
  165. }
  166. }
  167. }
  168. }
  169. }
  170. }
  171. function removeTechniquePasses(gltf) {
  172. var techniques = gltf.techniques;
  173. for (var techniqueId in techniques) {
  174. if (Object.prototype.hasOwnProperty.call(techniques, techniqueId)) {
  175. var technique = techniques[techniqueId];
  176. var passes = technique.passes;
  177. if (defined(passes)) {
  178. var passName = defaultValue(technique.pass, 'defaultPass');
  179. if (Object.prototype.hasOwnProperty.call(passes, passName)) {
  180. var pass = passes[passName];
  181. var instanceProgram = pass.instanceProgram;
  182. technique.attributes = defaultValue(technique.attributes, instanceProgram.attributes);
  183. technique.program = defaultValue(technique.program, instanceProgram.program);
  184. technique.uniforms = defaultValue(technique.uniforms, instanceProgram.uniforms);
  185. technique.states = defaultValue(technique.states, pass.states);
  186. }
  187. delete technique.passes;
  188. delete technique.pass;
  189. }
  190. }
  191. }
  192. }
  193. function glTF08to10(gltf) {
  194. if (!defined(gltf.asset)) {
  195. gltf.asset = {};
  196. }
  197. var asset = gltf.asset;
  198. asset.version = '1.0';
  199. // Profile should be an object, not a string
  200. if (typeof asset.profile === 'string') {
  201. var split = asset.profile.split(' ');
  202. asset.profile = {
  203. api: split[0],
  204. version: split[1]
  205. };
  206. } else {
  207. asset.profile = {};
  208. }
  209. // Version property should be in asset, not on the root element
  210. if (defined(gltf.version)) {
  211. delete gltf.version;
  212. }
  213. // material.instanceTechnique properties should be directly on the material
  214. updateInstanceTechniques(gltf);
  215. // primitive.primitive should be primitive.mode
  216. setPrimitiveModes(gltf);
  217. // Node rotation should be quaternion, not axis-angle
  218. // node.instanceSkin is deprecated
  219. updateNodes(gltf);
  220. // Animations that target rotations should be quaternion, not axis-angle
  221. updateAnimations(gltf);
  222. // technique.pass and techniques.passes are deprecated
  223. removeTechniquePasses(gltf);
  224. // gltf.allExtensions -> extensionsUsed
  225. if (defined(gltf.allExtensions)) {
  226. gltf.extensionsUsed = gltf.allExtensions;
  227. delete gltf.allExtensions;
  228. }
  229. // gltf.lights -> khrMaterialsCommon.lights
  230. if (defined(gltf.lights)) {
  231. var extensions = defaultValue(gltf.extensions, {});
  232. gltf.extensions = extensions;
  233. var materialsCommon = defaultValue(extensions.KHR_materials_common, {});
  234. extensions.KHR_materials_common = materialsCommon;
  235. materialsCommon.lights = gltf.lights;
  236. delete gltf.lights;
  237. addExtensionsUsed(gltf, 'KHR_materials_common');
  238. }
  239. }
  240. function removeAnimationSamplersIndirection(gltf) {
  241. var animations = gltf.animations;
  242. for (var animationId in animations) {
  243. if (Object.prototype.hasOwnProperty.call(animations, animationId)) {
  244. var animation = animations[animationId];
  245. var parameters = animation.parameters;
  246. if (defined(parameters)) {
  247. var samplers = animation.samplers;
  248. for (var samplerId in samplers) {
  249. if (Object.prototype.hasOwnProperty.call(samplers, samplerId)) {
  250. var sampler = samplers[samplerId];
  251. sampler.input = parameters[sampler.input];
  252. sampler.output = parameters[sampler.output];
  253. }
  254. }
  255. delete animation.parameters;
  256. }
  257. }
  258. }
  259. }
  260. function objectToArray(object, mapping) {
  261. var array = [];
  262. for (var id in object) {
  263. if (Object.prototype.hasOwnProperty.call(object, id)) {
  264. var value = object[id];
  265. mapping[id] = array.length;
  266. array.push(value);
  267. if (!defined(value.name)) {
  268. value.name = id;
  269. }
  270. }
  271. }
  272. return array;
  273. }
  274. function objectsToArrays(gltf) {
  275. var i;
  276. var globalMapping = {
  277. accessors: {},
  278. animations: {},
  279. buffers: {},
  280. bufferViews: {},
  281. cameras: {},
  282. images: {},
  283. materials: {},
  284. meshes: {},
  285. nodes: {},
  286. programs: {},
  287. samplers: {},
  288. scenes: {},
  289. shaders: {},
  290. skins: {},
  291. textures: {},
  292. techniques: {}
  293. };
  294. // Map joint names to id names
  295. var jointName;
  296. var jointNameToId = {};
  297. var nodes = gltf.nodes;
  298. for (var id in nodes) {
  299. if (Object.prototype.hasOwnProperty.call(nodes, id)) {
  300. jointName = nodes[id].jointName;
  301. if (defined(jointName)) {
  302. jointNameToId[jointName] = id;
  303. }
  304. }
  305. }
  306. // Convert top level objects to arrays
  307. for (var topLevelId in gltf) {
  308. if (Object.prototype.hasOwnProperty.call(gltf, topLevelId) && defined(globalMapping[topLevelId])) {
  309. var objectMapping = {};
  310. var object = gltf[topLevelId];
  311. gltf[topLevelId] = objectToArray(object, objectMapping);
  312. globalMapping[topLevelId] = objectMapping;
  313. }
  314. }
  315. // Remap joint names to array indexes
  316. for (jointName in jointNameToId) {
  317. if (Object.prototype.hasOwnProperty.call(jointNameToId, jointName)) {
  318. jointNameToId[jointName] = globalMapping.nodes[jointNameToId[jointName]];
  319. }
  320. }
  321. // Fix references
  322. if (defined(gltf.scene)) {
  323. gltf.scene = globalMapping.scenes[gltf.scene];
  324. }
  325. ForEach.bufferView(gltf, function(bufferView) {
  326. if (defined(bufferView.buffer)) {
  327. bufferView.buffer = globalMapping.buffers[bufferView.buffer];
  328. }
  329. });
  330. ForEach.accessor(gltf, function(accessor) {
  331. if (defined(accessor.bufferView)) {
  332. accessor.bufferView = globalMapping.bufferViews[accessor.bufferView];
  333. }
  334. });
  335. ForEach.shader(gltf, function(shader) {
  336. var extensions = shader.extensions;
  337. if (defined(extensions)) {
  338. var binaryGltf = extensions.KHR_binary_glTF;
  339. if (defined(binaryGltf)) {
  340. shader.bufferView = globalMapping.bufferViews[binaryGltf.bufferView];
  341. delete extensions.KHR_binary_glTF;
  342. }
  343. if (Object.keys(extensions).length === 0) {
  344. delete shader.extensions;
  345. }
  346. }
  347. });
  348. ForEach.program(gltf, function(program) {
  349. if (defined(program.vertexShader)) {
  350. program.vertexShader = globalMapping.shaders[program.vertexShader];
  351. }
  352. if (defined(program.fragmentShader)) {
  353. program.fragmentShader = globalMapping.shaders[program.fragmentShader];
  354. }
  355. });
  356. ForEach.technique(gltf, function(technique) {
  357. if (defined(technique.program)) {
  358. technique.program = globalMapping.programs[technique.program];
  359. }
  360. ForEach.techniqueParameter(technique, function(parameter) {
  361. if (defined(parameter.node)) {
  362. parameter.node = globalMapping.nodes[parameter.node];
  363. }
  364. var value = parameter.value;
  365. if (typeof value === 'string') {
  366. parameter.value = {
  367. index: globalMapping.textures[value]
  368. };
  369. }
  370. });
  371. });
  372. ForEach.mesh(gltf, function(mesh) {
  373. ForEach.meshPrimitive(mesh, function(primitive) {
  374. if (defined(primitive.indices)) {
  375. primitive.indices = globalMapping.accessors[primitive.indices];
  376. }
  377. ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) {
  378. primitive.attributes[semantic] = globalMapping.accessors[accessorId];
  379. });
  380. if (defined(primitive.material)) {
  381. primitive.material = globalMapping.materials[primitive.material];
  382. }
  383. });
  384. });
  385. ForEach.node(gltf, function(node) {
  386. var children = node.children;
  387. if (defined(children)) {
  388. var childrenLength = children.length;
  389. for (i = 0; i < childrenLength; ++i) {
  390. children[i] = globalMapping.nodes[children[i]];
  391. }
  392. }
  393. if (defined(node.meshes)) {
  394. // Split out meshes on nodes
  395. var meshes = node.meshes;
  396. var meshesLength = meshes.length;
  397. if (meshesLength > 0) {
  398. node.mesh = globalMapping.meshes[meshes[0]];
  399. for (i = 1; i < meshesLength; ++i) {
  400. var meshNode = {
  401. mesh: globalMapping.meshes[meshes[i]]
  402. };
  403. var meshNodeId = addToArray(gltf.nodes, meshNode);
  404. if (!defined(children)) {
  405. children = [];
  406. node.children = children;
  407. }
  408. children.push(meshNodeId);
  409. }
  410. }
  411. delete node.meshes;
  412. }
  413. if (defined(node.camera)) {
  414. node.camera = globalMapping.cameras[node.camera];
  415. }
  416. if (defined(node.skin)) {
  417. node.skin = globalMapping.skins[node.skin];
  418. }
  419. if (defined(node.skeletons)) {
  420. // Assign skeletons to skins
  421. var skeletons = node.skeletons;
  422. var skeletonsLength = skeletons.length;
  423. if ((skeletonsLength > 0) && defined(node.skin)) {
  424. var skin = gltf.skins[node.skin];
  425. skin.skeleton = globalMapping.nodes[skeletons[0]];
  426. }
  427. delete node.skeletons;
  428. }
  429. if (defined(node.jointName)) {
  430. delete node.jointName;
  431. }
  432. });
  433. ForEach.skin(gltf, function(skin) {
  434. if (defined(skin.inverseBindMatrices)) {
  435. skin.inverseBindMatrices = globalMapping.accessors[skin.inverseBindMatrices];
  436. }
  437. var jointNames = skin.jointNames;
  438. if (defined(jointNames)) {
  439. var joints = [];
  440. var jointNamesLength = jointNames.length;
  441. for (i = 0; i < jointNamesLength; ++i) {
  442. joints[i] = jointNameToId[jointNames[i]];
  443. }
  444. skin.joints = joints;
  445. delete skin.jointNames;
  446. }
  447. });
  448. ForEach.scene(gltf, function(scene) {
  449. var sceneNodes = scene.nodes;
  450. if (defined(sceneNodes)) {
  451. var sceneNodesLength = sceneNodes.length;
  452. for (i = 0; i < sceneNodesLength; ++i) {
  453. sceneNodes[i] = globalMapping.nodes[sceneNodes[i]];
  454. }
  455. }
  456. });
  457. ForEach.animation(gltf, function(animation) {
  458. var samplerMapping = {};
  459. animation.samplers = objectToArray(animation.samplers, samplerMapping);
  460. ForEach.animationSampler(animation, function(sampler) {
  461. sampler.input = globalMapping.accessors[sampler.input];
  462. sampler.output = globalMapping.accessors[sampler.output];
  463. });
  464. ForEach.animationChannel(animation, function(channel) {
  465. channel.sampler = samplerMapping[channel.sampler];
  466. var target = channel.target;
  467. if (defined(target)) {
  468. target.node = globalMapping.nodes[target.id];
  469. delete target.id;
  470. }
  471. });
  472. });
  473. ForEach.material(gltf, function(material) {
  474. if (defined(material.technique)) {
  475. material.technique = globalMapping.techniques[material.technique];
  476. }
  477. ForEach.materialValue(material, function(value, name) {
  478. if (typeof value === 'string') {
  479. material.values[name] = {
  480. index: globalMapping.textures[value]
  481. };
  482. }
  483. });
  484. var extensions = material.extensions;
  485. if (defined(extensions)) {
  486. var materialsCommon = extensions.KHR_materials_common;
  487. if (defined(materialsCommon)) {
  488. ForEach.materialValue(materialsCommon, function(value, name) {
  489. if (typeof value === 'string') {
  490. materialsCommon.values[name] = {
  491. index: globalMapping.textures[value]
  492. };
  493. }
  494. });
  495. }
  496. }
  497. });
  498. ForEach.image(gltf, function(image) {
  499. var extensions = image.extensions;
  500. if (defined(extensions)) {
  501. var binaryGltf = extensions.KHR_binary_glTF;
  502. if (defined(binaryGltf)) {
  503. image.bufferView = globalMapping.bufferViews[binaryGltf.bufferView];
  504. image.mimeType = binaryGltf.mimeType;
  505. delete extensions.KHR_binary_glTF;
  506. }
  507. if (Object.keys(extensions).length === 0) {
  508. delete image.extensions;
  509. }
  510. }
  511. ForEach.compressedImage(image, function(compressedImage) {
  512. var compressedExtensions = compressedImage.extensions;
  513. if (defined(compressedExtensions)) {
  514. var compressedBinaryGltf = compressedExtensions.KHR_binary_glTF;
  515. if (defined(compressedBinaryGltf)) {
  516. compressedImage.bufferView = globalMapping.bufferViews[compressedBinaryGltf.bufferView];
  517. compressedImage.mimeType = compressedBinaryGltf.mimeType;
  518. delete compressedExtensions.KHR_binary_glTF;
  519. }
  520. if (Object.keys(extensions).length === 0) {
  521. delete compressedImage.extensions;
  522. }
  523. }
  524. });
  525. });
  526. ForEach.texture(gltf, function(texture) {
  527. if (defined(texture.sampler)) {
  528. texture.sampler = globalMapping.samplers[texture.sampler];
  529. }
  530. if (defined(texture.source)) {
  531. texture.source = globalMapping.images[texture.source];
  532. }
  533. });
  534. }
  535. function removeAnimationSamplerNames(gltf) {
  536. ForEach.animation(gltf, function(animation) {
  537. ForEach.animationSampler(animation, function(sampler) {
  538. delete sampler.name;
  539. });
  540. });
  541. }
  542. function removeEmptyArrays(gltf) {
  543. for (var topLevelId in gltf) {
  544. if (Object.prototype.hasOwnProperty.call(gltf, topLevelId)) {
  545. var array = gltf[topLevelId];
  546. if (isArray(array) && array.length === 0) {
  547. delete gltf[topLevelId];
  548. }
  549. }
  550. }
  551. ForEach.node(gltf, function(node) {
  552. if (defined(node.children) && node.children.length === 0) {
  553. delete node.children;
  554. }
  555. });
  556. }
  557. function stripAsset(gltf) {
  558. var asset = gltf.asset;
  559. delete asset.profile;
  560. delete asset.premultipliedAlpha;
  561. }
  562. var knownExtensions = {
  563. CESIUM_RTC: true,
  564. KHR_materials_common: true,
  565. WEB3D_quantized_attributes: true
  566. };
  567. function requireKnownExtensions(gltf) {
  568. var extensionsUsed = gltf.extensionsUsed;
  569. gltf.extensionsRequired = defaultValue(gltf.extensionsRequired, []);
  570. if (defined(extensionsUsed)) {
  571. var extensionsUsedLength = extensionsUsed.length;
  572. for (var i = 0; i < extensionsUsedLength; ++i) {
  573. var extension = extensionsUsed[i];
  574. if (defined(knownExtensions[extension])) {
  575. gltf.extensionsRequired.push(extension);
  576. }
  577. }
  578. }
  579. }
  580. function removeBufferType(gltf) {
  581. ForEach.buffer(gltf, function(buffer) {
  582. delete buffer.type;
  583. });
  584. }
  585. function removeTextureProperties(gltf) {
  586. ForEach.texture(gltf, function(texture) {
  587. delete texture.format;
  588. delete texture.internalFormat;
  589. delete texture.target;
  590. delete texture.type;
  591. });
  592. }
  593. function requireAttributeSetIndex(gltf) {
  594. ForEach.mesh(gltf, function(mesh) {
  595. ForEach.meshPrimitive(mesh, function(primitive) {
  596. ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) {
  597. if (semantic === 'TEXCOORD') {
  598. primitive.attributes.TEXCOORD_0 = accessorId;
  599. } else if (semantic === 'COLOR') {
  600. primitive.attributes.COLOR_0 = accessorId;
  601. }
  602. });
  603. delete primitive.attributes.TEXCOORD;
  604. delete primitive.attributes.COLOR;
  605. });
  606. });
  607. ForEach.technique(gltf, function(technique) {
  608. ForEach.techniqueParameter(technique, function(parameter) {
  609. var semantic = parameter.semantic;
  610. if (defined(semantic)) {
  611. if (semantic === 'TEXCOORD') {
  612. parameter.semantic = 'TEXCOORD_0';
  613. } else if (semantic === 'COLOR') {
  614. parameter.semantic = 'COLOR_0';
  615. }
  616. }
  617. });
  618. });
  619. }
  620. var knownSemantics = {
  621. POSITION: true,
  622. NORMAL: true,
  623. TANGENT: true
  624. };
  625. var indexedSemantics = {
  626. COLOR: 'COLOR',
  627. JOINT : 'JOINTS',
  628. JOINTS: 'JOINTS',
  629. TEXCOORD: 'TEXCOORD',
  630. WEIGHT: 'WEIGHTS',
  631. WEIGHTS: 'WEIGHTS'
  632. };
  633. function underscoreApplicationSpecificSemantics(gltf) {
  634. var mappedSemantics = {};
  635. ForEach.mesh(gltf, function(mesh) {
  636. ForEach.meshPrimitive(mesh, function(primitive) {
  637. /*eslint-disable no-unused-vars*/
  638. ForEach.meshPrimitiveAttribute(primitive, function(accessorId, semantic) {
  639. if (semantic.charAt(0) !== '_') {
  640. var setIndex = semantic.search(/_[0-9]+/g);
  641. var strippedSemantic = semantic;
  642. var suffix = '_0';
  643. if (setIndex >= 0) {
  644. strippedSemantic = semantic.substring(0, setIndex);
  645. suffix = semantic.substring(setIndex);
  646. }
  647. var newSemantic;
  648. var indexedSemantic = indexedSemantics[strippedSemantic];
  649. if (defined(indexedSemantic)) {
  650. newSemantic = indexedSemantic + suffix;
  651. mappedSemantics[semantic] = newSemantic;
  652. } else if (!defined(knownSemantics[strippedSemantic])) {
  653. newSemantic = '_' + semantic;
  654. mappedSemantics[semantic] = newSemantic;
  655. }
  656. }
  657. });
  658. for (var semantic in mappedSemantics) {
  659. if (Object.prototype.hasOwnProperty.call(mappedSemantics, semantic)) {
  660. var mappedSemantic = mappedSemantics[semantic];
  661. var accessorId = primitive.attributes[semantic];
  662. if (defined(accessorId)) {
  663. delete primitive.attributes[semantic];
  664. primitive.attributes[mappedSemantic] = accessorId;
  665. }
  666. }
  667. }
  668. });
  669. });
  670. ForEach.technique(gltf, function(technique) {
  671. ForEach.techniqueParameter(technique, function(parameter) {
  672. var mappedSemantic = mappedSemantics[parameter.semantic];
  673. if (defined(mappedSemantic)) {
  674. parameter.semantic = mappedSemantic;
  675. }
  676. });
  677. });
  678. }
  679. function clampCameraParameters(gltf) {
  680. ForEach.camera(gltf, function(camera) {
  681. var perspective = camera.perspective;
  682. if (defined(perspective)) {
  683. var aspectRatio = perspective.aspectRatio;
  684. if (defined(aspectRatio) && aspectRatio === 0.0) {
  685. delete perspective.aspectRatio;
  686. }
  687. var yfov = perspective.yfov;
  688. if (defined(yfov) && yfov === 0.0) {
  689. perspective.yfov = 1.0;
  690. }
  691. }
  692. });
  693. }
  694. function computeAccessorByteStride(gltf, accessor) {
  695. return (defined(accessor.byteStride) && accessor.byteStride !== 0) ? accessor.byteStride : getAccessorByteStride(gltf, accessor);
  696. }
  697. function requireByteLength(gltf) {
  698. ForEach.buffer(gltf, function(buffer) {
  699. if (!defined(buffer.byteLength)) {
  700. buffer.byteLength = buffer.extras._pipeline.source.length;
  701. }
  702. });
  703. ForEach.accessor(gltf, function(accessor) {
  704. var bufferViewId = accessor.bufferView;
  705. if (defined(bufferViewId)) {
  706. var bufferView = gltf.bufferViews[bufferViewId];
  707. var accessorByteStride = computeAccessorByteStride(gltf, accessor);
  708. var accessorByteEnd = accessor.byteOffset + accessor.count * accessorByteStride;
  709. bufferView.byteLength = Math.max(defaultValue(bufferView.byteLength, 0), accessorByteEnd);
  710. }
  711. });
  712. }
  713. function moveByteStrideToBufferView(gltf) {
  714. var i;
  715. var j;
  716. var bufferView;
  717. var bufferViews = gltf.bufferViews;
  718. var bufferViewHasVertexAttributes = {};
  719. ForEach.accessorContainingVertexAttributeData(gltf, function(accessorId) {
  720. var accessor = gltf.accessors[accessorId];
  721. if (defined(accessor.bufferView)) {
  722. bufferViewHasVertexAttributes[accessor.bufferView] = true;
  723. }
  724. });
  725. // Map buffer views to a list of accessors
  726. var bufferViewMap = {};
  727. ForEach.accessor(gltf, function(accessor) {
  728. if (defined(accessor.bufferView)) {
  729. bufferViewMap[accessor.bufferView] = defaultValue(bufferViewMap[accessor.bufferView], []);
  730. bufferViewMap[accessor.bufferView].push(accessor);
  731. }
  732. });
  733. // Split accessors with different byte strides
  734. for (var bufferViewId in bufferViewMap) {
  735. if (Object.prototype.hasOwnProperty.call(bufferViewMap, bufferViewId)) {
  736. bufferView = bufferViews[bufferViewId];
  737. var accessors = bufferViewMap[bufferViewId];
  738. accessors.sort(function(a, b) {
  739. return a.byteOffset - b.byteOffset;
  740. });
  741. var currentByteOffset = 0;
  742. var currentIndex = 0;
  743. var accessorsLength = accessors.length;
  744. for (i = 0; i < accessorsLength; ++i) {
  745. var accessor = accessors[i];
  746. var accessorByteStride = computeAccessorByteStride(gltf, accessor);
  747. var accessorByteOffset = accessor.byteOffset;
  748. var accessorByteLength = accessor.count * accessorByteStride;
  749. delete accessor.byteStride;
  750. var hasNextAccessor = (i < accessorsLength - 1);
  751. var nextAccessorByteStride = hasNextAccessor ? computeAccessorByteStride(gltf, accessors[i + 1]) : undefined;
  752. if (accessorByteStride !== nextAccessorByteStride) {
  753. var newBufferView = clone(bufferView, true);
  754. if (bufferViewHasVertexAttributes[bufferViewId]) {
  755. newBufferView.byteStride = accessorByteStride;
  756. }
  757. newBufferView.byteOffset += currentByteOffset;
  758. newBufferView.byteLength = accessorByteOffset + accessorByteLength - currentByteOffset;
  759. var newBufferViewId = addToArray(bufferViews, newBufferView);
  760. for (j = currentIndex; j <= i; ++j) {
  761. accessor = accessors[j];
  762. accessor.bufferView = newBufferViewId;
  763. accessor.byteOffset = accessor.byteOffset - currentByteOffset;
  764. }
  765. // Set current byte offset to next accessor's byte offset
  766. currentByteOffset = hasNextAccessor ? accessors[i + 1].byteOffset : undefined;
  767. currentIndex = i + 1;
  768. }
  769. }
  770. }
  771. }
  772. // Remove unused buffer views
  773. removeUnusedElements(gltf, ['accessor', 'bufferView', 'buffer']);
  774. }
  775. function requirePositionAccessorMinMax(gltf) {
  776. ForEach.accessorWithSemantic(gltf, 'POSITION', function(accessorId) {
  777. var accessor = gltf.accessors[accessorId];
  778. if (!defined(accessor.min) || !defined(accessor.max)) {
  779. var minMax = findAccessorMinMax(gltf, accessor);
  780. accessor.min = minMax.min;
  781. accessor.max = minMax.max;
  782. }
  783. });
  784. }
  785. function isNodeEmpty(node) {
  786. return (!defined(node.children) || node.children.length === 0) &&
  787. (!defined(node.meshes) || node.meshes.length === 0) &&
  788. !defined(node.camera) && !defined(node.skin) && !defined(node.skeletons) && !defined(node.jointName) &&
  789. (!defined(node.translation) || Cartesian3.fromArray(node.translation).equals(Cartesian3.ZERO)) &&
  790. (!defined(node.scale) || Cartesian3.fromArray(node.scale).equals(new Cartesian3(1.0, 1.0, 1.0))) &&
  791. (!defined(node.rotation) || Cartesian4.fromArray(node.rotation).equals(new Cartesian4(0.0, 0.0, 0.0, 1.0))) &&
  792. (!defined(node.matrix) || Matrix4.fromColumnMajorArray(node.matrix).equals(Matrix4.IDENTITY)) &&
  793. !defined(node.extensions) && !defined(node.extras);
  794. }
  795. function deleteNode(gltf, nodeId) {
  796. // Remove from list of nodes in scene
  797. ForEach.scene(gltf, function(scene) {
  798. var sceneNodes = scene.nodes;
  799. if (defined(sceneNodes)) {
  800. var sceneNodesLength = sceneNodes.length;
  801. for (var i = sceneNodesLength; i >= 0; --i) {
  802. if (sceneNodes[i] === nodeId) {
  803. sceneNodes.splice(i, 1);
  804. return;
  805. }
  806. }
  807. }
  808. });
  809. // Remove parent node's reference to this node, and delete the parent if also empty
  810. ForEach.node(gltf, function(parentNode, parentNodeId) {
  811. if (defined(parentNode.children)) {
  812. var index = parentNode.children.indexOf(nodeId);
  813. if (index > -1) {
  814. parentNode.children.splice(index, 1);
  815. if (isNodeEmpty(parentNode)) {
  816. deleteNode(gltf, parentNodeId);
  817. }
  818. }
  819. }
  820. });
  821. delete gltf.nodes[nodeId];
  822. }
  823. function removeEmptyNodes(gltf) {
  824. ForEach.node(gltf, function(node, nodeId) {
  825. if (isNodeEmpty(node)) {
  826. deleteNode(gltf, nodeId);
  827. }
  828. });
  829. return gltf;
  830. }
  831. function requireAnimationAccessorMinMax(gltf) {
  832. ForEach.animation(gltf, function(animation) {
  833. ForEach.animationSampler(animation, function(sampler) {
  834. var accessor = gltf.accessors[sampler.input];
  835. if (!defined(accessor.min) || !defined(accessor.max)) {
  836. var minMax = findAccessorMinMax(gltf, accessor);
  837. accessor.min = minMax.min;
  838. accessor.max = minMax.max;
  839. }
  840. });
  841. });
  842. }
  843. function glTF10to20(gltf) {
  844. gltf.asset = defaultValue(gltf.asset, {});
  845. gltf.asset.version = '2.0';
  846. // material.instanceTechnique properties should be directly on the material. instanceTechnique is a gltf 0.8 property but is seen in some 1.0 models.
  847. updateInstanceTechniques(gltf);
  848. // animation.samplers now refers directly to accessors and animation.parameters should be removed
  849. removeAnimationSamplersIndirection(gltf);
  850. // Remove empty nodes and re-assign referencing indices
  851. removeEmptyNodes(gltf);
  852. // Top-level objects are now arrays referenced by index instead of id
  853. objectsToArrays(gltf);
  854. // Animation.sampler objects cannot have names
  855. removeAnimationSamplerNames(gltf);
  856. // asset.profile no longer exists
  857. stripAsset(gltf);
  858. // Move known extensions from extensionsUsed to extensionsRequired
  859. requireKnownExtensions(gltf);
  860. // bufferView.byteLength and buffer.byteLength are required
  861. requireByteLength(gltf);
  862. // byteStride moved from accessor to bufferView
  863. moveByteStrideToBufferView(gltf);
  864. // accessor.min and accessor.max must be defined for accessors containing POSITION attributes
  865. requirePositionAccessorMinMax(gltf);
  866. // An animation sampler's input accessor must have min and max properties defined
  867. requireAnimationAccessorMinMax(gltf);
  868. // buffer.type is unnecessary and should be removed
  869. removeBufferType(gltf);
  870. // Remove format, internalFormat, target, and type
  871. removeTextureProperties(gltf);
  872. // TEXCOORD and COLOR attributes must be written with a set index (TEXCOORD_#)
  873. requireAttributeSetIndex(gltf);
  874. // Add underscores to application-specific parameters
  875. underscoreApplicationSpecificSemantics(gltf);
  876. // Accessors referenced by JOINTS_0 and WEIGHTS_0 attributes must have correct component types
  877. updateAccessorComponentTypes(gltf);
  878. // Clamp camera parameters
  879. clampCameraParameters(gltf);
  880. // Move legacy technique render states to material properties and add KHR_blend extension blending functions
  881. moveTechniqueRenderStates(gltf);
  882. // Add material techniques to KHR_techniques_webgl extension, removing shaders, programs, and techniques
  883. moveTechniquesToExtension(gltf);
  884. // Remove empty arrays
  885. removeEmptyArrays(gltf);
  886. }
  887. export default updateVersion;