UNPKG

@polygonjs/polygonjs

Version:

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

184 lines (183 loc) 5.86 kB
"use strict"; import { TypedPostNode, PostParamOptions } from "./_Base"; import { EffectPass } from "postprocessing"; import { BuilderEffect } from "./utils/BuilderEffect"; import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig"; import { GlobalsGeometryHandler } from "../gl/code/globals/Geometry"; import { GlNodeFinder } from "../gl/code/utils/NodeFinder"; import { Poly } from "../../Poly"; import { AssemblerName } from "./../../poly/registers/assemblers/_BaseRegister"; import { PostPersistedConfig } from "./../gl/code/assemblers/post/PostPersistedConfig"; import { PostType } from "./../../poly/registers/nodes/types/Post"; import defaultFragmentShader from "./gl/builder.glsl"; import { NodeContext } from "../../poly/NodeContext"; class BuilderPostParamsConfig extends NodeParamsConfig { constructor() { super(...arguments); /** @param effect amount */ this.useInput1OuputBuffer = ParamConfig.BOOLEAN(1, { ...PostParamOptions }); } } const ParamsConfig = new BuilderPostParamsConfig(); export class BuilderPostNode extends TypedPostNode { constructor() { super(...arguments); this.paramsConfig = ParamsConfig; this.persisted_config = new PostPersistedConfig(this); this._assemblerController = this._createAssemblerController(); this._childrenControllerContext = NodeContext.GL; // private _cook_main_without_inputs_when_dirty_bound = this._cook_main_without_inputs_when_dirty.bind(this); // private async _cook_main_without_inputs_when_dirty() { // await this.cookController.cookMainWithoutInputs(); // } // override cook() { // this.compileIfRequired(); // this.cookController.endCook(); // } /** * * FRAGMENT SHADER UPDATE * */ this._fragmentShader = defaultFragmentShader; this._uniforms = {}; } static type() { return PostType.BUILDER; } usedAssembler() { return AssemblerName.GL_POST; } _createAssemblerController() { const assemblerController = Poly.assemblersRegister.assembler(this, this.usedAssembler()); if (assemblerController) { const globalsHandler = new GlobalsGeometryHandler(); assemblerController.setAssemblerGlobalsHandler(globalsHandler); return assemblerController; } } assemblerController() { return this._assemblerController; } initializeNode() { super.initializeNode(); this.io.inputs.setCount(0, 2); this.addPostDirtyHook("_cook_main_without_inputs_when_dirty", () => { this.compileIfRequired(); }); } 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; } fragmentShader() { return this._fragmentShader; } setFragmentShader(fragmentShader) { this._fragmentShader = fragmentShader; this._updatePasses(); } uniforms() { return this._uniforms; } setUniforms(uniforms) { this._uniforms = uniforms; this._updatePasses(); } shaders_by_name() { return { fragment: this._fragmentShader }; } compileIfRequired() { var _a; if ((_a = this.assemblerController()) == null ? void 0 : _a.compileRequired()) { try { this.compile(); } catch (err) { const message = err.message || "failed to compile"; this.states.error.set(message); } } } compile() { const assemblerController = this.assemblerController(); if (!assemblerController) { return; } const outputNodes = GlNodeFinder.findOutputNodes(this); if (outputNodes.length == 0) { this.states.error.set("one output node is required"); return; } if (outputNodes.length > 1) { this.states.error.set("only one output node allowed"); return; } const outputNode = outputNodes[0]; if (outputNode) { const rootNodes = outputNodes; assemblerController.assembler.set_root_nodes(rootNodes); assemblerController.assembler.updateFragmentShader(); const fragmentShader = assemblerController.assembler.fragment_shader(); const uniforms = assemblerController.assembler.uniforms(); if (fragmentShader && uniforms) { this._fragmentShader = fragmentShader; this._uniforms = uniforms; } BuilderPostNode.handleDependencies(this, assemblerController.assembler.uniformsTimeDependent()); } if (this._fragmentShader && this._uniforms) { this._updatePasses(); } assemblerController.post_compile(); } static handleDependencies(node, timeDependent, uniforms) { } /** * * PASS CREATE / UPDATE * */ createPass(context) { this.compileIfRequired(); const composerInput1 = this._createEffectComposer(context); composerInput1.autoRenderToScreen = false; const clonedContextInput1 = { ...context }; clonedContextInput1.composer = composerInput1; this._addPassFromInput(1, clonedContextInput1); const effect = new BuilderEffect(composerInput1, { fragmentShader: this._fragmentShader, useOutputBuffer: this.pv.useInput1OuputBuffer }); const pass = new EffectPass(context.camera, effect); this.updatePass(pass); return pass; } updatePass(pass) { const effect = pass.effects[0]; effect.updateUniforms(this._uniforms); effect.updateFragmentShader(this._fragmentShader); pass.fullscreenMaterial.needsUpdate = true; } _createEffectComposer(context) { const parentNode = this._postProcessNetworkNode(); return parentNode.effectsComposerController.createEffectsComposer(context); } }