TilesRenderer: Add shader "chaining" logic for adding and removing visualizations layers
Right now "visualizations" are added via on before compile which makes it difficult to add multiple visualizations on top of eachother and clean up when a plugin is removed (see fade, topo, overlays, user shaders, etc). This also makes users or plugins replacing shaders more difficult to deal with since we don't know when they're added or removed. A built in chaining / material mixin registration system would allow this to work more cleanly.
tiles.registerMaterialLayer( {
uniforms: {},
defines: {},
onBeforeCompile: () => {},
customCacheKey: () => {},
name: 'TOPO_MATERIAL_LAYER',
order: 0,
} );
tiles.unregisterMaterialLayer( layer );
Node materials will likely also need a similar kind of mechanism.
Implementation concept
// wrap the material with the given stack of effects
const stack = new LayerStack( [ ... ] );
const handler = new MaterialExtender( material, stack );
// allow for modification of the wrapped material
handler.setStack( ... );
handler.setDefine( ... );
handler.getUniforms( ... );
handler.needsUpdate = true;
// remove stack and reset the material
handler.dispose();
// initial class
export class MaterialLayerStack {
constructor( layers = [] ) {
this.layers = [ ...layers ];
}
add( info ) {
this.layers.push( info );
}
delete( info ) {
const index = this.layers.indexOf( info );
if ( index !== - 1 ) {
this.layers.splice( index, 1 );
}
}
sort() {
this.layers.sort( ( a, b ) => {
return a.order - b.order;
} );
}
}
export class MaterialExtender {
constructor( material, stack ) {
if (
material.onBeforeCompile !== Material.prototype.onBeforeCompile ||
material.customProgramCacheKey !== Material.prototype.customProgramCacheKey
) {
throw new Error();
}
this.stack = stack;
this.material = material;
this.uniforms = {};
this.defines = {};
// TODO: wrap the material callbacks
}
dispose() {
material.onBeforeCompile = Material.prototype.onBeforeCompile;
material.customProgramCacheKey = Material.prototype.customProgramCacheKey;
}
}
Threepipe has a similar material extension system, you can have a look incase it might be useful to check as reference, its mostly standalone and provides helpers for different usecases - https://github.com/repalash/threepipe/blob/master/src/materials/MaterialExtension.ts and https://github.com/repalash/threepipe/blob/master/src/materials/MaterialExtender.ts