Add existing to tracked
This commit is contained in:
+424
@@ -0,0 +1,424 @@
|
||||
import usesExtension from "./usesExtension.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
|
||||
/**
|
||||
* Contains traversal functions for processing elements of the glTF hierarchy.
|
||||
* @constructor
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function ForEach() {}
|
||||
|
||||
/**
|
||||
* Fallback for glTF 1.0
|
||||
* @private
|
||||
*/
|
||||
ForEach.objectLegacy = function (objects, handler) {
|
||||
if (defined(objects)) {
|
||||
for (const objectId in objects) {
|
||||
if (Object.prototype.hasOwnProperty.call(objects, objectId)) {
|
||||
const object = objects[objectId];
|
||||
const value = handler(object, objectId);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ForEach.object = function (arrayOfObjects, handler) {
|
||||
if (defined(arrayOfObjects)) {
|
||||
const length = arrayOfObjects.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const object = arrayOfObjects[i];
|
||||
const value = handler(object, i);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Supports glTF 1.0 and 2.0
|
||||
* @private
|
||||
*/
|
||||
ForEach.topLevel = function (gltf, name, handler) {
|
||||
const gltfProperty = gltf[name];
|
||||
if (defined(gltfProperty) && !Array.isArray(gltfProperty)) {
|
||||
return ForEach.objectLegacy(gltfProperty, handler);
|
||||
}
|
||||
|
||||
return ForEach.object(gltfProperty, handler);
|
||||
};
|
||||
|
||||
ForEach.accessor = function (gltf, handler) {
|
||||
return ForEach.topLevel(gltf, "accessors", handler);
|
||||
};
|
||||
|
||||
ForEach.accessorWithSemantic = function (gltf, semantic, handler) {
|
||||
const visited = {};
|
||||
return ForEach.mesh(gltf, function (mesh) {
|
||||
return ForEach.meshPrimitive(mesh, function (primitive) {
|
||||
const valueForEach = ForEach.meshPrimitiveAttribute(
|
||||
primitive,
|
||||
function (accessorId, attributeSemantic) {
|
||||
if (
|
||||
attributeSemantic.indexOf(semantic) === 0 &&
|
||||
!defined(visited[accessorId])
|
||||
) {
|
||||
visited[accessorId] = true;
|
||||
const value = handler(accessorId);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (defined(valueForEach)) {
|
||||
return valueForEach;
|
||||
}
|
||||
|
||||
return ForEach.meshPrimitiveTarget(primitive, function (target) {
|
||||
return ForEach.meshPrimitiveTargetAttribute(
|
||||
target,
|
||||
function (accessorId, attributeSemantic) {
|
||||
if (
|
||||
attributeSemantic.indexOf(semantic) === 0 &&
|
||||
!defined(visited[accessorId])
|
||||
) {
|
||||
visited[accessorId] = true;
|
||||
const value = handler(accessorId);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
ForEach.accessorContainingVertexAttributeData = function (gltf, handler) {
|
||||
const visited = {};
|
||||
return ForEach.mesh(gltf, function (mesh) {
|
||||
return ForEach.meshPrimitive(mesh, function (primitive) {
|
||||
const valueForEach = ForEach.meshPrimitiveAttribute(
|
||||
primitive,
|
||||
function (accessorId) {
|
||||
if (!defined(visited[accessorId])) {
|
||||
visited[accessorId] = true;
|
||||
const value = handler(accessorId);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (defined(valueForEach)) {
|
||||
return valueForEach;
|
||||
}
|
||||
|
||||
return ForEach.meshPrimitiveTarget(primitive, function (target) {
|
||||
return ForEach.meshPrimitiveTargetAttribute(
|
||||
target,
|
||||
function (accessorId) {
|
||||
if (!defined(visited[accessorId])) {
|
||||
visited[accessorId] = true;
|
||||
const value = handler(accessorId);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
ForEach.accessorContainingIndexData = function (gltf, handler) {
|
||||
const visited = {};
|
||||
return ForEach.mesh(gltf, function (mesh) {
|
||||
return ForEach.meshPrimitive(mesh, function (primitive) {
|
||||
const indices = primitive.indices;
|
||||
if (defined(indices) && !defined(visited[indices])) {
|
||||
visited[indices] = true;
|
||||
const value = handler(indices);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
ForEach.animation = function (gltf, handler) {
|
||||
return ForEach.topLevel(gltf, "animations", handler);
|
||||
};
|
||||
|
||||
ForEach.animationChannel = function (animation, handler) {
|
||||
const channels = animation.channels;
|
||||
return ForEach.object(channels, handler);
|
||||
};
|
||||
|
||||
ForEach.animationSampler = function (animation, handler) {
|
||||
const samplers = animation.samplers;
|
||||
return ForEach.object(samplers, handler);
|
||||
};
|
||||
|
||||
ForEach.buffer = function (gltf, handler) {
|
||||
return ForEach.topLevel(gltf, "buffers", handler);
|
||||
};
|
||||
|
||||
ForEach.bufferView = function (gltf, handler) {
|
||||
return ForEach.topLevel(gltf, "bufferViews", handler);
|
||||
};
|
||||
|
||||
ForEach.camera = function (gltf, handler) {
|
||||
return ForEach.topLevel(gltf, "cameras", handler);
|
||||
};
|
||||
|
||||
ForEach.image = function (gltf, handler) {
|
||||
return ForEach.topLevel(gltf, "images", handler);
|
||||
};
|
||||
|
||||
ForEach.material = function (gltf, handler) {
|
||||
return ForEach.topLevel(gltf, "materials", handler);
|
||||
};
|
||||
|
||||
ForEach.materialValue = function (material, handler) {
|
||||
let values = material.values;
|
||||
if (
|
||||
defined(material.extensions) &&
|
||||
defined(material.extensions.KHR_techniques_webgl)
|
||||
) {
|
||||
values = material.extensions.KHR_techniques_webgl.values;
|
||||
}
|
||||
|
||||
for (const name in values) {
|
||||
if (Object.prototype.hasOwnProperty.call(values, name)) {
|
||||
const value = handler(values[name], name);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ForEach.mesh = function (gltf, handler) {
|
||||
return ForEach.topLevel(gltf, "meshes", handler);
|
||||
};
|
||||
|
||||
ForEach.meshPrimitive = function (mesh, handler) {
|
||||
const primitives = mesh.primitives;
|
||||
if (defined(primitives)) {
|
||||
const primitivesLength = primitives.length;
|
||||
for (let i = 0; i < primitivesLength; i++) {
|
||||
const primitive = primitives[i];
|
||||
const value = handler(primitive, i);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ForEach.meshPrimitiveAttribute = function (primitive, handler) {
|
||||
const attributes = primitive.attributes;
|
||||
for (const semantic in attributes) {
|
||||
if (Object.prototype.hasOwnProperty.call(attributes, semantic)) {
|
||||
const value = handler(attributes[semantic], semantic);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ForEach.meshPrimitiveTarget = function (primitive, handler) {
|
||||
const targets = primitive.targets;
|
||||
if (defined(targets)) {
|
||||
const length = targets.length;
|
||||
for (let i = 0; i < length; ++i) {
|
||||
const value = handler(targets[i], i);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ForEach.meshPrimitiveTargetAttribute = function (target, handler) {
|
||||
for (const semantic in target) {
|
||||
if (Object.prototype.hasOwnProperty.call(target, semantic)) {
|
||||
const accessorId = target[semantic];
|
||||
const value = handler(accessorId, semantic);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ForEach.node = function (gltf, handler) {
|
||||
return ForEach.topLevel(gltf, "nodes", handler);
|
||||
};
|
||||
|
||||
ForEach.nodeInTree = function (gltf, nodeIds, handler) {
|
||||
const nodes = gltf.nodes;
|
||||
if (defined(nodes)) {
|
||||
const length = nodeIds.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const nodeId = nodeIds[i];
|
||||
const node = nodes[nodeId];
|
||||
if (defined(node)) {
|
||||
let value = handler(node, nodeId);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const children = node.children;
|
||||
if (defined(children)) {
|
||||
value = ForEach.nodeInTree(gltf, children, handler);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ForEach.nodeInScene = function (gltf, scene, handler) {
|
||||
const sceneNodeIds = scene.nodes;
|
||||
if (defined(sceneNodeIds)) {
|
||||
return ForEach.nodeInTree(gltf, sceneNodeIds, handler);
|
||||
}
|
||||
};
|
||||
|
||||
ForEach.program = function (gltf, handler) {
|
||||
if (usesExtension(gltf, "KHR_techniques_webgl")) {
|
||||
return ForEach.object(
|
||||
gltf.extensions.KHR_techniques_webgl.programs,
|
||||
handler,
|
||||
);
|
||||
}
|
||||
|
||||
return ForEach.topLevel(gltf, "programs", handler);
|
||||
};
|
||||
|
||||
ForEach.sampler = function (gltf, handler) {
|
||||
return ForEach.topLevel(gltf, "samplers", handler);
|
||||
};
|
||||
|
||||
ForEach.scene = function (gltf, handler) {
|
||||
return ForEach.topLevel(gltf, "scenes", handler);
|
||||
};
|
||||
|
||||
ForEach.shader = function (gltf, handler) {
|
||||
if (usesExtension(gltf, "KHR_techniques_webgl")) {
|
||||
return ForEach.object(
|
||||
gltf.extensions.KHR_techniques_webgl.shaders,
|
||||
handler,
|
||||
);
|
||||
}
|
||||
|
||||
return ForEach.topLevel(gltf, "shaders", handler);
|
||||
};
|
||||
|
||||
ForEach.skin = function (gltf, handler) {
|
||||
return ForEach.topLevel(gltf, "skins", handler);
|
||||
};
|
||||
|
||||
ForEach.skinJoint = function (skin, handler) {
|
||||
const joints = skin.joints;
|
||||
if (defined(joints)) {
|
||||
const jointsLength = joints.length;
|
||||
for (let i = 0; i < jointsLength; i++) {
|
||||
const joint = joints[i];
|
||||
const value = handler(joint);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ForEach.techniqueAttribute = function (technique, handler) {
|
||||
const attributes = technique.attributes;
|
||||
for (const attributeName in attributes) {
|
||||
if (Object.prototype.hasOwnProperty.call(attributes, attributeName)) {
|
||||
const value = handler(attributes[attributeName], attributeName);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ForEach.techniqueUniform = function (technique, handler) {
|
||||
const uniforms = technique.uniforms;
|
||||
for (const uniformName in uniforms) {
|
||||
if (Object.prototype.hasOwnProperty.call(uniforms, uniformName)) {
|
||||
const value = handler(uniforms[uniformName], uniformName);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ForEach.techniqueParameter = function (technique, handler) {
|
||||
const parameters = technique.parameters;
|
||||
for (const parameterName in parameters) {
|
||||
if (Object.prototype.hasOwnProperty.call(parameters, parameterName)) {
|
||||
const value = handler(parameters[parameterName], parameterName);
|
||||
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ForEach.technique = function (gltf, handler) {
|
||||
if (usesExtension(gltf, "KHR_techniques_webgl")) {
|
||||
return ForEach.object(
|
||||
gltf.extensions.KHR_techniques_webgl.techniques,
|
||||
handler,
|
||||
);
|
||||
}
|
||||
|
||||
return ForEach.topLevel(gltf, "techniques", handler);
|
||||
};
|
||||
|
||||
ForEach.texture = function (gltf, handler) {
|
||||
return ForEach.topLevel(gltf, "textures", handler);
|
||||
};
|
||||
|
||||
export default ForEach;
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
import addToArray from "./addToArray.js";
|
||||
|
||||
/**
|
||||
* Adds buffer to gltf.
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @param {Buffer} buffer A Buffer object which will be added to gltf.buffers.
|
||||
* @returns {number} The bufferView id of the newly added bufferView.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function addBuffer(gltf, buffer) {
|
||||
const newBuffer = {
|
||||
byteLength: buffer.length,
|
||||
extras: {
|
||||
_pipeline: {
|
||||
source: buffer,
|
||||
},
|
||||
},
|
||||
};
|
||||
const bufferId = addToArray(gltf.buffers, newBuffer);
|
||||
const bufferView = {
|
||||
buffer: bufferId,
|
||||
byteOffset: 0,
|
||||
byteLength: buffer.length,
|
||||
};
|
||||
return addToArray(gltf.bufferViews, bufferView);
|
||||
}
|
||||
|
||||
export default addBuffer;
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
import addToArray from "./addToArray.js";
|
||||
import ForEach from "./ForEach.js";
|
||||
import getAccessorByteStride from "./getAccessorByteStride.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
import WebGLConstants from "../../Core/WebGLConstants.js";
|
||||
|
||||
/**
|
||||
* Adds default glTF values if they don't exist.
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @returns {object} The modified glTF.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function addDefaults(gltf) {
|
||||
ForEach.accessor(gltf, function (accessor) {
|
||||
if (defined(accessor.bufferView)) {
|
||||
accessor.byteOffset = accessor.byteOffset ?? 0;
|
||||
}
|
||||
});
|
||||
|
||||
ForEach.bufferView(gltf, function (bufferView) {
|
||||
if (defined(bufferView.buffer)) {
|
||||
bufferView.byteOffset = bufferView.byteOffset ?? 0;
|
||||
}
|
||||
});
|
||||
|
||||
ForEach.mesh(gltf, function (mesh) {
|
||||
ForEach.meshPrimitive(mesh, function (primitive) {
|
||||
primitive.mode = primitive.mode ?? WebGLConstants.TRIANGLES;
|
||||
if (!defined(primitive.material)) {
|
||||
if (!defined(gltf.materials)) {
|
||||
gltf.materials = [];
|
||||
}
|
||||
const defaultMaterial = {
|
||||
name: "default",
|
||||
};
|
||||
primitive.material = addToArray(gltf.materials, defaultMaterial);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ForEach.accessorContainingVertexAttributeData(gltf, function (accessorId) {
|
||||
const accessor = gltf.accessors[accessorId];
|
||||
const bufferViewId = accessor.bufferView;
|
||||
accessor.normalized = accessor.normalized ?? false;
|
||||
if (defined(bufferViewId)) {
|
||||
const bufferView = gltf.bufferViews[bufferViewId];
|
||||
bufferView.byteStride = getAccessorByteStride(gltf, accessor);
|
||||
bufferView.target = WebGLConstants.ARRAY_BUFFER;
|
||||
}
|
||||
});
|
||||
|
||||
ForEach.accessorContainingIndexData(gltf, function (accessorId) {
|
||||
const accessor = gltf.accessors[accessorId];
|
||||
const bufferViewId = accessor.bufferView;
|
||||
if (defined(bufferViewId)) {
|
||||
const bufferView = gltf.bufferViews[bufferViewId];
|
||||
bufferView.target = WebGLConstants.ELEMENT_ARRAY_BUFFER;
|
||||
}
|
||||
});
|
||||
|
||||
ForEach.material(gltf, function (material) {
|
||||
const extensions = material.extensions ?? {};
|
||||
const materialsCommon = extensions.KHR_materials_common;
|
||||
if (defined(materialsCommon)) {
|
||||
const technique = materialsCommon.technique;
|
||||
const values = defined(materialsCommon.values)
|
||||
? materialsCommon.values
|
||||
: {};
|
||||
materialsCommon.values = values;
|
||||
|
||||
values.ambient = defined(values.ambient)
|
||||
? values.ambient
|
||||
: [0.0, 0.0, 0.0, 1.0];
|
||||
values.emission = defined(values.emission)
|
||||
? values.emission
|
||||
: [0.0, 0.0, 0.0, 1.0];
|
||||
|
||||
values.transparency = values.transparency ?? 1.0;
|
||||
|
||||
if (technique !== "CONSTANT") {
|
||||
values.diffuse = defined(values.diffuse)
|
||||
? values.diffuse
|
||||
: [0.0, 0.0, 0.0, 1.0];
|
||||
if (technique !== "LAMBERT") {
|
||||
values.specular = defined(values.specular)
|
||||
? values.specular
|
||||
: [0.0, 0.0, 0.0, 1.0];
|
||||
values.shininess = values.shininess ?? 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// These actually exist on the extension object, not the values object despite what's shown in the spec
|
||||
materialsCommon.transparent = materialsCommon.transparent ?? false;
|
||||
materialsCommon.doubleSided = materialsCommon.doubleSided ?? false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
material.emissiveFactor = material.emissiveFactor ?? [0.0, 0.0, 0.0];
|
||||
material.alphaMode = material.alphaMode ?? "OPAQUE";
|
||||
material.doubleSided = material.doubleSided ?? false;
|
||||
|
||||
if (material.alphaMode === "MASK") {
|
||||
material.alphaCutoff = material.alphaCutoff ?? 0.5;
|
||||
}
|
||||
|
||||
const techniquesExtension = extensions.KHR_techniques_webgl;
|
||||
if (defined(techniquesExtension)) {
|
||||
ForEach.materialValue(material, function (materialValue) {
|
||||
// Check if material value is a TextureInfo object
|
||||
if (defined(materialValue.index)) {
|
||||
addTextureDefaults(materialValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addTextureDefaults(material.emissiveTexture);
|
||||
addTextureDefaults(material.normalTexture);
|
||||
addTextureDefaults(material.occlusionTexture);
|
||||
|
||||
const pbrMetallicRoughness = material.pbrMetallicRoughness;
|
||||
if (defined(pbrMetallicRoughness)) {
|
||||
pbrMetallicRoughness.baseColorFactor =
|
||||
pbrMetallicRoughness.baseColorFactor ?? [1.0, 1.0, 1.0, 1.0];
|
||||
pbrMetallicRoughness.metallicFactor =
|
||||
pbrMetallicRoughness.metallicFactor ?? 1.0;
|
||||
pbrMetallicRoughness.roughnessFactor =
|
||||
pbrMetallicRoughness.roughnessFactor ?? 1.0;
|
||||
addTextureDefaults(pbrMetallicRoughness.baseColorTexture);
|
||||
addTextureDefaults(pbrMetallicRoughness.metallicRoughnessTexture);
|
||||
}
|
||||
|
||||
const pbrSpecularGlossiness =
|
||||
extensions.KHR_materials_pbrSpecularGlossiness;
|
||||
if (defined(pbrSpecularGlossiness)) {
|
||||
pbrSpecularGlossiness.diffuseFactor =
|
||||
pbrSpecularGlossiness.diffuseFactor ?? [1.0, 1.0, 1.0, 1.0];
|
||||
pbrSpecularGlossiness.specularFactor =
|
||||
pbrSpecularGlossiness.specularFactor ?? [1.0, 1.0, 1.0];
|
||||
pbrSpecularGlossiness.glossinessFactor =
|
||||
pbrSpecularGlossiness.glossinessFactor ?? 1.0;
|
||||
addTextureDefaults(pbrSpecularGlossiness.specularGlossinessTexture);
|
||||
}
|
||||
});
|
||||
|
||||
ForEach.animation(gltf, function (animation) {
|
||||
ForEach.animationSampler(animation, function (sampler) {
|
||||
sampler.interpolation = sampler.interpolation ?? "LINEAR";
|
||||
});
|
||||
});
|
||||
|
||||
const animatedNodes = getAnimatedNodes(gltf);
|
||||
ForEach.node(gltf, function (node, id) {
|
||||
const animated = defined(animatedNodes[id]);
|
||||
if (
|
||||
animated ||
|
||||
defined(node.translation) ||
|
||||
defined(node.rotation) ||
|
||||
defined(node.scale)
|
||||
) {
|
||||
node.translation = node.translation ?? [0.0, 0.0, 0.0];
|
||||
node.rotation = node.rotation ?? [0.0, 0.0, 0.0, 1.0];
|
||||
node.scale = node.scale ?? [1.0, 1.0, 1.0];
|
||||
} else {
|
||||
node.matrix = node.matrix ?? [
|
||||
1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0,
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
ForEach.sampler(gltf, function (sampler) {
|
||||
sampler.wrapS = sampler.wrapS ?? WebGLConstants.REPEAT;
|
||||
sampler.wrapT = sampler.wrapT ?? WebGLConstants.REPEAT;
|
||||
});
|
||||
|
||||
if (defined(gltf.scenes) && !defined(gltf.scene)) {
|
||||
gltf.scene = 0;
|
||||
}
|
||||
|
||||
return gltf;
|
||||
}
|
||||
|
||||
function getAnimatedNodes(gltf) {
|
||||
const nodes = {};
|
||||
ForEach.animation(gltf, function (animation) {
|
||||
ForEach.animationChannel(animation, function (channel) {
|
||||
const target = channel.target;
|
||||
const nodeId = target.node;
|
||||
const path = target.path;
|
||||
// Ignore animations that target 'weights'
|
||||
if (path === "translation" || path === "rotation" || path === "scale") {
|
||||
nodes[nodeId] = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
return nodes;
|
||||
}
|
||||
|
||||
function addTextureDefaults(texture) {
|
||||
if (defined(texture)) {
|
||||
texture.texCoord = texture.texCoord ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
export default addDefaults;
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
import addExtensionsUsed from "./addExtensionsUsed.js";
|
||||
import addToArray from "./addToArray.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
|
||||
/**
|
||||
* Adds an extension to gltf.extensionsRequired if it does not already exist.
|
||||
* Initializes extensionsRequired if it is not defined.
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @param {string} extension The extension to add.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function addExtensionsRequired(gltf, extension) {
|
||||
let extensionsRequired = gltf.extensionsRequired;
|
||||
if (!defined(extensionsRequired)) {
|
||||
extensionsRequired = [];
|
||||
gltf.extensionsRequired = extensionsRequired;
|
||||
}
|
||||
addToArray(extensionsRequired, extension, true);
|
||||
addExtensionsUsed(gltf, extension);
|
||||
}
|
||||
|
||||
export default addExtensionsRequired;
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
import addToArray from "./addToArray.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
|
||||
/**
|
||||
* Adds an extension to gltf.extensionsUsed if it does not already exist.
|
||||
* Initializes extensionsUsed if it is not defined.
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @param {string} extension The extension to add.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function addExtensionsUsed(gltf, extension) {
|
||||
let extensionsUsed = gltf.extensionsUsed;
|
||||
if (!defined(extensionsUsed)) {
|
||||
extensionsUsed = [];
|
||||
gltf.extensionsUsed = extensionsUsed;
|
||||
}
|
||||
addToArray(extensionsUsed, extension, true);
|
||||
}
|
||||
|
||||
export default addExtensionsUsed;
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
import ForEach from "./ForEach.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
|
||||
/**
|
||||
* Adds extras._pipeline to each object that can have extras in the glTF asset.
|
||||
* This stage runs before updateVersion and handles both glTF 1.0 and glTF 2.0 assets.
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @returns {object} The glTF asset with the added pipeline extras.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function addPipelineExtras(gltf) {
|
||||
ForEach.shader(gltf, function (shader) {
|
||||
addExtras(shader);
|
||||
});
|
||||
ForEach.buffer(gltf, function (buffer) {
|
||||
addExtras(buffer);
|
||||
});
|
||||
ForEach.image(gltf, function (image) {
|
||||
addExtras(image);
|
||||
});
|
||||
|
||||
addExtras(gltf);
|
||||
|
||||
return gltf;
|
||||
}
|
||||
|
||||
function addExtras(object) {
|
||||
object.extras = defined(object.extras) ? object.extras : {};
|
||||
object.extras._pipeline = defined(object.extras._pipeline)
|
||||
? object.extras._pipeline
|
||||
: {};
|
||||
}
|
||||
|
||||
export default addPipelineExtras;
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
|
||||
/**
|
||||
* Adds an element to an array and returns the element's index.
|
||||
*
|
||||
* @param {Array} array The array to add to.
|
||||
* @param {object} element The element to add.
|
||||
* @param {boolean} [checkDuplicates=false] When <code>true</code>, if a duplicate element is found its index is returned and <code>element</code> is not added to the array.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function addToArray(array, element, checkDuplicates) {
|
||||
checkDuplicates = checkDuplicates ?? false;
|
||||
if (checkDuplicates) {
|
||||
const index = array.indexOf(element);
|
||||
if (index > -1) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
array.push(element);
|
||||
return array.length - 1;
|
||||
}
|
||||
|
||||
export default addToArray;
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
import getAccessorByteStride from "./getAccessorByteStride.js";
|
||||
import getComponentReader from "./getComponentReader.js";
|
||||
import numberOfComponentsForType from "./numberOfComponentsForType.js";
|
||||
import ComponentDatatype from "../../Core/ComponentDatatype.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
|
||||
/**
|
||||
* Finds the min and max values of the accessor.
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @param {object} accessor The accessor object from the glTF asset to read.
|
||||
* @returns {{min: Array, max: Array}} min holding the array of minimum values and max holding the array of maximum values.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function findAccessorMinMax(gltf, accessor) {
|
||||
const bufferViews = gltf.bufferViews;
|
||||
const buffers = gltf.buffers;
|
||||
const bufferViewId = accessor.bufferView;
|
||||
const numberOfComponents = numberOfComponentsForType(accessor.type);
|
||||
|
||||
// According to the spec, when bufferView is not defined, accessor must be initialized with zeros
|
||||
if (!defined(accessor.bufferView)) {
|
||||
return {
|
||||
min: new Array(numberOfComponents).fill(0.0),
|
||||
max: new Array(numberOfComponents).fill(0.0),
|
||||
};
|
||||
}
|
||||
|
||||
const min = new Array(numberOfComponents).fill(Number.POSITIVE_INFINITY);
|
||||
const max = new Array(numberOfComponents).fill(Number.NEGATIVE_INFINITY);
|
||||
|
||||
const bufferView = bufferViews[bufferViewId];
|
||||
const bufferId = bufferView.buffer;
|
||||
const buffer = buffers[bufferId];
|
||||
const source = buffer.extras._pipeline.source;
|
||||
|
||||
const count = accessor.count;
|
||||
const byteStride = getAccessorByteStride(gltf, accessor);
|
||||
let byteOffset =
|
||||
accessor.byteOffset + bufferView.byteOffset + source.byteOffset;
|
||||
const componentType = accessor.componentType;
|
||||
const componentTypeByteLength =
|
||||
ComponentDatatype.getSizeInBytes(componentType);
|
||||
const dataView = new DataView(source.buffer);
|
||||
const components = new Array(numberOfComponents);
|
||||
const componentReader = getComponentReader(componentType);
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
componentReader(
|
||||
dataView,
|
||||
byteOffset,
|
||||
numberOfComponents,
|
||||
componentTypeByteLength,
|
||||
components,
|
||||
);
|
||||
for (let j = 0; j < numberOfComponents; j++) {
|
||||
const value = components[j];
|
||||
min[j] = Math.min(min[j], value);
|
||||
max[j] = Math.max(max[j], value);
|
||||
}
|
||||
byteOffset += byteStride;
|
||||
}
|
||||
|
||||
return {
|
||||
min: min,
|
||||
max: max,
|
||||
};
|
||||
}
|
||||
|
||||
export default findAccessorMinMax;
|
||||
Generated
Vendored
+165
@@ -0,0 +1,165 @@
|
||||
import ForEach from "./ForEach.js";
|
||||
import Check from "../../Core/Check.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
|
||||
/**
|
||||
* Calls the provider handler function on each texture used by the material.
|
||||
* Mimics the behavior of functions in gltf-pipeline ForEach.
|
||||
* @param {object} material The glTF material.
|
||||
* @param {forEachTextureInMaterial~handler} handler Function that is called for each texture in the material.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function forEachTextureInMaterial(material, handler) {
|
||||
Check.typeOf.object("material", material);
|
||||
Check.defined("handler", handler);
|
||||
|
||||
// Metallic roughness
|
||||
const pbrMetallicRoughness = material.pbrMetallicRoughness;
|
||||
if (defined(pbrMetallicRoughness)) {
|
||||
if (defined(pbrMetallicRoughness.baseColorTexture)) {
|
||||
const textureInfo = pbrMetallicRoughness.baseColorTexture;
|
||||
const value = handler(textureInfo.index, textureInfo);
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
if (defined(pbrMetallicRoughness.metallicRoughnessTexture)) {
|
||||
const textureInfo = pbrMetallicRoughness.metallicRoughnessTexture;
|
||||
const value = handler(textureInfo.index, textureInfo);
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const { extensions } = material;
|
||||
if (defined(extensions)) {
|
||||
// Spec gloss extension
|
||||
const pbrSpecularGlossiness =
|
||||
extensions.KHR_materials_pbrSpecularGlossiness;
|
||||
if (defined(pbrSpecularGlossiness)) {
|
||||
if (defined(pbrSpecularGlossiness.diffuseTexture)) {
|
||||
const textureInfo = pbrSpecularGlossiness.diffuseTexture;
|
||||
const value = handler(textureInfo.index, textureInfo);
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
if (defined(pbrSpecularGlossiness.specularGlossinessTexture)) {
|
||||
const textureInfo = pbrSpecularGlossiness.specularGlossinessTexture;
|
||||
const value = handler(textureInfo.index, textureInfo);
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Specular extension
|
||||
const specular = extensions.KHR_materials_specular;
|
||||
if (defined(specular)) {
|
||||
const { specularTexture, specularColorTexture } = specular;
|
||||
if (defined(specularTexture)) {
|
||||
const value = handler(specularTexture.index, specularTexture);
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
if (defined(specularColorTexture)) {
|
||||
const value = handler(specularColorTexture.index, specularColorTexture);
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Transmission extension
|
||||
const transmission = extensions.KHR_materials_transmission;
|
||||
if (defined(transmission) && defined(transmission.transmissionTexture)) {
|
||||
const textureInfo = transmission.transmissionTexture;
|
||||
const value = handler(textureInfo.index, textureInfo);
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// Materials common extension (may be present in models converted from glTF 1.0)
|
||||
const materialsCommon = extensions.KHR_materials_common;
|
||||
if (defined(materialsCommon) && defined(materialsCommon.values)) {
|
||||
const { diffuse, ambient, emission, specular } = materialsCommon.values;
|
||||
if (defined(diffuse) && defined(diffuse.index)) {
|
||||
const value = handler(diffuse.index, diffuse);
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
if (defined(ambient) && defined(ambient.index)) {
|
||||
const value = handler(ambient.index, ambient);
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
if (defined(emission) && defined(emission.index)) {
|
||||
const value = handler(emission.index, emission);
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
if (defined(specular) && defined(specular.index)) {
|
||||
const value = handler(specular.index, specular);
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// KHR_techniques_webgl extension
|
||||
const value = ForEach.materialValue(material, function (materialValue) {
|
||||
if (defined(materialValue.index)) {
|
||||
const value = handler(materialValue.index, materialValue);
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// Top level textures
|
||||
if (defined(material.emissiveTexture)) {
|
||||
const textureInfo = material.emissiveTexture;
|
||||
const value = handler(textureInfo.index, textureInfo);
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
if (defined(material.normalTexture)) {
|
||||
const textureInfo = material.normalTexture;
|
||||
const value = handler(textureInfo.index, textureInfo);
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
if (defined(material.occlusionTexture)) {
|
||||
const textureInfo = material.occlusionTexture;
|
||||
const value = handler(textureInfo.index, textureInfo);
|
||||
if (defined(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that is called for each texture in the material. If this function returns a value the for each stops and returns that value.
|
||||
* @callback forEachTextureInMaterial~handler
|
||||
* @param {number} The texture index.
|
||||
* @param {object} The texture info object.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
export default forEachTextureInMaterial;
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import numberOfComponentsForType from "./numberOfComponentsForType.js";
|
||||
import ComponentDatatype from "../../Core/ComponentDatatype.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
|
||||
/**
|
||||
* Returns the byte stride of the provided accessor.
|
||||
* If the byteStride is 0, it is calculated based on type and componentType
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @param {object} accessor The accessor.
|
||||
* @returns {number} The byte stride of the accessor.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function getAccessorByteStride(gltf, accessor) {
|
||||
const bufferViewId = accessor.bufferView;
|
||||
if (defined(bufferViewId)) {
|
||||
const bufferView = gltf.bufferViews[bufferViewId];
|
||||
if (defined(bufferView.byteStride) && bufferView.byteStride > 0) {
|
||||
return bufferView.byteStride;
|
||||
}
|
||||
}
|
||||
return (
|
||||
ComponentDatatype.getSizeInBytes(accessor.componentType) *
|
||||
numberOfComponentsForType(accessor.type)
|
||||
);
|
||||
}
|
||||
|
||||
export default getAccessorByteStride;
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
import ComponentDatatype from "../../Core/ComponentDatatype.js";
|
||||
|
||||
/**
|
||||
* Returns a function to read and convert data from a DataView into an array.
|
||||
*
|
||||
* @param {number} componentType Type to convert the data to.
|
||||
* @returns {ComponentReader} Function that reads and converts data.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function getComponentReader(componentType) {
|
||||
switch (componentType) {
|
||||
case ComponentDatatype.BYTE:
|
||||
return function (
|
||||
dataView,
|
||||
byteOffset,
|
||||
numberOfComponents,
|
||||
componentTypeByteLength,
|
||||
result,
|
||||
) {
|
||||
for (let i = 0; i < numberOfComponents; ++i) {
|
||||
result[i] = dataView.getInt8(
|
||||
byteOffset + i * componentTypeByteLength,
|
||||
);
|
||||
}
|
||||
};
|
||||
case ComponentDatatype.UNSIGNED_BYTE:
|
||||
return function (
|
||||
dataView,
|
||||
byteOffset,
|
||||
numberOfComponents,
|
||||
componentTypeByteLength,
|
||||
result,
|
||||
) {
|
||||
for (let i = 0; i < numberOfComponents; ++i) {
|
||||
result[i] = dataView.getUint8(
|
||||
byteOffset + i * componentTypeByteLength,
|
||||
);
|
||||
}
|
||||
};
|
||||
case ComponentDatatype.SHORT:
|
||||
return function (
|
||||
dataView,
|
||||
byteOffset,
|
||||
numberOfComponents,
|
||||
componentTypeByteLength,
|
||||
result,
|
||||
) {
|
||||
for (let i = 0; i < numberOfComponents; ++i) {
|
||||
result[i] = dataView.getInt16(
|
||||
byteOffset + i * componentTypeByteLength,
|
||||
true,
|
||||
);
|
||||
}
|
||||
};
|
||||
case ComponentDatatype.UNSIGNED_SHORT:
|
||||
return function (
|
||||
dataView,
|
||||
byteOffset,
|
||||
numberOfComponents,
|
||||
componentTypeByteLength,
|
||||
result,
|
||||
) {
|
||||
for (let i = 0; i < numberOfComponents; ++i) {
|
||||
result[i] = dataView.getUint16(
|
||||
byteOffset + i * componentTypeByteLength,
|
||||
true,
|
||||
);
|
||||
}
|
||||
};
|
||||
case ComponentDatatype.INT:
|
||||
return function (
|
||||
dataView,
|
||||
byteOffset,
|
||||
numberOfComponents,
|
||||
componentTypeByteLength,
|
||||
result,
|
||||
) {
|
||||
for (let i = 0; i < numberOfComponents; ++i) {
|
||||
result[i] = dataView.getInt32(
|
||||
byteOffset + i * componentTypeByteLength,
|
||||
true,
|
||||
);
|
||||
}
|
||||
};
|
||||
case ComponentDatatype.UNSIGNED_INT:
|
||||
return function (
|
||||
dataView,
|
||||
byteOffset,
|
||||
numberOfComponents,
|
||||
componentTypeByteLength,
|
||||
result,
|
||||
) {
|
||||
for (let i = 0; i < numberOfComponents; ++i) {
|
||||
result[i] = dataView.getUint32(
|
||||
byteOffset + i * componentTypeByteLength,
|
||||
true,
|
||||
);
|
||||
}
|
||||
};
|
||||
case ComponentDatatype.FLOAT:
|
||||
return function (
|
||||
dataView,
|
||||
byteOffset,
|
||||
numberOfComponents,
|
||||
componentTypeByteLength,
|
||||
result,
|
||||
) {
|
||||
for (let i = 0; i < numberOfComponents; ++i) {
|
||||
result[i] = dataView.getFloat32(
|
||||
byteOffset + i * componentTypeByteLength,
|
||||
true,
|
||||
);
|
||||
}
|
||||
};
|
||||
case ComponentDatatype.DOUBLE:
|
||||
return function (
|
||||
dataView,
|
||||
byteOffset,
|
||||
numberOfComponents,
|
||||
componentTypeByteLength,
|
||||
result,
|
||||
) {
|
||||
for (let i = 0; i < numberOfComponents; ++i) {
|
||||
result[i] = dataView.getFloat64(
|
||||
byteOffset + i * componentTypeByteLength,
|
||||
true,
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback function that logs messages.
|
||||
* @callback ComponentReader
|
||||
*
|
||||
* @param {DataView} dataView The data view to read from.
|
||||
* @param {number} byteOffset The byte offset applied when reading from the data view.
|
||||
* @param {number} numberOfComponents The number of components to read.
|
||||
* @param {number} componentTypeByteLength The byte length of each component.
|
||||
* @param {number} result An array storing the components that are read.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
export default getComponentReader;
|
||||
Generated
Vendored
+135
@@ -0,0 +1,135 @@
|
||||
import addExtensionsUsed from "./addExtensionsUsed.js";
|
||||
import ForEach from "./ForEach.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
import WebGLConstants from "../../Core/WebGLConstants.js";
|
||||
|
||||
const defaultBlendEquation = [WebGLConstants.FUNC_ADD, WebGLConstants.FUNC_ADD];
|
||||
|
||||
const defaultBlendFactors = [
|
||||
WebGLConstants.ONE,
|
||||
WebGLConstants.ZERO,
|
||||
WebGLConstants.ONE,
|
||||
WebGLConstants.ZERO,
|
||||
];
|
||||
|
||||
function isStateEnabled(renderStates, state) {
|
||||
const enabled = renderStates.enable;
|
||||
if (!defined(enabled)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return enabled.indexOf(state) > -1;
|
||||
}
|
||||
|
||||
const supportedBlendFactors = [
|
||||
WebGLConstants.ZERO,
|
||||
WebGLConstants.ONE,
|
||||
WebGLConstants.SRC_COLOR,
|
||||
WebGLConstants.ONE_MINUS_SRC_COLOR,
|
||||
WebGLConstants.SRC_ALPHA,
|
||||
WebGLConstants.ONE_MINUS_SRC_ALPHA,
|
||||
WebGLConstants.DST_ALPHA,
|
||||
WebGLConstants.ONE_MINUS_DST_ALPHA,
|
||||
WebGLConstants.DST_COLOR,
|
||||
WebGLConstants.ONE_MINUS_DST_COLOR,
|
||||
];
|
||||
|
||||
// If any of the blend factors are not supported, return the default
|
||||
function getSupportedBlendFactors(value, defaultValue) {
|
||||
if (!defined(value)) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
if (supportedBlendFactors.indexOf(value[i]) === -1) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move glTF 1.0 technique render states to glTF 2.0 materials properties and KHR_blend extension.
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @returns {object} The updated glTF asset.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function moveTechniqueRenderStates(gltf) {
|
||||
const blendingForTechnique = {};
|
||||
const materialPropertiesForTechnique = {};
|
||||
const techniquesLegacy = gltf.techniques;
|
||||
if (!defined(techniquesLegacy)) {
|
||||
return gltf;
|
||||
}
|
||||
|
||||
ForEach.technique(gltf, function (techniqueLegacy, techniqueIndex) {
|
||||
const renderStates = techniqueLegacy.states;
|
||||
if (defined(renderStates)) {
|
||||
const materialProperties = (materialPropertiesForTechnique[
|
||||
techniqueIndex
|
||||
] = {});
|
||||
|
||||
// If BLEND is enabled, the material should have alpha mode BLEND
|
||||
if (isStateEnabled(renderStates, WebGLConstants.BLEND)) {
|
||||
materialProperties.alphaMode = "BLEND";
|
||||
|
||||
const blendFunctions = renderStates.functions;
|
||||
if (
|
||||
defined(blendFunctions) &&
|
||||
(defined(blendFunctions.blendEquationSeparate) ||
|
||||
defined(blendFunctions.blendFuncSeparate))
|
||||
) {
|
||||
blendingForTechnique[techniqueIndex] = {
|
||||
blendEquation:
|
||||
blendFunctions.blendEquationSeparate ?? defaultBlendEquation,
|
||||
blendFactors: getSupportedBlendFactors(
|
||||
blendFunctions.blendFuncSeparate,
|
||||
defaultBlendFactors,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// If CULL_FACE is not enabled, the material should be doubleSided
|
||||
if (!isStateEnabled(renderStates, WebGLConstants.CULL_FACE)) {
|
||||
materialProperties.doubleSided = true;
|
||||
}
|
||||
|
||||
delete techniqueLegacy.states;
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.keys(blendingForTechnique).length > 0) {
|
||||
if (!defined(gltf.extensions)) {
|
||||
gltf.extensions = {};
|
||||
}
|
||||
|
||||
addExtensionsUsed(gltf, "KHR_blend");
|
||||
}
|
||||
|
||||
ForEach.material(gltf, function (material) {
|
||||
if (defined(material.technique)) {
|
||||
const materialProperties =
|
||||
materialPropertiesForTechnique[material.technique];
|
||||
ForEach.objectLegacy(materialProperties, function (value, property) {
|
||||
material[property] = value;
|
||||
});
|
||||
|
||||
const blending = blendingForTechnique[material.technique];
|
||||
if (defined(blending)) {
|
||||
if (!defined(material.extensions)) {
|
||||
material.extensions = {};
|
||||
}
|
||||
|
||||
material.extensions.KHR_blend = blending;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return gltf;
|
||||
}
|
||||
|
||||
export default moveTechniqueRenderStates;
|
||||
Generated
Vendored
+145
@@ -0,0 +1,145 @@
|
||||
import addExtensionsUsed from "./addExtensionsUsed.js";
|
||||
import addExtensionsRequired from "./addExtensionsRequired.js";
|
||||
import addToArray from "./addToArray.js";
|
||||
import ForEach from "./ForEach.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
|
||||
/**
|
||||
* Move glTF 1.0 material techniques to glTF 2.0 KHR_techniques_webgl extension.
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @returns {object} The updated glTF asset.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function moveTechniquesToExtension(gltf) {
|
||||
const techniquesLegacy = gltf.techniques;
|
||||
const mappedUniforms = {};
|
||||
const updatedTechniqueIndices = {};
|
||||
const seenPrograms = {};
|
||||
if (defined(techniquesLegacy)) {
|
||||
const extension = {
|
||||
programs: [],
|
||||
shaders: [],
|
||||
techniques: [],
|
||||
};
|
||||
|
||||
// Some 1.1 models have a glExtensionsUsed property that can be transferred to program.glExtensions
|
||||
const glExtensions = gltf.glExtensionsUsed;
|
||||
delete gltf.glExtensionsUsed;
|
||||
|
||||
ForEach.technique(gltf, function (techniqueLegacy, techniqueId) {
|
||||
const technique = {
|
||||
name: techniqueLegacy.name,
|
||||
program: undefined,
|
||||
attributes: {},
|
||||
uniforms: {},
|
||||
};
|
||||
|
||||
let parameterLegacy;
|
||||
ForEach.techniqueAttribute(
|
||||
techniqueLegacy,
|
||||
function (parameterName, attributeName) {
|
||||
parameterLegacy = techniqueLegacy.parameters[parameterName];
|
||||
technique.attributes[attributeName] = {
|
||||
semantic: parameterLegacy.semantic,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
ForEach.techniqueUniform(
|
||||
techniqueLegacy,
|
||||
function (parameterName, uniformName) {
|
||||
parameterLegacy = techniqueLegacy.parameters[parameterName];
|
||||
technique.uniforms[uniformName] = {
|
||||
count: parameterLegacy.count,
|
||||
node: parameterLegacy.node,
|
||||
type: parameterLegacy.type,
|
||||
semantic: parameterLegacy.semantic,
|
||||
value: parameterLegacy.value,
|
||||
};
|
||||
|
||||
// Store the name of the uniform to update material values.
|
||||
if (!defined(mappedUniforms[techniqueId])) {
|
||||
mappedUniforms[techniqueId] = {};
|
||||
}
|
||||
mappedUniforms[techniqueId][parameterName] = uniformName;
|
||||
},
|
||||
);
|
||||
|
||||
if (!defined(seenPrograms[techniqueLegacy.program])) {
|
||||
const programLegacy = gltf.programs[techniqueLegacy.program];
|
||||
|
||||
const program = {
|
||||
name: programLegacy.name,
|
||||
fragmentShader: undefined,
|
||||
vertexShader: undefined,
|
||||
glExtensions: glExtensions,
|
||||
};
|
||||
|
||||
const fs = gltf.shaders[programLegacy.fragmentShader];
|
||||
program.fragmentShader = addToArray(extension.shaders, fs, true);
|
||||
|
||||
const vs = gltf.shaders[programLegacy.vertexShader];
|
||||
program.vertexShader = addToArray(extension.shaders, vs, true);
|
||||
|
||||
technique.program = addToArray(extension.programs, program);
|
||||
seenPrograms[techniqueLegacy.program] = technique.program;
|
||||
} else {
|
||||
technique.program = seenPrograms[techniqueLegacy.program];
|
||||
}
|
||||
|
||||
// Store the index of the new technique to reference instead.
|
||||
updatedTechniqueIndices[techniqueId] = addToArray(
|
||||
extension.techniques,
|
||||
technique,
|
||||
);
|
||||
});
|
||||
|
||||
if (extension.techniques.length > 0) {
|
||||
if (!defined(gltf.extensions)) {
|
||||
gltf.extensions = {};
|
||||
}
|
||||
|
||||
gltf.extensions.KHR_techniques_webgl = extension;
|
||||
addExtensionsUsed(gltf, "KHR_techniques_webgl");
|
||||
addExtensionsRequired(gltf, "KHR_techniques_webgl");
|
||||
}
|
||||
}
|
||||
|
||||
ForEach.material(gltf, function (material) {
|
||||
if (defined(material.technique)) {
|
||||
const materialExtension = {
|
||||
technique: updatedTechniqueIndices[material.technique],
|
||||
};
|
||||
|
||||
ForEach.objectLegacy(material.values, function (value, parameterName) {
|
||||
if (!defined(materialExtension.values)) {
|
||||
materialExtension.values = {};
|
||||
}
|
||||
|
||||
const uniformName = mappedUniforms[material.technique][parameterName];
|
||||
if (defined(uniformName)) {
|
||||
materialExtension.values[uniformName] = value;
|
||||
}
|
||||
});
|
||||
|
||||
if (!defined(material.extensions)) {
|
||||
material.extensions = {};
|
||||
}
|
||||
|
||||
material.extensions.KHR_techniques_webgl = materialExtension;
|
||||
}
|
||||
|
||||
delete material.technique;
|
||||
delete material.values;
|
||||
});
|
||||
|
||||
delete gltf.techniques;
|
||||
delete gltf.programs;
|
||||
delete gltf.shaders;
|
||||
|
||||
return gltf;
|
||||
}
|
||||
|
||||
export default moveTechniquesToExtension;
|
||||
Generated
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
|
||||
|
||||
/**
|
||||
* Utility function for retrieving the number of components in a given type.
|
||||
*
|
||||
* @param {string} type glTF type
|
||||
* @returns {number} The number of components in that type.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function numberOfComponentsForType(type) {
|
||||
switch (type) {
|
||||
case "SCALAR":
|
||||
return 1;
|
||||
case "VEC2":
|
||||
return 2;
|
||||
case "VEC3":
|
||||
return 3;
|
||||
case "VEC4":
|
||||
case "MAT2":
|
||||
return 4;
|
||||
case "MAT3":
|
||||
return 9;
|
||||
case "MAT4":
|
||||
return 16;
|
||||
}
|
||||
}
|
||||
|
||||
export default numberOfComponentsForType;
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
import addPipelineExtras from "./addPipelineExtras.js";
|
||||
import removeExtensionsUsed from "./removeExtensionsUsed.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
import getMagic from "../../Core/getMagic.js";
|
||||
import getStringFromTypedArray from "../../Core/getStringFromTypedArray.js";
|
||||
import RuntimeError from "../../Core/RuntimeError.js";
|
||||
|
||||
const sizeOfUint32 = 4;
|
||||
|
||||
/**
|
||||
* Convert a binary glTF to glTF.
|
||||
*
|
||||
* The returned glTF has pipeline extras included. The embedded binary data is stored in gltf.buffers[0].extras._pipeline.source.
|
||||
*
|
||||
* @param {Buffer} glb The glb data to parse.
|
||||
* @returns {object} A javascript object containing a glTF asset with pipeline extras included.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function parseGlb(glb) {
|
||||
// Check that the magic string is present
|
||||
const magic = getMagic(glb);
|
||||
if (magic !== "glTF") {
|
||||
throw new RuntimeError("File is not valid binary glTF");
|
||||
}
|
||||
|
||||
const header = readHeader(glb, 0, 5);
|
||||
const version = header[1];
|
||||
if (version !== 1 && version !== 2) {
|
||||
throw new RuntimeError("Binary glTF version is not 1 or 2");
|
||||
}
|
||||
|
||||
if (version === 1) {
|
||||
return parseGlbVersion1(glb, header);
|
||||
}
|
||||
|
||||
return parseGlbVersion2(glb, header);
|
||||
}
|
||||
|
||||
function readHeader(glb, byteOffset, count) {
|
||||
const dataView = new DataView(glb.buffer);
|
||||
const header = new Array(count);
|
||||
for (let i = 0; i < count; ++i) {
|
||||
header[i] = dataView.getUint32(
|
||||
glb.byteOffset + byteOffset + i * sizeOfUint32,
|
||||
true,
|
||||
);
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
||||
function parseGlbVersion1(glb, header) {
|
||||
const length = header[2];
|
||||
const contentLength = header[3];
|
||||
const contentFormat = header[4];
|
||||
|
||||
// Check that the content format is 0, indicating that it is JSON
|
||||
if (contentFormat !== 0) {
|
||||
throw new RuntimeError("Binary glTF scene format is not JSON");
|
||||
}
|
||||
|
||||
const jsonStart = 20;
|
||||
const binaryStart = jsonStart + contentLength;
|
||||
|
||||
const contentString = getStringFromTypedArray(glb, jsonStart, contentLength);
|
||||
const gltf = JSON.parse(contentString);
|
||||
addPipelineExtras(gltf);
|
||||
|
||||
const binaryBuffer = glb.subarray(binaryStart, length);
|
||||
|
||||
const buffers = gltf.buffers;
|
||||
if (defined(buffers) && Object.keys(buffers).length > 0) {
|
||||
// In some older models, the binary glTF buffer is named KHR_binary_glTF
|
||||
const binaryGltfBuffer = buffers.binary_glTF ?? buffers.KHR_binary_glTF;
|
||||
if (defined(binaryGltfBuffer)) {
|
||||
binaryGltfBuffer.extras._pipeline.source = binaryBuffer;
|
||||
delete binaryGltfBuffer.uri;
|
||||
}
|
||||
}
|
||||
// Remove the KHR_binary_glTF extension
|
||||
removeExtensionsUsed(gltf, "KHR_binary_glTF");
|
||||
return gltf;
|
||||
}
|
||||
|
||||
function parseGlbVersion2(glb, header) {
|
||||
const length = header[2];
|
||||
let byteOffset = 12;
|
||||
let gltf;
|
||||
let binaryBuffer;
|
||||
while (byteOffset < length) {
|
||||
const chunkHeader = readHeader(glb, byteOffset, 2);
|
||||
const chunkLength = chunkHeader[0];
|
||||
const chunkType = chunkHeader[1];
|
||||
byteOffset += 8;
|
||||
const chunkBuffer = glb.subarray(byteOffset, byteOffset + chunkLength);
|
||||
byteOffset += chunkLength;
|
||||
// Load JSON chunk
|
||||
if (chunkType === 0x4e4f534a) {
|
||||
const jsonString = getStringFromTypedArray(chunkBuffer);
|
||||
gltf = JSON.parse(jsonString);
|
||||
addPipelineExtras(gltf);
|
||||
}
|
||||
// Load Binary chunk
|
||||
else if (chunkType === 0x004e4942) {
|
||||
binaryBuffer = chunkBuffer;
|
||||
}
|
||||
}
|
||||
if (defined(gltf) && defined(binaryBuffer)) {
|
||||
const buffers = gltf.buffers;
|
||||
if (defined(buffers) && buffers.length > 0) {
|
||||
const buffer = buffers[0];
|
||||
buffer.extras._pipeline.source = binaryBuffer;
|
||||
}
|
||||
}
|
||||
return gltf;
|
||||
}
|
||||
|
||||
export default parseGlb;
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import getAccessorByteStride from "./getAccessorByteStride.js";
|
||||
import getComponentReader from "./getComponentReader.js";
|
||||
import numberOfComponentsForType from "./numberOfComponentsForType.js";
|
||||
import ComponentDatatype from "../../Core/ComponentDatatype.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
|
||||
/**
|
||||
* Returns the accessor data in a contiguous array.
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @param {object} accessor The accessor.
|
||||
* @returns {Array} The accessor values in a contiguous array.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function readAccessorPacked(gltf, accessor) {
|
||||
const byteStride = getAccessorByteStride(gltf, accessor);
|
||||
const componentTypeByteLength = ComponentDatatype.getSizeInBytes(
|
||||
accessor.componentType,
|
||||
);
|
||||
const numberOfComponents = numberOfComponentsForType(accessor.type);
|
||||
const count = accessor.count;
|
||||
const values = new Array(numberOfComponents * count);
|
||||
|
||||
if (!defined(accessor.bufferView)) {
|
||||
return values.fill(0);
|
||||
}
|
||||
|
||||
const bufferView = gltf.bufferViews[accessor.bufferView];
|
||||
const source = gltf.buffers[bufferView.buffer].extras._pipeline.source;
|
||||
let byteOffset =
|
||||
accessor.byteOffset + bufferView.byteOffset + source.byteOffset;
|
||||
|
||||
const dataView = new DataView(source.buffer);
|
||||
const components = new Array(numberOfComponents);
|
||||
const componentReader = getComponentReader(accessor.componentType);
|
||||
|
||||
for (let i = 0; i < count; ++i) {
|
||||
componentReader(
|
||||
dataView,
|
||||
byteOffset,
|
||||
numberOfComponents,
|
||||
componentTypeByteLength,
|
||||
components,
|
||||
);
|
||||
for (let j = 0; j < numberOfComponents; ++j) {
|
||||
values[i * numberOfComponents + j] = components[j];
|
||||
}
|
||||
byteOffset += byteStride;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
export default readAccessorPacked;
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
import ForEach from "./ForEach.js";
|
||||
import removeExtensionsUsed from "./removeExtensionsUsed.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
|
||||
/**
|
||||
* Removes an extension from gltf.extensions, gltf.extensionsUsed, gltf.extensionsRequired, and any other objects in the glTF if it is present.
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @param {string} extension The extension to remove.
|
||||
*
|
||||
* @returns {*} The extension data removed from gltf.extensions.
|
||||
*/
|
||||
function removeExtension(gltf, extension) {
|
||||
removeExtensionsUsed(gltf, extension); // Also removes from extensionsRequired
|
||||
|
||||
if (extension === "CESIUM_RTC") {
|
||||
removeCesiumRTC(gltf);
|
||||
}
|
||||
|
||||
return removeExtensionAndTraverse(gltf, extension);
|
||||
}
|
||||
|
||||
function removeCesiumRTC(gltf) {
|
||||
ForEach.technique(gltf, function (technique) {
|
||||
ForEach.techniqueUniform(technique, function (uniform) {
|
||||
if (uniform.semantic === "CESIUM_RTC_MODELVIEW") {
|
||||
uniform.semantic = "MODELVIEW";
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function removeExtensionAndTraverse(object, extension) {
|
||||
if (Array.isArray(object)) {
|
||||
const length = object.length;
|
||||
for (let i = 0; i < length; ++i) {
|
||||
removeExtensionAndTraverse(object[i], extension);
|
||||
}
|
||||
} else if (
|
||||
object !== null &&
|
||||
typeof object === "object" &&
|
||||
object.constructor === Object
|
||||
) {
|
||||
const extensions = object.extensions;
|
||||
let extensionData;
|
||||
if (defined(extensions)) {
|
||||
extensionData = extensions[extension];
|
||||
if (defined(extensionData)) {
|
||||
delete extensions[extension];
|
||||
if (Object.keys(extensions).length === 0) {
|
||||
delete object.extensions;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const key in object) {
|
||||
if (Object.prototype.hasOwnProperty.call(object, key)) {
|
||||
removeExtensionAndTraverse(object[key], extension);
|
||||
}
|
||||
}
|
||||
return extensionData;
|
||||
}
|
||||
}
|
||||
|
||||
export default removeExtension;
|
||||
Generated
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
import defined from "../../Core/defined.js";
|
||||
|
||||
/**
|
||||
* Removes an extension from gltf.extensionsRequired if it is present.
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @param {string} extension The extension to remove.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function removeExtensionsRequired(gltf, extension) {
|
||||
const extensionsRequired = gltf.extensionsRequired;
|
||||
if (defined(extensionsRequired)) {
|
||||
const index = extensionsRequired.indexOf(extension);
|
||||
if (index >= 0) {
|
||||
extensionsRequired.splice(index, 1);
|
||||
}
|
||||
if (extensionsRequired.length === 0) {
|
||||
delete gltf.extensionsRequired;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default removeExtensionsRequired;
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
import removeExtensionsRequired from "./removeExtensionsRequired.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
|
||||
/**
|
||||
* Removes an extension from gltf.extensionsUsed and gltf.extensionsRequired if it is present.
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @param {string} extension The extension to remove.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function removeExtensionsUsed(gltf, extension) {
|
||||
const extensionsUsed = gltf.extensionsUsed;
|
||||
if (defined(extensionsUsed)) {
|
||||
const index = extensionsUsed.indexOf(extension);
|
||||
if (index >= 0) {
|
||||
extensionsUsed.splice(index, 1);
|
||||
}
|
||||
removeExtensionsRequired(gltf, extension);
|
||||
if (extensionsUsed.length === 0) {
|
||||
delete gltf.extensionsUsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default removeExtensionsUsed;
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
import ForEach from "./ForEach.js";
|
||||
import defined from "../../Core/defined.js";
|
||||
|
||||
/**
|
||||
* Iterate through the objects within the glTF and delete their pipeline extras object.
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @returns {object} glTF with no pipeline extras.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function removePipelineExtras(gltf) {
|
||||
ForEach.shader(gltf, function (shader) {
|
||||
removeExtras(shader);
|
||||
});
|
||||
ForEach.buffer(gltf, function (buffer) {
|
||||
removeExtras(buffer);
|
||||
});
|
||||
ForEach.image(gltf, function (image) {
|
||||
removeExtras(image);
|
||||
});
|
||||
|
||||
removeExtras(gltf);
|
||||
|
||||
return gltf;
|
||||
}
|
||||
|
||||
function removeExtras(object) {
|
||||
if (!defined(object.extras)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (defined(object.extras._pipeline)) {
|
||||
delete object.extras._pipeline;
|
||||
}
|
||||
|
||||
if (Object.keys(object.extras).length === 0) {
|
||||
delete object.extras;
|
||||
}
|
||||
}
|
||||
|
||||
export default removePipelineExtras;
|
||||
+916
@@ -0,0 +1,916 @@
|
||||
import ForEach from "./ForEach.js";
|
||||
import forEachTextureInMaterial from "./forEachTextureInMaterial.js";
|
||||
import usesExtension from "./usesExtension.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 = 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--;
|
||||
}
|
||||
|
||||
const ext = primitive.extensions;
|
||||
if (
|
||||
defined(ext) &&
|
||||
defined(ext.CESIUM_primitive_outline) &&
|
||||
ext.CESIUM_primitive_outline.indices > accessorId
|
||||
) {
|
||||
--ext.CESIUM_primitive_outline.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--;
|
||||
}
|
||||
|
||||
const extensions = bufferView.extensions;
|
||||
if (defined(extensions)) {
|
||||
const ext = extensions.EXT_meshopt_compression;
|
||||
if (defined(ext) && ext.buffer > bufferId) {
|
||||
ext.buffer--;
|
||||
}
|
||||
const khr = extensions.KHR_meshopt_compression;
|
||||
if (defined(khr) && khr.buffer > bufferId) {
|
||||
khr.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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (usesExtension(gltf, "EXT_structural_metadata")) {
|
||||
const extension = gltf.extensions.EXT_structural_metadata;
|
||||
const propertyTables = extension.propertyTables;
|
||||
if (defined(propertyTables)) {
|
||||
const propertyTablesLength = propertyTables.length;
|
||||
for (let i = 0; i < propertyTablesLength; ++i) {
|
||||
const propertyTable = propertyTables[i];
|
||||
const properties = propertyTable.properties;
|
||||
for (const propertyId in properties) {
|
||||
if (properties.hasOwnProperty(propertyId)) {
|
||||
const property = properties[propertyId];
|
||||
if (defined(property.values) && property.values > bufferViewId) {
|
||||
property.values--;
|
||||
}
|
||||
if (
|
||||
defined(property.arrayOffsets) &&
|
||||
property.arrayOffsets > bufferViewId
|
||||
) {
|
||||
property.arrayOffsets--;
|
||||
}
|
||||
if (
|
||||
defined(property.stringOffsets) &&
|
||||
property.stringOffsets > bufferViewId
|
||||
) {
|
||||
property.stringOffsets--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (usesExtension(gltf, "EXT_mesh_features")) {
|
||||
ForEach.mesh(gltf, function (mesh) {
|
||||
ForEach.meshPrimitive(mesh, function (primitive) {
|
||||
const extensions = primitive.extensions;
|
||||
if (defined(extensions) && defined(extensions.EXT_mesh_features)) {
|
||||
const extension = extensions.EXT_mesh_features;
|
||||
const featureIds = extension.featureIds;
|
||||
if (defined(featureIds)) {
|
||||
const featureIdsLength = featureIds.length;
|
||||
for (let i = 0; i < featureIdsLength; ++i) {
|
||||
const featureId = featureIds[i];
|
||||
if (defined(featureId.texture)) {
|
||||
if (featureId.texture.index > textureId) {
|
||||
--featureId.texture.index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (usesExtension(gltf, "EXT_structural_metadata")) {
|
||||
const extension = gltf.extensions.EXT_structural_metadata;
|
||||
const propertyTextures = extension.propertyTextures;
|
||||
if (defined(propertyTextures)) {
|
||||
const propertyTexturesLength = propertyTextures.length;
|
||||
for (let i = 0; i < propertyTexturesLength; ++i) {
|
||||
const propertyTexture = propertyTextures[i];
|
||||
const properties = propertyTexture.properties;
|
||||
for (const propertyId in properties) {
|
||||
if (properties.hasOwnProperty(propertyId)) {
|
||||
const property = properties[propertyId];
|
||||
if (property.index > textureId) {
|
||||
--property.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;
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (usesExtension(gltf, "CESIUM_primitive_outline")) {
|
||||
ForEach.mesh(gltf, function (mesh) {
|
||||
ForEach.meshPrimitive(mesh, function (primitive) {
|
||||
const extensions = primitive.extensions;
|
||||
if (
|
||||
defined(extensions) &&
|
||||
defined(extensions.CESIUM_primitive_outline)
|
||||
) {
|
||||
const extension = extensions.CESIUM_primitive_outline;
|
||||
const indicesAccessorId = extension.indices;
|
||||
if (defined(indicesAccessorId)) {
|
||||
usedAccessorIds[indicesAccessorId] = 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;
|
||||
}
|
||||
|
||||
const extensions = bufferView.extensions;
|
||||
if (defined(extensions)) {
|
||||
const ext = extensions.EXT_meshopt_compression;
|
||||
if (defined(ext)) {
|
||||
usedBufferIds[ext.buffer] = true;
|
||||
}
|
||||
const khr = extensions.KHR_meshopt_compression;
|
||||
if (defined(khr)) {
|
||||
usedBufferIds[khr.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (usesExtension(gltf, "EXT_structural_metadata")) {
|
||||
const extension = gltf.extensions.EXT_structural_metadata;
|
||||
const propertyTables = extension.propertyTables;
|
||||
if (defined(propertyTables)) {
|
||||
const propertyTablesLength = propertyTables.length;
|
||||
for (let i = 0; i < propertyTablesLength; ++i) {
|
||||
const propertyTable = propertyTables[i];
|
||||
const properties = propertyTable.properties;
|
||||
for (const propertyId in properties) {
|
||||
if (properties.hasOwnProperty(propertyId)) {
|
||||
const property = properties[propertyId];
|
||||
if (defined(property.values)) {
|
||||
usedBufferViewIds[property.values] = true;
|
||||
}
|
||||
if (defined(property.arrayOffsets)) {
|
||||
usedBufferViewIds[property.arrayOffsets] = true;
|
||||
}
|
||||
if (defined(property.stringOffsets)) {
|
||||
usedBufferViewIds[property.stringOffsets] = 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (usesExtension(gltf, "EXT_mesh_features")) {
|
||||
ForEach.mesh(gltf, function (mesh) {
|
||||
ForEach.meshPrimitive(mesh, function (primitive) {
|
||||
const extensions = primitive.extensions;
|
||||
if (defined(extensions) && defined(extensions.EXT_mesh_features)) {
|
||||
const extension = extensions.EXT_mesh_features;
|
||||
const featureIds = extension.featureIds;
|
||||
if (defined(featureIds)) {
|
||||
const featureIdsLength = featureIds.length;
|
||||
for (let i = 0; i < featureIdsLength; ++i) {
|
||||
const featureId = featureIds[i];
|
||||
if (defined(featureId.texture)) {
|
||||
usedTextureIds[featureId.texture.index] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (usesExtension(gltf, "EXT_structural_metadata")) {
|
||||
const extension = gltf.extensions.EXT_structural_metadata;
|
||||
const propertyTextures = extension.propertyTextures;
|
||||
if (defined(propertyTextures)) {
|
||||
const propertyTexturesLength = propertyTextures.length;
|
||||
for (let i = 0; i < propertyTexturesLength; ++i) {
|
||||
const propertyTexture = propertyTextures[i];
|
||||
const properties = propertyTexture.properties;
|
||||
for (const propertyId in properties) {
|
||||
if (properties.hasOwnProperty(propertyId)) {
|
||||
const property = properties[propertyId];
|
||||
usedTextureIds[property.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;
|
||||
Generated
Vendored
+53
@@ -0,0 +1,53 @@
|
||||
import addBuffer from "./addBuffer.js";
|
||||
import ForEach from "./ForEach.js";
|
||||
import readAccessorPacked from "./readAccessorPacked.js";
|
||||
import ComponentDatatype from "../../Core/ComponentDatatype.js";
|
||||
import WebGLConstants from "../../Core/WebGLConstants.js";
|
||||
|
||||
/**
|
||||
* Update accessors referenced by JOINTS_0 and WEIGHTS_0 attributes to use correct component types.
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @returns {object} The glTF asset with compressed meshes.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function updateAccessorComponentTypes(gltf) {
|
||||
let componentType;
|
||||
ForEach.accessorWithSemantic(gltf, "JOINTS_0", function (accessorId) {
|
||||
const accessor = gltf.accessors[accessorId];
|
||||
componentType = accessor.componentType;
|
||||
if (componentType === WebGLConstants.BYTE) {
|
||||
convertType(gltf, accessor, ComponentDatatype.UNSIGNED_BYTE);
|
||||
} else if (
|
||||
componentType !== WebGLConstants.UNSIGNED_BYTE &&
|
||||
componentType !== WebGLConstants.UNSIGNED_SHORT
|
||||
) {
|
||||
convertType(gltf, accessor, ComponentDatatype.UNSIGNED_SHORT);
|
||||
}
|
||||
});
|
||||
ForEach.accessorWithSemantic(gltf, "WEIGHTS_0", function (accessorId) {
|
||||
const accessor = gltf.accessors[accessorId];
|
||||
componentType = accessor.componentType;
|
||||
if (componentType === WebGLConstants.BYTE) {
|
||||
convertType(gltf, accessor, ComponentDatatype.UNSIGNED_BYTE);
|
||||
} else if (componentType === WebGLConstants.SHORT) {
|
||||
convertType(gltf, accessor, ComponentDatatype.UNSIGNED_SHORT);
|
||||
}
|
||||
});
|
||||
|
||||
return gltf;
|
||||
}
|
||||
|
||||
function convertType(gltf, accessor, updatedComponentType) {
|
||||
const typedArray = ComponentDatatype.createTypedArray(
|
||||
updatedComponentType,
|
||||
readAccessorPacked(gltf, accessor),
|
||||
);
|
||||
const newBuffer = new Uint8Array(typedArray.buffer);
|
||||
accessor.bufferView = addBuffer(gltf, newBuffer);
|
||||
accessor.componentType = updatedComponentType;
|
||||
accessor.byteOffset = 0;
|
||||
}
|
||||
|
||||
export default updateAccessorComponentTypes;
|
||||
+1148
File diff suppressed because it is too large
Load Diff
+18
@@ -0,0 +1,18 @@
|
||||
import defined from "../../Core/defined.js";
|
||||
|
||||
/**
|
||||
* Checks whether the glTF uses the given extension.
|
||||
*
|
||||
* @param {object} gltf A javascript object containing a glTF asset.
|
||||
* @param {string} extension The name of the extension.
|
||||
* @returns {boolean} Whether the glTF uses the given extension.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function usesExtension(gltf, extension) {
|
||||
return (
|
||||
defined(gltf.extensionsUsed) && gltf.extensionsUsed.indexOf(extension) >= 0
|
||||
);
|
||||
}
|
||||
|
||||
export default usesExtension;
|
||||
Reference in New Issue
Block a user