nanogl-gltf
Version:
137 lines (136 loc) • 4.71 kB
JavaScript
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);
}
}