UNPKG

polygonjs-engine

Version:

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

226 lines (225 loc) 9.64 kB
import {BaseGlShaderAssembler} from "../_Base"; import TemplateDefault from "../../templates/particles/Default.glsl"; import {AttributeGlNode} from "../../../Attribute"; import {TextureAllocationsController as TextureAllocationsController2} from "../../utils/TextureAllocationsController"; import {ThreeToGl as ThreeToGl2} from "../../../../../../core/ThreeToGl"; import {GlobalsGlNode} from "../../../Globals"; import {TypedNodeTraverser} from "../../../../utils/shaders/NodeTraverser"; import {OutputGlNode} from "../../../Output"; import {GlConnectionPointType, GlConnectionPoint} from "../../../../utils/io/connections/Gl"; import {UniformGLDefinition} from "../../../utils/GLDefinition"; export class ShaderAssemblerParticles extends BaseGlShaderAssembler { get _template_shader() { return void 0; } _template_shader_for_shader_name(shader_name) { return TemplateDefault; } compile() { this.setup_shader_names_and_variables(); this.update_shaders(); } root_nodes_by_shader_name(shader_name) { const list = []; for (let node of this._root_nodes) { switch (node.type()) { case OutputGlNode.type(): { list.push(node); break; } case AttributeGlNode.type(): { const attrib_name = node.attribute_name; const variable = this._texture_allocations_controller?.variable(attrib_name); if (variable && variable.allocation) { const allocation_shader_name = variable.allocation.shader_name; if (allocation_shader_name == shader_name) { list.push(node); } } break; } } } return list; } leaf_nodes_by_shader_name(shader_name) { const list = []; for (let node of this._leaf_nodes) { switch (node.type()) { case GlobalsGlNode.type(): { list.push(node); break; } case AttributeGlNode.type(): { const attrib_name = node.attribute_name; const variable = this._texture_allocations_controller?.variable(attrib_name); if (variable && variable.allocation) { const allocation_shader_name = variable.allocation.shader_name; if (allocation_shader_name == shader_name) { list.push(node); } } break; } } } return list; } setup_shader_names_and_variables() { const node_traverser = new TypedNodeTraverser(this._gl_parent_node, this.shader_names, (root_node, shader_name) => { return this.input_names_for_shader_name(root_node, shader_name); }); this._leaf_nodes = node_traverser.leaves_from_nodes(this._root_nodes); this._texture_allocations_controller = new TextureAllocationsController2(); this._texture_allocations_controller.allocate_connections_from_root_nodes(this._root_nodes, this._leaf_nodes); if (this.globals_handler) { this.globals_handler?.set_texture_allocations_controller(this._texture_allocations_controller); } this._reset_shader_configs(); } update_shaders() { this._shaders_by_name = new Map(); this._lines = new Map(); for (let shader_name of this.shader_names) { const template = this._template_shader_for_shader_name(shader_name); this._lines.set(shader_name, template.split("\n")); } if (this._root_nodes.length > 0) { this.build_code_from_nodes(this._root_nodes); this._build_lines(); } for (let shader_name of this.shader_names) { const lines = this._lines.get(shader_name); if (lines) { this._shaders_by_name.set(shader_name, lines.join("\n")); } } } add_output_inputs(output_child) { output_child.io.inputs.setNamedInputConnectionPoints([ new GlConnectionPoint("position", GlConnectionPointType.VEC3), new GlConnectionPoint("velocity", GlConnectionPointType.VEC3) ]); } add_globals_outputs(globals_node) { globals_node.io.outputs.setNamedOutputConnectionPoints([ new GlConnectionPoint("position", GlConnectionPointType.VEC3), new GlConnectionPoint("velocity", GlConnectionPointType.VEC3), new GlConnectionPoint("time", GlConnectionPointType.FLOAT) ]); } allow_attribute_exports() { return true; } get texture_allocations_controller() { return this._texture_allocations_controller = this._texture_allocations_controller || new TextureAllocationsController2(); } create_shader_configs() { return this._texture_allocations_controller?.create_shader_configs() || []; } create_variable_configs() { return []; } get shader_names() { return this.texture_allocations_controller.shader_names() || []; } input_names_for_shader_name(root_node, shader_name) { return this.texture_allocations_controller.input_names_for_shader_name(root_node, shader_name) || []; } insert_define_after(shader_name) { return "// INSERT DEFINE"; } insert_body_after(shader_name) { return "// INSERT BODY"; } lines_to_remove(shader_name) { return ["// INSERT DEFINE", "// INSERT BODY"]; } add_export_body_line(export_node, input_name, input, variable_name, shaders_collection_controller) { if (input) { const var_input = export_node.variable_for_input(input_name); const new_var = ThreeToGl2.vector3(var_input); if (new_var) { const texture_variable = this.texture_allocations_controller.variable(variable_name); const shader_name = shaders_collection_controller.current_shader_name; if (texture_variable && texture_variable.allocation?.shader_name == shader_name) { const component = texture_variable.component; const line = `gl_FragColor.${component} = ${new_var}`; shaders_collection_controller.add_body_lines(export_node, [line], shader_name); } } } } set_node_lines_output(output_node, shaders_collection_controller) { const shader_name = shaders_collection_controller.current_shader_name; const input_names = this.texture_allocations_controller.input_names_for_shader_name(output_node, shader_name); if (input_names) { for (let input_name of input_names) { const input = output_node.io.inputs.named_input(input_name); if (input) { const variable_name = input_name; this.add_export_body_line(output_node, input_name, input, variable_name, shaders_collection_controller); } else { } } } } set_node_lines_attribute(attribute_node, shaders_collection_controller) { if (attribute_node.is_importing) { const gl_type = attribute_node.gl_type(); const attribute_name = attribute_node.attribute_name; const new_value = this.globals_handler?.read_attribute(attribute_node, gl_type, attribute_name, shaders_collection_controller); const var_name = attribute_node.gl_var_name(attribute_node.output_name); const body_line = `${gl_type} ${var_name} = ${new_value}`; shaders_collection_controller.add_body_lines(attribute_node, [body_line]); const texture_variable = this.texture_allocations_controller.variable(attribute_name); const shader_name = shaders_collection_controller.current_shader_name; if (texture_variable && texture_variable.allocation?.shader_name == shader_name) { const variable = this.texture_allocations_controller.variable(attribute_name); if (variable) { const component = variable.component; const body_line2 = `gl_FragColor.${component} = ${var_name}`; shaders_collection_controller.add_body_lines(attribute_node, [body_line2]); } } } if (attribute_node.is_exporting) { const input = attribute_node.connected_input_node(); if (input) { const variable_name = attribute_node.attribute_name; this.add_export_body_line(attribute_node, attribute_node.input_name, input, variable_name, shaders_collection_controller); } } } set_node_lines_globals(globals_node, shaders_collection_controller) { for (let output_name of globals_node.io.outputs.used_output_names()) { switch (output_name) { case "time": this._handle_globals_time(globals_node, output_name, shaders_collection_controller); break; default: this._handle_globals_default(globals_node, output_name, shaders_collection_controller); } } } _handle_globals_time(globals_node, output_name, shaders_collection_controller) { const definition = new UniformGLDefinition(globals_node, GlConnectionPointType.FLOAT, output_name); shaders_collection_controller.add_definitions(globals_node, [definition]); const var_name = globals_node.gl_var_name(output_name); const body_line = `float ${var_name} = ${output_name}`; shaders_collection_controller.add_body_lines(globals_node, [body_line]); this.set_uniforms_time_dependent(); } _handle_globals_default(globals_node, output_name, shaders_collection_controller) { const output_connection_point = globals_node.io.outputs.named_output_connection_points_by_name(output_name); if (output_connection_point) { const gl_type = output_connection_point.type(); const attrib_read = this.globals_handler?.read_attribute(globals_node, gl_type, output_name, shaders_collection_controller); if (attrib_read) { const var_name = globals_node.gl_var_name(output_name); const body_line = `${gl_type} ${var_name} = ${attrib_read}`; shaders_collection_controller.add_body_lines(globals_node, [body_line]); } } } }