123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741 |
- import ForEach from "./ForEach.js";
- import forEachTextureInMaterial from "./forEachTextureInMaterial.js";
- import usesExtension from "./usesExtension.js";
- import defaultValue from "../../Core/defaultValue.js";
- import defined from "../../Core/defined.js";
- const allElementTypes = [
- "mesh",
- "node",
- "material",
- "accessor",
- "bufferView",
- "buffer",
- "texture",
- "sampler",
- "image",
- ];
- /**
- * Removes unused elements from gltf.
- *
- * @param {Object} gltf A javascript object containing a glTF asset.
- * @param {String[]} [elementTypes=['mesh', 'node', 'material', 'accessor', 'bufferView', 'buffer']] Element types to be removed. Needs to be a subset of ['mesh', 'node', 'material', 'accessor', 'bufferView', 'buffer'], other items will be ignored.
- *
- * @private
- */
- function removeUnusedElements(gltf, elementTypes) {
- elementTypes = defaultValue(elementTypes, allElementTypes);
- allElementTypes.forEach(function (type) {
- if (elementTypes.indexOf(type) > -1) {
- removeUnusedElementsByType(gltf, type);
- }
- });
- return gltf;
- }
- const TypeToGltfElementName = {
- accessor: "accessors",
- buffer: "buffers",
- bufferView: "bufferViews",
- image: "images",
- node: "nodes",
- material: "materials",
- mesh: "meshes",
- sampler: "samplers",
- texture: "textures",
- };
- function removeUnusedElementsByType(gltf, type) {
- const name = TypeToGltfElementName[type];
- const arrayOfObjects = gltf[name];
- if (defined(arrayOfObjects)) {
- let removed = 0;
- const usedIds = getListOfElementsIdsInUse[type](gltf);
- const length = arrayOfObjects.length;
- for (let i = 0; i < length; ++i) {
- if (!usedIds[i]) {
- Remove[type](gltf, i - removed);
- removed++;
- }
- }
- }
- }
- /**
- * Contains functions for removing elements from a glTF hierarchy.
- * Since top-level glTF elements are arrays, when something is removed, referring
- * indices need to be updated.
- * @constructor
- *
- * @private
- */
- function Remove() {}
- Remove.accessor = function (gltf, accessorId) {
- const accessors = gltf.accessors;
- accessors.splice(accessorId, 1);
- ForEach.mesh(gltf, function (mesh) {
- ForEach.meshPrimitive(mesh, function (primitive) {
- // Update accessor ids for the primitives.
- ForEach.meshPrimitiveAttribute(
- primitive,
- function (attributeAccessorId, semantic) {
- if (attributeAccessorId > accessorId) {
- primitive.attributes[semantic]--;
- }
- }
- );
- // Update accessor ids for the targets.
- ForEach.meshPrimitiveTarget(primitive, function (target) {
- ForEach.meshPrimitiveTargetAttribute(
- target,
- function (attributeAccessorId, semantic) {
- if (attributeAccessorId > accessorId) {
- target[semantic]--;
- }
- }
- );
- });
- const indices = primitive.indices;
- if (defined(indices) && indices > accessorId) {
- primitive.indices--;
- }
- });
- });
- ForEach.skin(gltf, function (skin) {
- if (
- defined(skin.inverseBindMatrices) &&
- skin.inverseBindMatrices > accessorId
- ) {
- skin.inverseBindMatrices--;
- }
- });
- ForEach.animation(gltf, function (animation) {
- ForEach.animationSampler(animation, function (sampler) {
- if (defined(sampler.input) && sampler.input > accessorId) {
- sampler.input--;
- }
- if (defined(sampler.output) && sampler.output > accessorId) {
- sampler.output--;
- }
- });
- });
- };
- Remove.buffer = function (gltf, bufferId) {
- const buffers = gltf.buffers;
- buffers.splice(bufferId, 1);
- ForEach.bufferView(gltf, function (bufferView) {
- if (defined(bufferView.buffer) && bufferView.buffer > bufferId) {
- bufferView.buffer--;
- }
- if (
- defined(bufferView.extensions) &&
- defined(bufferView.extensions.EXT_meshopt_compression)
- ) {
- bufferView.extensions.EXT_meshopt_compression.buffer--;
- }
- });
- };
- Remove.bufferView = function (gltf, bufferViewId) {
- const bufferViews = gltf.bufferViews;
- bufferViews.splice(bufferViewId, 1);
- ForEach.accessor(gltf, function (accessor) {
- if (defined(accessor.bufferView) && accessor.bufferView > bufferViewId) {
- accessor.bufferView--;
- }
- });
- ForEach.shader(gltf, function (shader) {
- if (defined(shader.bufferView) && shader.bufferView > bufferViewId) {
- shader.bufferView--;
- }
- });
- ForEach.image(gltf, function (image) {
- if (defined(image.bufferView) && image.bufferView > bufferViewId) {
- image.bufferView--;
- }
- });
- if (usesExtension(gltf, "KHR_draco_mesh_compression")) {
- ForEach.mesh(gltf, function (mesh) {
- ForEach.meshPrimitive(mesh, function (primitive) {
- if (
- defined(primitive.extensions) &&
- defined(primitive.extensions.KHR_draco_mesh_compression)
- ) {
- if (
- primitive.extensions.KHR_draco_mesh_compression.bufferView >
- bufferViewId
- ) {
- primitive.extensions.KHR_draco_mesh_compression.bufferView--;
- }
- }
- });
- });
- }
- if (usesExtension(gltf, "EXT_feature_metadata")) {
- const extension = gltf.extensions.EXT_feature_metadata;
- const featureTables = extension.featureTables;
- for (const featureTableId in featureTables) {
- if (featureTables.hasOwnProperty(featureTableId)) {
- const featureTable = featureTables[featureTableId];
- const properties = featureTable.properties;
- if (defined(properties)) {
- for (const propertyId in properties) {
- if (properties.hasOwnProperty(propertyId)) {
- const property = properties[propertyId];
- if (
- defined(property.bufferView) &&
- property.bufferView > bufferViewId
- ) {
- property.bufferView--;
- }
- if (
- defined(property.arrayOffsetBufferView) &&
- property.arrayOffsetBufferView > bufferViewId
- ) {
- property.arrayOffsetBufferView--;
- }
- if (
- defined(property.stringOffsetBufferView) &&
- property.stringOffsetBufferView > bufferViewId
- ) {
- property.stringOffsetBufferView--;
- }
- }
- }
- }
- }
- }
- }
- };
- Remove.image = function (gltf, imageId) {
- const images = gltf.images;
- images.splice(imageId, 1);
- ForEach.texture(gltf, function (texture) {
- if (defined(texture.source)) {
- if (texture.source > imageId) {
- --texture.source;
- }
- }
- const ext = texture.extensions;
- if (
- defined(ext) &&
- defined(ext.EXT_texture_webp) &&
- ext.EXT_texture_webp.source > imageId
- ) {
- --texture.extensions.EXT_texture_webp.source;
- } else if (
- defined(ext) &&
- defined(ext.KHR_texture_basisu) &&
- ext.KHR_texture_basisu.source > imageId
- ) {
- --texture.extensions.KHR_texture_basisu.source;
- }
- });
- };
- Remove.mesh = function (gltf, meshId) {
- const meshes = gltf.meshes;
- meshes.splice(meshId, 1);
- ForEach.node(gltf, function (node) {
- if (defined(node.mesh)) {
- if (node.mesh > meshId) {
- node.mesh--;
- } else if (node.mesh === meshId) {
- // Remove reference to deleted mesh
- delete node.mesh;
- }
- }
- });
- };
- Remove.node = function (gltf, nodeId) {
- const nodes = gltf.nodes;
- nodes.splice(nodeId, 1);
- // Shift all node references
- ForEach.skin(gltf, function (skin) {
- if (defined(skin.skeleton) && skin.skeleton > nodeId) {
- skin.skeleton--;
- }
- skin.joints = skin.joints.map(function (x) {
- return x > nodeId ? x - 1 : x;
- });
- });
- ForEach.animation(gltf, function (animation) {
- ForEach.animationChannel(animation, function (channel) {
- if (
- defined(channel.target) &&
- defined(channel.target.node) &&
- channel.target.node > nodeId
- ) {
- channel.target.node--;
- }
- });
- });
- ForEach.technique(gltf, function (technique) {
- ForEach.techniqueUniform(technique, function (uniform) {
- if (defined(uniform.node) && uniform.node > nodeId) {
- uniform.node--;
- }
- });
- });
- ForEach.node(gltf, function (node) {
- if (!defined(node.children)) {
- return;
- }
- node.children = node.children
- .filter(function (x) {
- return x !== nodeId; // Remove
- })
- .map(function (x) {
- return x > nodeId ? x - 1 : x; // Shift indices
- });
- });
- ForEach.scene(gltf, function (scene) {
- scene.nodes = scene.nodes
- .filter(function (x) {
- return x !== nodeId; // Remove
- })
- .map(function (x) {
- return x > nodeId ? x - 1 : x; // Shift indices
- });
- });
- };
- Remove.material = function (gltf, materialId) {
- const materials = gltf.materials;
- materials.splice(materialId, 1);
- // Shift other material ids
- ForEach.mesh(gltf, function (mesh) {
- ForEach.meshPrimitive(mesh, function (primitive) {
- if (defined(primitive.material) && primitive.material > materialId) {
- primitive.material--;
- }
- });
- });
- };
- Remove.sampler = function (gltf, samplerId) {
- const samplers = gltf.samplers;
- samplers.splice(samplerId, 1);
- ForEach.texture(gltf, function (texture) {
- if (defined(texture.sampler)) {
- if (texture.sampler > samplerId) {
- --texture.sampler;
- }
- }
- });
- };
- Remove.texture = function (gltf, textureId) {
- const textures = gltf.textures;
- textures.splice(textureId, 1);
- ForEach.material(gltf, function (material) {
- forEachTextureInMaterial(material, function (textureIndex, textureInfo) {
- if (textureInfo.index > textureId) {
- --textureInfo.index;
- }
- });
- });
- if (usesExtension(gltf, "EXT_feature_metadata")) {
- ForEach.mesh(gltf, function (mesh) {
- ForEach.meshPrimitive(mesh, function (primitive) {
- const extensions = primitive.extensions;
- if (defined(extensions) && defined(extensions.EXT_feature_metadata)) {
- const extension = extensions.EXT_feature_metadata;
- const featureIdTextures = extension.featureIdTextures;
- if (defined(featureIdTextures)) {
- const featureIdTexturesLength = featureIdTextures.length;
- for (let i = 0; i < featureIdTexturesLength; ++i) {
- const featureIdTexture = featureIdTextures[i];
- const textureInfo = featureIdTexture.featureIds.texture;
- if (textureInfo.index > textureId) {
- --textureInfo.index;
- }
- }
- }
- }
- });
- });
- const extension = gltf.extensions.EXT_feature_metadata;
- const featureTextures = extension.featureTextures;
- for (const featureTextureId in featureTextures) {
- if (featureTextures.hasOwnProperty(featureTextureId)) {
- const featureTexture = featureTextures[featureTextureId];
- const properties = featureTexture.properties;
- if (defined(properties)) {
- for (const propertyId in properties) {
- if (properties.hasOwnProperty(propertyId)) {
- const property = properties[propertyId];
- const textureInfo = property.texture;
- if (textureInfo.index > textureId) {
- --textureInfo.index;
- }
- }
- }
- }
- }
- }
- }
- };
- /**
- * Contains functions for getting a list of element ids in use by the glTF asset.
- * @constructor
- *
- * @private
- */
- function getListOfElementsIdsInUse() {}
- getListOfElementsIdsInUse.accessor = function (gltf) {
- // Calculate accessor's that are currently in use.
- const usedAccessorIds = {};
- ForEach.mesh(gltf, function (mesh) {
- ForEach.meshPrimitive(mesh, function (primitive) {
- ForEach.meshPrimitiveAttribute(primitive, function (accessorId) {
- usedAccessorIds[accessorId] = true;
- });
- ForEach.meshPrimitiveTarget(primitive, function (target) {
- ForEach.meshPrimitiveTargetAttribute(target, function (accessorId) {
- usedAccessorIds[accessorId] = true;
- });
- });
- const indices = primitive.indices;
- if (defined(indices)) {
- usedAccessorIds[indices] = true;
- }
- });
- });
- ForEach.skin(gltf, function (skin) {
- if (defined(skin.inverseBindMatrices)) {
- usedAccessorIds[skin.inverseBindMatrices] = true;
- }
- });
- ForEach.animation(gltf, function (animation) {
- ForEach.animationSampler(animation, function (sampler) {
- if (defined(sampler.input)) {
- usedAccessorIds[sampler.input] = true;
- }
- if (defined(sampler.output)) {
- usedAccessorIds[sampler.output] = true;
- }
- });
- });
- if (usesExtension(gltf, "EXT_mesh_gpu_instancing")) {
- ForEach.node(gltf, function (node) {
- if (
- defined(node.extensions) &&
- defined(node.extensions.EXT_mesh_gpu_instancing)
- ) {
- Object.keys(node.extensions.EXT_mesh_gpu_instancing.attributes).forEach(
- function (key) {
- const attributeAccessorId =
- node.extensions.EXT_mesh_gpu_instancing.attributes[key];
- usedAccessorIds[attributeAccessorId] = true;
- }
- );
- }
- });
- }
- return usedAccessorIds;
- };
- getListOfElementsIdsInUse.buffer = function (gltf) {
- // Calculate buffer's that are currently in use.
- const usedBufferIds = {};
- ForEach.bufferView(gltf, function (bufferView) {
- if (defined(bufferView.buffer)) {
- usedBufferIds[bufferView.buffer] = true;
- }
- if (
- defined(bufferView.extensions) &&
- defined(bufferView.extensions.EXT_meshopt_compression)
- ) {
- usedBufferIds[
- bufferView.extensions.EXT_meshopt_compression.buffer
- ] = true;
- }
- });
- return usedBufferIds;
- };
- getListOfElementsIdsInUse.bufferView = function (gltf) {
- // Calculate bufferView's that are currently in use.
- const usedBufferViewIds = {};
- ForEach.accessor(gltf, function (accessor) {
- if (defined(accessor.bufferView)) {
- usedBufferViewIds[accessor.bufferView] = true;
- }
- });
- ForEach.shader(gltf, function (shader) {
- if (defined(shader.bufferView)) {
- usedBufferViewIds[shader.bufferView] = true;
- }
- });
- ForEach.image(gltf, function (image) {
- if (defined(image.bufferView)) {
- usedBufferViewIds[image.bufferView] = true;
- }
- });
- if (usesExtension(gltf, "KHR_draco_mesh_compression")) {
- ForEach.mesh(gltf, function (mesh) {
- ForEach.meshPrimitive(mesh, function (primitive) {
- if (
- defined(primitive.extensions) &&
- defined(primitive.extensions.KHR_draco_mesh_compression)
- ) {
- usedBufferViewIds[
- primitive.extensions.KHR_draco_mesh_compression.bufferView
- ] = true;
- }
- });
- });
- }
- if (usesExtension(gltf, "EXT_feature_metadata")) {
- const extension = gltf.extensions.EXT_feature_metadata;
- const featureTables = extension.featureTables;
- for (const featureTableId in featureTables) {
- if (featureTables.hasOwnProperty(featureTableId)) {
- const featureTable = featureTables[featureTableId];
- const properties = featureTable.properties;
- if (defined(properties)) {
- for (const propertyId in properties) {
- if (properties.hasOwnProperty(propertyId)) {
- const property = properties[propertyId];
- if (defined(property.bufferView)) {
- usedBufferViewIds[property.bufferView] = true;
- }
- if (defined(property.arrayOffsetBufferView)) {
- usedBufferViewIds[property.arrayOffsetBufferView] = true;
- }
- if (defined(property.stringOffsetBufferView)) {
- usedBufferViewIds[property.stringOffsetBufferView] = true;
- }
- }
- }
- }
- }
- }
- }
- return usedBufferViewIds;
- };
- getListOfElementsIdsInUse.image = function (gltf) {
- const usedImageIds = {};
- ForEach.texture(gltf, function (texture) {
- if (defined(texture.source)) {
- usedImageIds[texture.source] = true;
- }
- if (
- defined(texture.extensions) &&
- defined(texture.extensions.EXT_texture_webp)
- ) {
- usedImageIds[texture.extensions.EXT_texture_webp.source] = true;
- } else if (
- defined(texture.extensions) &&
- defined(texture.extensions.KHR_texture_basisu)
- ) {
- usedImageIds[texture.extensions.KHR_texture_basisu.source] = true;
- }
- });
- return usedImageIds;
- };
- getListOfElementsIdsInUse.mesh = function (gltf) {
- const usedMeshIds = {};
- ForEach.node(gltf, function (node) {
- if (defined(node.mesh && defined(gltf.meshes))) {
- const mesh = gltf.meshes[node.mesh];
- if (
- defined(mesh) &&
- defined(mesh.primitives) &&
- mesh.primitives.length > 0
- ) {
- usedMeshIds[node.mesh] = true;
- }
- }
- });
- return usedMeshIds;
- };
- // Check if node is empty. It is considered empty if neither referencing
- // mesh, camera, extensions and has no children
- function nodeIsEmpty(gltf, nodeId, usedNodeIds) {
- const node = gltf.nodes[nodeId];
- if (
- defined(node.mesh) ||
- defined(node.camera) ||
- defined(node.skin) ||
- defined(node.weights) ||
- defined(node.extras) ||
- (defined(node.extensions) && Object.keys(node.extensions).length !== 0) ||
- defined(usedNodeIds[nodeId])
- ) {
- return false;
- }
- // Empty if no children or children are all empty nodes
- return (
- !defined(node.children) ||
- node.children.filter(function (n) {
- return !nodeIsEmpty(gltf, n, usedNodeIds);
- }).length === 0
- );
- }
- getListOfElementsIdsInUse.node = function (gltf) {
- const usedNodeIds = {};
- ForEach.skin(gltf, function (skin) {
- if (defined(skin.skeleton)) {
- usedNodeIds[skin.skeleton] = true;
- }
- ForEach.skinJoint(skin, function (joint) {
- usedNodeIds[joint] = true;
- });
- });
- ForEach.animation(gltf, function (animation) {
- ForEach.animationChannel(animation, function (channel) {
- if (defined(channel.target) && defined(channel.target.node)) {
- usedNodeIds[channel.target.node] = true;
- }
- });
- });
- ForEach.technique(gltf, function (technique) {
- ForEach.techniqueUniform(technique, function (uniform) {
- if (defined(uniform.node)) {
- usedNodeIds[uniform.node] = true;
- }
- });
- });
- ForEach.node(gltf, function (node, nodeId) {
- if (!nodeIsEmpty(gltf, nodeId, usedNodeIds)) {
- usedNodeIds[nodeId] = true;
- }
- });
- return usedNodeIds;
- };
- getListOfElementsIdsInUse.material = function (gltf) {
- const usedMaterialIds = {};
- ForEach.mesh(gltf, function (mesh) {
- ForEach.meshPrimitive(mesh, function (primitive) {
- if (defined(primitive.material)) {
- usedMaterialIds[primitive.material] = true;
- }
- });
- });
- return usedMaterialIds;
- };
- getListOfElementsIdsInUse.texture = function (gltf) {
- const usedTextureIds = {};
- ForEach.material(gltf, function (material) {
- forEachTextureInMaterial(material, function (textureId) {
- usedTextureIds[textureId] = true;
- });
- });
- if (usesExtension(gltf, "EXT_feature_metadata")) {
- ForEach.mesh(gltf, function (mesh) {
- ForEach.meshPrimitive(mesh, function (primitive) {
- const extensions = primitive.extensions;
- if (defined(extensions) && defined(extensions.EXT_feature_metadata)) {
- const extension = extensions.EXT_feature_metadata;
- const featureIdTextures = extension.featureIdTextures;
- if (defined(featureIdTextures)) {
- const featureIdTexturesLength = featureIdTextures.length;
- for (let i = 0; i < featureIdTexturesLength; ++i) {
- const featureIdTexture = featureIdTextures[i];
- const textureInfo = featureIdTexture.featureIds.texture;
- usedTextureIds[textureInfo.index] = true;
- }
- }
- }
- });
- });
- const extension = gltf.extensions.EXT_feature_metadata;
- const featureTextures = extension.featureTextures;
- for (const featureTextureId in featureTextures) {
- if (featureTextures.hasOwnProperty(featureTextureId)) {
- const featureTexture = featureTextures[featureTextureId];
- const properties = featureTexture.properties;
- if (defined(properties)) {
- for (const propertyId in properties) {
- if (properties.hasOwnProperty(propertyId)) {
- const property = properties[propertyId];
- const textureInfo = property.texture;
- usedTextureIds[textureInfo.index] = true;
- }
- }
- }
- }
- }
- }
- return usedTextureIds;
- };
- getListOfElementsIdsInUse.sampler = function (gltf) {
- const usedSamplerIds = {};
- ForEach.texture(gltf, function (texture) {
- if (defined(texture.sampler)) {
- usedSamplerIds[texture.sampler] = true;
- }
- });
- return usedSamplerIds;
- };
- export default removeUnusedElements;
|