polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
116 lines (107 loc) • 4.19 kB
text/typescript
import {BasePersistedConfig} from '../../../../utils/PersistedConfig';
import {BaseBuilderMatNodeType} from '../../../../mat/_BaseBuilder';
import {CustomMaterialName} from './_BaseMaterial';
import {ShaderMaterialWithCustomMaterials} from '../../../../../../core/geometry/Material';
import {IUniformsWithTime, IUniformsWithResolution} from '../../../../../scene/utils/UniformsController';
import {GlParamConfig} from '../../utils/ParamConfig';
import {Poly} from '../../../../../Poly';
import {PolyDictionary} from '../../../../../../types/GlobalTypes';
export interface PersistedConfigBaseMaterialData {
material: object;
param_uniform_pairs: [string, string][];
uniforms_time_dependent?: boolean;
uniforms_resolution_dependent?: boolean;
custom_materials?: PolyDictionary<object>;
}
// potential bug with Material Loader
// - 1. a uniform with a mat3, such as uvTransform, will be reloaded with a mat4
// - 2. the boolean lights property is not saved
// - 3. if a color property is added on the material itself, it should not be saved
// - 4. for the volume shader, a uniform with an array of vector can be saved, but not loaded again as a vector (but only as an {x,y,z} object)
export class MaterialPersistedConfig extends BasePersistedConfig {
private _material: ShaderMaterialWithCustomMaterials | undefined;
constructor(protected node: BaseBuilderMatNodeType) {
super(node);
}
toJSON(): PersistedConfigBaseMaterialData | undefined {
const assemblerController = this.node.assemblerController;
if (!assemblerController) {
return;
}
// custom materials
const custom_materials_data: PolyDictionary<object> = {};
const custom_materials = this.node.material.custom_materials;
if (custom_materials) {
const custom_material_names: CustomMaterialName[] = Object.keys(custom_materials) as CustomMaterialName[];
for (let name of custom_material_names) {
const custom_material = custom_materials[name];
if (custom_material) {
custom_materials_data[name] = this._material_to_json(custom_material);
}
}
}
// params updating uniforms
const param_uniform_pairs: [string, string][] = [];
const param_configs = assemblerController.assembler.param_configs();
for (let param_config of param_configs) {
param_uniform_pairs.push([param_config.name(), param_config.uniform_name]);
}
const data = {
material: this._material_to_json(this.node.material),
uniforms_time_dependent: assemblerController.assembler.uniforms_time_dependent(),
uniforms_resolution_dependent: assemblerController.assembler.resolution_dependent(),
param_uniform_pairs: param_uniform_pairs,
custom_materials: custom_materials_data,
};
return data;
}
load(data: PersistedConfigBaseMaterialData) {
this._material = this._load_material(data.material);
if (!this._material) {
return;
}
this._material.custom_materials = this._material.custom_materials || {};
if (data.custom_materials) {
const names: CustomMaterialName[] = Object.keys(data.custom_materials) as CustomMaterialName[];
for (let name of names) {
const custom_mat_data = data.custom_materials[name];
const custom_mat = this._load_material(custom_mat_data);
if (custom_mat) {
this._material.custom_materials[name] = custom_mat;
}
}
}
if (data.uniforms_time_dependent) {
this.node
.scene()
.uniforms_controller.add_time_dependent_uniform_owner(
this._material.uuid,
this._material.uniforms as IUniformsWithTime
);
}
if (data.uniforms_resolution_dependent) {
this.node
.scene()
.uniforms_controller.add_resolution_dependent_uniform_owner(
this._material.uuid,
this._material.uniforms as IUniformsWithResolution
);
}
if (data.param_uniform_pairs) {
for (let pair of data.param_uniform_pairs) {
const param = this.node.params.get(pair[0]);
const uniform = this._material.uniforms[pair[1]];
if (param && uniform) {
param.options.set_option('callback', () => {
GlParamConfig.callback(param, uniform);
});
}
}
}
}
material(): ShaderMaterialWithCustomMaterials | undefined {
if (Poly.playerMode()) {
return this._material;
}
}
}