UNPKG

nanogl-gltf

Version:
137 lines (136 loc) 4.71 kB
import GltfTypes from "../types/GltfTypes"; function invokeMaterialFactory(factory, ctx) { if (factory instanceof Function) { return factory(ctx); } return factory; } function invokePassFactory(factory, ctx, material) { if (factory instanceof Function) { return factory(ctx, material); } return factory; } /** * IMaterial which directly return it's material in `createMaterialForPrimitive()` implementation * used to implement `MaterialOverrideExtension.overrideMaterial()` */ class OverrideMaterial { constructor(materialFactory, data) { this.materialFactory = materialFactory; this.data = data; this.gltftype = GltfTypes.MATERIAL; } createMaterialForPrimitive(gltf, node, primitive) { return invokeMaterialFactory(this.materialFactory, { data: this.data, gltf, node, primitive }); } parse(gltfLoader, data) { return null; } } class MaterialOverrideExtensionInstance { constructor(gltfLoader, ext) { this.ext = ext; this.name = 'material_override'; this.priority = 10; this.loader = gltfLoader; } acceptElement(data, element) { if (data.gltftype === GltfTypes.MATERIAL) { return this.createOverridePassMaterial(data, element); } return null; } loadElement(data) { if (data.gltftype === GltfTypes.MATERIAL) { return this.createOverrideMaterial(data); } return null; } createOverrideMaterial(data) { const materialFactory = this.ext.materials.get(data.name) || this.ext.materials.get(''); if (materialFactory !== undefined) { const el = new OverrideMaterial(materialFactory, data); return Promise.resolve(el); } return null; } /** * overwrite `createMaterialForPrimitive()` method of original material so it will return the given pass */ createOverridePassMaterial(data, material) { const passFactory = this.ext.passes.get(data.name) || this.ext.passes.get(''); if (passFactory !== undefined) { const baseFunc = material.createMaterialForPrimitive; material.createMaterialForPrimitive = (gltf, node, primitive) => { const m = baseFunc.apply(material, [gltf, node, primitive]); const pass = invokePassFactory(passFactory, { data, gltf, node, primitive }, m); if (pass) { m.addPass(pass); } return m; }; } return null; } } /** * This extension allows all materials and their passes to be overriden by custom code at load time. * Useful to add custom shading, completely replace a material, add Chunk effect to every materials of a GLTF, ... */ export default class MaterialOverrideExtension { constructor() { this.name = 'material_override'; /** * Map of material override factories */ this.materials = new Map(); /** * Map of pass override factories */ this.passes = new Map(); } /** * Add Material Override. * Gltf material with the given name will be replaced by the one created by the given material factory * @param name The name of the gltf material to override, if empty string the given material will be used as default override * @param m Material factory to use to create the override material */ overrideMaterial(name, m) { this.assertNotExist(name); this.materials.set(name, m); } /** * Add Pass Override. * The Color pass of the overriden material will be replaced by the one created by the given pass factory * @param name The name of the material to override, if empty string is given, the pass will be applied to all materials * @param p Pass factory to use to create the override pass */ overridePass(name, p) { this.assertNotExist(name); this.passes.set(name, p); } /** * Check that the given name is not already used by a material or pass override * @param name Material or pass name to check */ assertNotExist(name) { if (this.materials.has(name)) throw `material override for "${name}" already exist`; if (this.passes.has(name)) throw `pass override for "${name}" already exist`; } createInstance(gltfLoader) { return new MaterialOverrideExtensionInstance(gltfLoader, this); } }