@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
214 lines (213 loc) • 7.97 kB
JavaScript
"use strict";
import { TypedSopNode } from "./_Base";
import { GlobalsTextureHandler, GlobalsTextureHandlerPurpose } from "../gl/code/globals/Texture";
import { InputCloneMode } from "../../poly/InputCloneMode";
import { NodeContext } from "../../poly/NodeContext";
import { CoreParticlesAttribute } from "../../../core/particles/CoreParticlesAttribute";
import {
createOrFindParticlesController,
disposeParticlesFromNode,
setParticleRenderer
} from "../../../core/particles/CoreParticles";
import { PARTICLE_DATA_TYPES } from "../../../core/particles/CoreParticlesGpuComputeController";
import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig";
import { GlNodeFinder } from "../gl/code/utils/NodeFinder";
import { AssemblerName } from "../../poly/registers/assemblers/_BaseRegister";
import { Poly } from "../../Poly";
import { ParticlesPersistedConfig } from "../gl/code/assemblers/particles/ParticlesPersistedConfig";
import { SopType } from "../../poly/registers/nodes/types/Sop";
import { ParticlesSystemGpuAttributesSopOperation } from "../../operations/sop/ParticlesSystemGpuAttributes";
import { ParticlesSystemGpuMaterialSopOperation } from "../../operations/sop/ParticlesSystemGpuMaterial";
import { CoreMask } from "../../../core/geometry/Mask";
const DEFAULT = ParticlesSystemGpuAttributesSopOperation.DEFAULT_PARAMS;
class ParticlesSystemGpuSopParamsConfig extends NodeParamsConfig {
constructor() {
super(...arguments);
/** @param group to assign the material to */
this.group = ParamConfig.STRING(DEFAULT.group, {
objectMask: true
});
/** @param data type used by the solver */
this.dataType = ParamConfig.INTEGER(0, {
menu: {
entries: PARTICLE_DATA_TYPES.map((value, index) => {
return { value: index, name: value };
})
}
});
/** @param number of frames to run before scene plays */
this.preRollFramesCount = ParamConfig.INTEGER(0, {
range: [0, 100],
rangeLocked: [true, false]
});
/** @param material used to render the particles */
this.material = ParamConfig.NODE_PATH("", {
// separatorBefore: true,
nodeSelection: {
context: NodeContext.MAT
},
dependentOnFoundNode: false,
separatorAfter: true
});
}
}
const ParamsConfig = new ParticlesSystemGpuSopParamsConfig();
export class ParticlesSystemGpuSopNode extends TypedSopNode {
constructor() {
super(...arguments);
this.paramsConfig = ParamsConfig;
this._assemblerController = this._createAssemblerController();
this.persisted_config = new ParticlesPersistedConfig(this);
this._particlesGlobalsHandler = new GlobalsTextureHandler(
GlobalsTextureHandler.PARTICLE_SIM_UV,
GlobalsTextureHandlerPurpose.PARTICLES_SHADER
);
this._shadersByName = /* @__PURE__ */ new Map();
this._childrenControllerContext = NodeContext.GL;
}
static type() {
return SopType.PARTICLES_SYSTEM_GPU;
}
dispose() {
disposeParticlesFromNode(this);
super.dispose();
}
assemblerController() {
return this._assemblerController;
}
usedAssembler() {
return AssemblerName.GL_PARTICLES;
}
_createAssemblerController() {
return Poly.assemblersRegister.assembler(this, this.usedAssembler());
}
shadersByName() {
return this._shadersByName;
}
static requireWebGL2() {
return true;
}
initializeNode() {
this.io.inputs.setCount(1);
this.io.inputs.initInputsClonedState(InputCloneMode.ALWAYS);
}
createNode(node_class, options) {
return super.createNode(node_class, options);
}
children() {
return super.children();
}
nodesByType(type) {
return super.nodesByType(type);
}
childrenAllowed() {
if (this.assemblerController()) {
return super.childrenAllowed();
}
return false;
}
sceneReadonly() {
return this.assemblerController() == null;
}
async cook(inputCoreGroups) {
this._operation = this._operation || {
attributes: new ParticlesSystemGpuAttributesSopOperation(this._scene, this.states, this),
material: new ParticlesSystemGpuMaterialSopOperation(this._scene, this.states, this)
};
this.compileIfRequired();
const coreGroup = inputCoreGroups[0];
const selectedObjects = CoreMask.filterThreejsObjects(coreGroup, this.pv);
for (const object of selectedObjects) {
const existingActorIds = this.scene().actorsManager.objectActorNodeIds(object);
if (existingActorIds == null || existingActorIds.length == 0) {
this.states.error.set(`the input objects requires an actor node assigned to it`);
return;
}
}
const renderer = await this.scene().renderersRegister.waitForRenderer();
if (!renderer) {
this.states.error.set(`no renderer found`);
return;
}
for (const object of selectedObjects) {
Poly.onObjectsAddRemoveHooks.assignOnAddHookHandler(object, this);
setParticleRenderer(this.graphNodeId(), renderer);
CoreParticlesAttribute.setParticlesNodeId(object, this.graphNodeId());
CoreParticlesAttribute.setDataType(object, this.pv.dataType);
CoreParticlesAttribute.setPreRollFramesCount(object, this.pv.preRollFramesCount);
}
this._operation.attributes.cook(inputCoreGroups, this.pv);
await this._operation.material.cook(inputCoreGroups, this.pv);
this.setObjects(selectedObjects);
}
updateObjectOnAdd(object) {
const particlesNodeId = CoreParticlesAttribute.getParticlesNodeId(object);
if (particlesNodeId == null) {
return;
}
if (particlesNodeId != this.graphNodeId()) {
return;
}
createOrFindParticlesController(object, this.scene());
}
compileIfRequired() {
var _a;
if ((_a = this.assemblerController()) == null ? void 0 : _a.compileRequired()) {
try {
this.run_assembler();
} catch (err) {
const message = err.message || "failed to compile";
this.states.error.set(message);
}
}
}
run_assembler() {
const assemblerController = this.assemblerController();
if (!assemblerController) {
return;
}
const exportNodes = this._findExportNodes();
if (exportNodes.length > 0) {
const rootNodes = exportNodes.concat(GlNodeFinder.findAjacencyNodes(this));
assemblerController.setAssemblerGlobalsHandler(this._particlesGlobalsHandler);
assemblerController.assembler.set_root_nodes(rootNodes);
assemblerController.assembler.compile();
assemblerController.post_compile();
}
const shadersByName = assemblerController.assembler.shaders_by_name();
this._setShaderNames(shadersByName);
}
_setShaderNames(shadersByName) {
this._shadersByName = shadersByName;
}
init_with_persisted_config() {
const shaders_by_name = this.persisted_config.shaders_by_name();
const texture_allocations_controller = this.persisted_config.texture_allocations_controller();
if (shaders_by_name && texture_allocations_controller) {
this._setShaderNames(shaders_by_name);
}
}
initCoreParticlesControllerFromPersistedConfig(coreParticlesController) {
const shaders_by_name = this.persisted_config.shaders_by_name();
const texture_allocations_controller = this.persisted_config.texture_allocations_controller();
if (shaders_by_name && texture_allocations_controller) {
coreParticlesController.setPersistedTextureAllocationController(texture_allocations_controller);
}
}
_findExportNodes() {
const nodes = GlNodeFinder.findAttributeExportNodes(this);
const outputNodes = GlNodeFinder.findOutputNodes(this);
if (outputNodes.length == 0) {
this.states.error.set("one output node is required");
}
if (outputNodes.length > 1) {
this.states.error.set("only one output node is allowed");
return [];
}
const outputNode = outputNodes[0];
if (outputNode) {
nodes.push(outputNode);
}
return nodes;
}
}