UNPKG

@google/model-viewer

Version:

Easily display interactive 3D models on the web and in AR!

126 lines 5.19 kB
/* @license * Copyright 2021 Google LLC. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an 'AS IS' BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @param object {THREE.Object3D} * @return {boolean} */ const compatibleObject = (object) => { // @TODO: Need properer variantMaterials format validation? return object.material !== undefined && // easier than (!object.isMesh && !object.isLine && // !object.isPoints) object.userData && // just in case object.userData.variantMaterials && // Is this line costly? !!Array .from(object.userData.variantMaterials .values()) .filter(m => compatibleMaterial(m.material)); }; /** * @param material {THREE.Material} * @return {boolean} */ const compatibleMaterial = (material) => { // @TODO: support multi materials? return material && material.isMaterial && !Array.isArray(material); }; export default class GLTFExporterMaterialsVariantsExtension { constructor(writer) { this.writer = writer; this.name = 'KHR_materials_variants'; this.variantNames = []; } beforeParse(objects) { // Find all variant names and store them to the table const variantNameSet = new Set(); for (const object of objects) { object.traverse(o => { if (!compatibleObject(o)) { return; } const variantMaterials = o.userData.variantMaterials; const variantDataMap = o.userData.variantData; for (const [variantName, variantData] of variantDataMap) { const variantMaterial = variantMaterials.get(variantData.index); // Ignore unloaded variant materials if (variantMaterial && compatibleMaterial(variantMaterial.material)) { variantNameSet.add(variantName); } } }); } // We may want to sort? variantNameSet.forEach(name => this.variantNames.push(name)); } writeMesh(mesh, meshDef) { if (!compatibleObject(mesh)) { return; } const userData = mesh.userData; const variantMaterials = userData.variantMaterials; const variantDataMap = userData.variantData; const mappingTable = new Map(); // Removes gaps in the variant indices list (caused by deleting variants). const reIndexedVariants = new Map(); const variants = Array.from(variantDataMap.values()).sort((a, b) => { return a.index - b.index; }); for (const [i, variantData] of variants.entries()) { reIndexedVariants.set(variantData.index, i); } for (const variantData of variantDataMap.values()) { const variantInstance = variantMaterials.get(variantData.index); if (!variantInstance || !compatibleMaterial(variantInstance.material)) { continue; } const materialIndex = this.writer.processMaterial(variantInstance.material); if (!mappingTable.has(materialIndex)) { mappingTable.set(materialIndex, { material: materialIndex, variants: [] }); } mappingTable.get(materialIndex).variants.push(reIndexedVariants.get(variantData.index)); } const mappingsDef = Array.from(mappingTable.values()) .map((m => { return m.variants.sort((a, b) => a - b) && m; })) .sort((a, b) => a.material - b.material); if (mappingsDef.length === 0) { return; } const originalMaterialIndex = compatibleMaterial(userData.originalMaterial) ? this.writer.processMaterial(userData.originalMaterial) : -1; for (const primitiveDef of meshDef.primitives) { // Override primitiveDef.material with original material. if (originalMaterialIndex >= 0) { primitiveDef.material = originalMaterialIndex; } primitiveDef.extensions = primitiveDef.extensions || {}; primitiveDef.extensions[this.name] = { mappings: mappingsDef }; } } afterParse() { if (this.variantNames.length === 0) { return; } const root = this.writer.json; root.extensions = root.extensions || {}; const variantsDef = this.variantNames.map(n => { return { name: n }; }); root.extensions[this.name] = { variants: variantsDef }; this.writer.extensionsUsed[this.name] = true; } } //# sourceMappingURL=VariantMaterialExporterPlugin.js.map