UNPKG

polygonjs-engine

Version:

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

191 lines (190 loc) 6.87 kB
import {TypedSopNode} from "./_Base"; import {GlobalsTextureHandler} from "../gl/code/globals/Texture"; import {InputCloneMode as InputCloneMode2} from "../../poly/InputCloneMode"; import {NodeContext as NodeContext2} from "../../poly/NodeContext"; import {ParticlesSystemGpuRenderController} from "./utils/ParticlesSystemGPU/RenderController"; import { ParticlesSystemGpuComputeController, PARTICLE_DATA_TYPES } from "./utils/ParticlesSystemGPU/GPUComputeController"; import {NodeParamsConfig, ParamConfig} from "../utils/params/ParamsConfig"; import {GlNodeFinder} from "../gl/code/utils/NodeFinder"; import {AssemblerName} from "../../poly/registers/assemblers/_BaseRegister"; import {Poly as Poly2} from "../../Poly"; import {ParticlesPersistedConfig} from "../gl/code/assemblers/particles/PersistedConfig"; class ParticlesSystemGpuSopParamsConfig extends NodeParamsConfig { constructor() { super(...arguments); this.startFrame = ParamConfig.FLOAT(1, {range: [1, 100]}); this.autoTexturesSize = ParamConfig.BOOLEAN(1); this.maxTexturesSize = ParamConfig.VECTOR2([1024, 1024], {visibleIf: {autoTexturesSize: 1}}); this.texturesSize = ParamConfig.VECTOR2([64, 64], {visibleIf: {autoTexturesSize: 0}}); this.dataType = ParamConfig.INTEGER(0, { menu: { entries: PARTICLE_DATA_TYPES.map((value, index) => { return {value: index, name: value}; }) } }); this.reset = ParamConfig.BUTTON(null, { callback: (node, param) => { ParticlesSystemGpuSopNode.PARAM_CALLBACK_reset(node); } }); this.material = ParamConfig.OPERATOR_PATH("", { nodeSelection: { context: NodeContext2.MAT }, dependentOnFoundNode: false }); } } const ParamsConfig2 = new ParticlesSystemGpuSopParamsConfig(); export class ParticlesSystemGpuSopNode extends TypedSopNode { constructor() { super(...arguments); this.params_config = ParamsConfig2; this._assembler_controller = this._create_assembler_controller(); this.persisted_config = new ParticlesPersistedConfig(this); this.globals_handler = new GlobalsTextureHandler(GlobalsTextureHandler.PARTICLE_SIM_UV); this._shaders_by_name = new Map(); this.gpu_controller = new ParticlesSystemGpuComputeController(this); this.render_controller = new ParticlesSystemGpuRenderController(this); this._reset_material_if_dirty_bound = this._reset_material_if_dirty.bind(this); this._children_controller_context = NodeContext2.GL; } static type() { return "particlesSystemGpu"; } dispose() { super.dispose(); this.gpu_controller.dispose(); } get assemblerController() { return this._assembler_controller; } usedAssembler() { return AssemblerName.GL_PARTICLES; } _create_assembler_controller() { return Poly2.assemblersRegister.assembler(this, this.usedAssembler()); } shaders_by_name() { return this._shaders_by_name; } static require_webgl2() { return true; } static PARAM_CALLBACK_reset(node) { node.PARAM_CALLBACK_reset(); } PARAM_CALLBACK_reset() { this.gpu_controller.reset_gpu_compute_and_set_dirty(); } static displayedInputNames() { return ["points to emit particles from"]; } initializeNode() { this.io.inputs.setCount(1); this.io.inputs.initInputsClonedState(InputCloneMode2.NEVER); this.addPostDirtyHook("_reset_material_if_dirty", this._reset_material_if_dirty_bound); } createNode(node_class, params_init_value_overrides) { return super.createNode(node_class, params_init_value_overrides); } children() { return super.children(); } nodesByType(type) { return super.nodesByType(type); } childrenAllowed() { if (this.assemblerController) { return super.childrenAllowed(); } this.scene().markAsReadOnly(this); return false; } async _reset_material_if_dirty() { if (this.p.material.isDirty()) { this.render_controller.reset_render_material(); if (!this.is_on_frame_start()) { await this.render_controller.init_render_material(); } } } is_on_frame_start() { return this.scene().frame() == this.pv.startFrame; } async cook(input_contents) { this.gpu_controller.set_restart_not_required(); const core_group = input_contents[0]; this.compile_if_required(); if (this.is_on_frame_start()) { this.gpu_controller.reset_particle_groups(); } if (!this.gpu_controller.initialized) { await this.gpu_controller.init(core_group); } if (!this.render_controller.initialized) { this.render_controller.init_core_group(core_group); await this.render_controller.init_render_material(); } this.gpu_controller.restart_simulation_if_required(); this.gpu_controller.compute_similation_if_required(); if (this.is_on_frame_start()) { this.setCoreGroup(core_group); } else { this.cookController.end_cook(); } } async compile_if_required() { if (this.assemblerController?.compile_required()) { await this.run_assembler(); } } async run_assembler() { const assemblerController = this.assemblerController; if (!assemblerController) { return; } const export_nodes = this._find_export_nodes(); if (export_nodes.length > 0) { const root_nodes = export_nodes; assemblerController.set_assembler_globals_handler(this.globals_handler); assemblerController.assembler.set_root_nodes(root_nodes); assemblerController.assembler.compile(); assemblerController.post_compile(); } const shaders_by_name = assemblerController.assembler.shaders_by_name(); this._set_shader_names(shaders_by_name); } _set_shader_names(shaders_by_name) { this._shaders_by_name = shaders_by_name; this.gpu_controller.set_shaders_by_name(this._shaders_by_name); this.render_controller.set_shaders_by_name(this._shaders_by_name); this.gpu_controller.reset_gpu_compute(); this.gpu_controller.reset_particle_groups(); } 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._set_shader_names(shaders_by_name); this.gpu_controller.set_persisted_texture_allocation_controller(texture_allocations_controller); } } _find_export_nodes() { const nodes = GlNodeFinder.find_attribute_export_nodes(this); const output_nodes = GlNodeFinder.find_output_nodes(this); if (output_nodes.length > 1) { this.states.error.set("only one output node is allowed"); return []; } const output_node = output_nodes[0]; if (output_node) { nodes.push(output_node); } return nodes; } }