@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
251 lines (243 loc) • 8.19 kB
text/typescript
/**
* Update a scene before some passes are rendered
*
* @remarks
* The node can also be provided a second input, which has to be an UpdateScene post node.
* This node will then be able to reset the changes made by this node.
*
*/
import {TypedPostNode, TypedPostNodeContext, PostParamOptions} from './_Base';
import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig';
import {isBooleanTrue} from '../../../core/Type';
import {BaseNodeType} from '../_Base';
import {Mesh, Material, MeshBasicMaterial, Color} from 'three';
import {UpdateScenePass} from './utils/effects/UpdateScenePass';
import {CoreObjectType, ObjectContent} from '../../../core/geometry/ObjectContent';
import {PostType} from '../../poly/registers/nodes/types/Post';
const MATTE_MATERIAL = new MeshBasicMaterial({color: new Color(0, 0, 0)});
// function _effectFromPass(effectPass: EffectPass): UpdateScenePass | undefined {
// const effect = (effectPass as any).effects[0];
// if (effect instanceof UpdateScenePass) {
// return effect;
// }
// }
class UpdateScenePostParamsConfig extends NodeParamsConfig {
/** @param reset */
reset = ParamConfig.BOOLEAN(0, {
...PostParamOptions,
});
/** @param objects Mask */
objectsMask = ParamConfig.STRING('*', {
...PostParamOptions,
visibleIf: {reset: 0},
objectMask: true,
});
/** @param invertMask */
invertMask = ParamConfig.BOOLEAN(0, {
...PostParamOptions,
visibleIf: {reset: 0},
});
/** @param prints which objects are targeted by this node, for debugging */
// printFoundObjectsFromMask = ParamConfig.BUTTON(null, {
// visibleIf: {reset: 0},
// callback: (node: BaseNodeType) => {
// UpdateScenePostNode.PARAM_CALLBACK_printResolve(node as UpdateScenePostNode);
// },
// });
/** @param update selected objects material to a matte one */
setMatteMaterial = ParamConfig.BOOLEAN(1, {
...PostParamOptions,
visibleIf: {reset: 0},
separatorBefore: true,
});
/** @param set visible state */
setVisible = ParamConfig.BOOLEAN(0, {
...PostParamOptions,
visibleIf: {reset: 0},
separatorBefore: true,
});
/** @param set visible state */
visible = ParamConfig.BOOLEAN(0, {
...PostParamOptions,
visibleIf: {reset: 0, setVisible: 1},
});
/** @param reset */
resetChanges = ParamConfig.BUTTON(null, {
visibleIf: {reset: 0},
callback: (node: BaseNodeType) => {
UpdateScenePostNode.PARAM_CALLBACK_resetChanges(node as UpdateScenePostNode);
},
separatorBefore: true,
});
/** @param material */
// material = ParamConfig.NODE_PATH('', {
// ...PostParamOptions,
// visibleIf: {overrideMaterial: 1},
// nodeSelection: {
// context: NodeContext.MAT,
// },
// callback: (node: BaseNodeType) => {
// UpdateScenePostNode.PARAM_CALLBACK_updatePassesMaterial(node as UpdateScenePostNode);
// },
// });
}
const ParamsConfig = new UpdateScenePostParamsConfig();
export class UpdateScenePostNode extends TypedPostNode<UpdateScenePass, UpdateScenePostParamsConfig> {
override paramsConfig = ParamsConfig;
static override type() {
return PostType.UPDATE_SCENE;
}
override initializeNode() {
super.initializeNode();
this.io.inputs.setCount(0, 2);
}
override createPass(context: TypedPostNodeContext) {
const pass = new UpdateScenePass({
// scene: this.scene(),
node: this,
reset: isBooleanTrue(this.pv.reset),
nodeToReset: this._nodeToReset(context),
// objectsMask: this.pv.objectsMask,
// invertMask: isBooleanTrue(this.pv.invertMask),
// setMatteMaterial: isBooleanTrue(this.pv.setMatteMaterial),
// setVisible: isBooleanTrue(this.pv.setVisible),
// visible: isBooleanTrue(this.pv.visible),
});
// const pass = new EffectPass(context.camera, effect);
this.updatePass(pass);
return pass;
}
override updatePass(pass: UpdateScenePass) {
// const effect = _effectFromPass(pass);
// if (!effect) {
// return;
// }
// pass.reset = isBooleanTrue(this.pv.reset);
// effect.objectsMask = this.pv.objectsMask;
// effect.invertMask = isBooleanTrue(this.pv.invertMask);
// effect.setMatteMaterial = isBooleanTrue(this.pv.setMatteMaterial);
// effect.setVisible = isBooleanTrue(this.pv.setVisible);
// effect.visible = isBooleanTrue(this.pv.visible);
}
private _nodeToReset(context: TypedPostNodeContext): UpdateScenePostNode | undefined {
const input2 = this.io.inputs.input(1);
if (!input2) {
return;
}
if (input2 instanceof UpdateScenePostNode) {
return input2;
// const pass = context.composerController.passByNodeInBuildPassesProcess(input2) as EffectPass | undefined; //input2.passesByRequester(requester);
// console.log(pass, pass ? _effectFromPass(pass) : undefined);
// return pass ? _effectFromPass(pass) : undefined;
}
}
// static PARAM_CALLBACK_printResolve(node: UpdateScenePostNode) {
// node._printResolve();
// }
// private _printResolve() {
// let firstPass: EffectPass | undefined;
// this._passesByEffectsComposer.forEach((passOrPasses) => {
// const passes = isArray(passOrPasses) ? passOrPasses : [passOrPasses];
// firstPass = firstPass || passes[0];
// });
// if (firstPass) {
// const effect = _effectFromPass(firstPass);
// if (effect) {
// console.log(hhis.objectsList());
// }
// } else {
// console.error(`no pass generated by this node, maybe it has not rendered yet?`);
// }
// }
static PARAM_CALLBACK_resetChanges(node: UpdateScenePostNode) {
node.resetChanges();
}
// private _resetMat() {
// this._passesByEffectsComposer.forEach((passOrPasses) => {
// const passes = isArray(passOrPasses) ? passOrPasses : [passOrPasses];
// for (let pass of passes) {
// const effect = _effectFromPass(pass);
// if (effect) {
// effect.resetChanges();
// }
// }
// });
// }
// static PARAM_CALLBACK_updatePassesMaterial(node: UpdateScenePostNode) {
// node._updatePassesMaterial();
// }
// private _updatePassesMaterial() {
// const matNode = this.pv.material.nodeWithContext(NodeContext.MAT);
// if (!matNode) {
// this._passes_by_requester_id.forEach((pass) => {
// pass.material = undefined;
// });
// } else {
// const mat = matNode.material;
// this._passes_by_requester_id.forEach((pass) => {
// pass.material = mat;
// });
// }
// }
private _objectsList: ObjectContent<CoreObjectType>[] = [];
objectsList() {
return this._objectsList;
}
private _materialByMesh: Map<Mesh, Material | Material[]> = new Map();
// private _parentByObject: Map<Object3D, Object3D | null> = new Map();
private _visibleByObject: Map<ObjectContent<CoreObjectType>, boolean> = new Map();
applyChanges() {
const changeNeeded = isBooleanTrue(this.pv.setMatteMaterial) || isBooleanTrue(this.pv.setVisible);
if (changeNeeded) {
this._objectsList.length = 0;
const mask = this.pv.objectsMask;
this._scene.objectsController.traverseObjectsWithMask(
mask,
this._updateObjectBound,
undefined,
this.pv.invertMask
);
}
}
resetChanges() {
// reset mat
this._materialByMesh.forEach((mat, mesh) => {
mesh.material = mat;
});
this._materialByMesh.clear();
// reset visibility
// this._parentByObject.forEach((parent, obj) => {
// parent?.add(obj);
// });
// this._parentByObject.clear();
this._visibleByObject.forEach((visible, obj) => {
obj.visible = visible;
});
this._visibleByObject.clear();
}
private _updateObjectBound = this._updateObject.bind(this);
private _updateObject(obj: ObjectContent<CoreObjectType>) {
this._objectsList.push(obj);
if (isBooleanTrue(this.pv.setMatteMaterial)) {
const mesh = obj as Mesh;
if (mesh.material) {
this._materialByMesh.set(mesh, mesh.material);
mesh.material = MATTE_MATERIAL;
}
}
if (isBooleanTrue(this.pv.setVisible)) {
const visible = this.pv.visible;
// const parent = obj.parent;
// const hasParent = parent != null;
if (obj.visible != visible) {
// this._parentByObject.set(obj, parent);
// obj.removeFromParent();
// obj.parent = null;
// console.log('remove parent', obj);
this._visibleByObject.set(obj, obj.visible);
obj.visible = visible;
// console.log(obj, obj.visible);
}
}
}
}