UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

214 lines (213 loc) 7.97 kB
"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; } }