UNPKG

polygonjs-engine

Version:

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

389 lines (388 loc) 13.1 kB
import {Vector2 as Vector22} from "three/src/math/Vector2"; import {LineType as LineType2} from "../utils/LineType"; import {ShaderConfig as ShaderConfig2} from "../configs/ShaderConfig"; import {VariableConfig as VariableConfig2} from "../configs/VariableConfig"; import {CodeBuilder as CodeBuilder2} from "../utils/CodeBuilder"; import {GlobalsGeometryHandler} from "../globals/Geometry"; import {TypedAssembler} from "../../../utils/shaders/BaseAssembler"; import {ShaderName as ShaderName2} from "../../../utils/shaders/ShaderName"; import {OutputGlNode} from "../../Output"; import {GlConnectionPoint, GlConnectionPointType} from "../../../utils/io/connections/Gl"; import {GlobalsGlNode} from "../../Globals"; import {AttributeGlNode} from "../../Attribute"; import {ParamGlNode} from "../../Param"; import {ShaderChunk as ShaderChunk2} from "three/src/renderers/shaders/ShaderChunk"; import {TypedNodeTraverser} from "../../../utils/shaders/NodeTraverser"; import {GlNodeFinder} from "../utils/NodeFinder"; import {VaryingWriteGlNode} from "../../VaryingWrite"; const INSERT_DEFINE_AFTER_MAP = new Map([ [ShaderName2.VERTEX, "#include <common>"], [ShaderName2.FRAGMENT, "#include <common>"] ]); const INSERT_BODY_AFTER_MAP = new Map([ [ShaderName2.VERTEX, "#include <color_vertex>"], [ShaderName2.FRAGMENT, "vec4 diffuseColor = vec4( diffuse, opacity );"] ]); const LINES_TO_REMOVE_MAP = new Map([ [ShaderName2.VERTEX, ["#include <begin_vertex>", "#include <beginnormal_vertex>"]], [ShaderName2.FRAGMENT, []] ]); const SPACED_LINES = 3; export class BaseGlShaderAssembler extends TypedAssembler { constructor(_gl_parent_node) { super(); this._gl_parent_node = _gl_parent_node; this._shaders_by_name = new Map(); this._lines = new Map(); this._root_nodes = []; this._leaf_nodes = []; this._uniforms_time_dependent = false; this._resolution_dependent = false; } compile() { } _template_shader_for_shader_name(shader_name) { switch (shader_name) { case ShaderName2.VERTEX: return this._template_shader?.vertexShader; case ShaderName2.FRAGMENT: return this._template_shader?.fragmentShader; } } get globals_handler() { return this._gl_parent_node.assemblerController?.globals_handler; } compile_allowed() { return this._gl_parent_node.assemblerController?.globals_handler != null; } shaders_by_name() { return this._shaders_by_name; } _build_lines() { for (let shader_name of this.shader_names) { const template = this._template_shader_for_shader_name(shader_name); if (template) { this._replace_template(template, shader_name); } } } set_root_nodes(root_nodes) { this._root_nodes = root_nodes; } get _template_shader() { return void 0; } add_uniforms(current_uniforms) { for (let param_config of this.param_configs()) { current_uniforms[param_config.uniform_name] = param_config.uniform; } if (this.uniforms_time_dependent()) { current_uniforms["time"] = { value: this._gl_parent_node.scene().time() }; } if (this.resolution_dependent()) { current_uniforms["resolution"] = { value: new Vector22(1e3, 1e3) }; } } 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 ParamGlNode.type(): { list.push(node); break; } case AttributeGlNode.type(): { } case VaryingWriteGlNode.type(): { 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(): { } } } return list; } set_node_lines_globals(globals_node, shaders_collection_controller) { } set_node_lines_output(output_node, shaders_collection_controller) { } set_node_lines_attribute(attribute_node, shaders_collection_controller) { } get code_builder() { return this._code_builder = this._code_builder || this._create_code_builder(); } _create_code_builder() { 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); }); return new CodeBuilder2(node_traverser, (shader_name) => { return this.root_nodes_by_shader_name(shader_name); }); } build_code_from_nodes(root_nodes) { const param_nodes = GlNodeFinder.find_param_generating_nodes(this._gl_parent_node); this.code_builder.build_from_nodes(root_nodes, param_nodes); } allow_new_param_configs() { this.code_builder.allow_new_param_configs(); } disallow_new_param_configs() { this.code_builder.disallow_new_param_configs(); } builder_param_configs() { return this.code_builder.param_configs(); } builder_lines(shader_name, line_type) { return this.code_builder.lines(shader_name, line_type); } all_builder_lines() { return this.code_builder.all_lines(); } param_configs() { const code_builder = this._param_config_owner || this.code_builder; return code_builder.param_configs(); } set_param_configs_owner(param_config_owner) { this._param_config_owner = param_config_owner; if (this._param_config_owner) { this.code_builder.disallow_new_param_configs(); } else { this.code_builder.allow_new_param_configs(); } } static output_input_connection_points() { return [ new GlConnectionPoint("position", GlConnectionPointType.VEC3), new GlConnectionPoint("normal", GlConnectionPointType.VEC3), new GlConnectionPoint("color", GlConnectionPointType.VEC3), new GlConnectionPoint("alpha", GlConnectionPointType.FLOAT), new GlConnectionPoint("uv", GlConnectionPointType.VEC2) ]; } add_output_inputs(output_child) { output_child.io.inputs.setNamedInputConnectionPoints(BaseGlShaderAssembler.output_input_connection_points()); } static create_globals_node_output_connections() { return [ new GlConnectionPoint("position", GlConnectionPointType.VEC3), new GlConnectionPoint("normal", GlConnectionPointType.VEC3), new GlConnectionPoint("color", GlConnectionPointType.VEC3), new GlConnectionPoint("uv", GlConnectionPointType.VEC2), new GlConnectionPoint("mvPosition", GlConnectionPointType.VEC4), new GlConnectionPoint("gl_Position", GlConnectionPointType.VEC4), new GlConnectionPoint("gl_FragCoord", GlConnectionPointType.VEC4), new GlConnectionPoint("cameraPosition", GlConnectionPointType.VEC3), new GlConnectionPoint("resolution", GlConnectionPointType.VEC2), new GlConnectionPoint("time", GlConnectionPointType.FLOAT) ]; } create_globals_node_output_connections() { return BaseGlShaderAssembler.create_globals_node_output_connections(); } add_globals_outputs(globals_node) { globals_node.io.outputs.setNamedOutputConnectionPoints(this.create_globals_node_output_connections()); } allow_attribute_exports() { return false; } reset_configs() { this._reset_shader_configs(); this._reset_variable_configs(); this._reset_uniforms_time_dependency(); this._reset_resolution_dependency(); } get shader_configs() { return this._shader_configs = this._shader_configs || this.create_shader_configs(); } set_shader_configs(shader_configs) { this._shader_configs = shader_configs; } get shader_names() { return this.shader_configs?.map((sc) => sc.name()) || []; } _reset_shader_configs() { this._shader_configs = void 0; } create_shader_configs() { return [ new ShaderConfig2(ShaderName2.VERTEX, ["position", "normal", "uv", VaryingWriteGlNode.INPUT_NAME], []), new ShaderConfig2(ShaderName2.FRAGMENT, ["color", "alpha"], [ShaderName2.VERTEX]) ]; } shader_config(name) { return this.shader_configs?.filter((sc) => { return sc.name() == name; })[0]; } variable_configs() { return this._variable_configs = this._variable_configs || this.create_variable_configs(); } set_variable_configs(variable_configs) { this._variable_configs = variable_configs; } variable_config(name) { return this.variable_configs().filter((vc) => { return vc.name() == name; })[0]; } static create_variable_configs() { return [ new VariableConfig2("position", { default_from_attribute: true, prefix: "vec3 transformed = " }), new VariableConfig2("normal", { default_from_attribute: true, prefix: "vec3 objectNormal = " }), new VariableConfig2("color", { prefix: "diffuseColor.xyz = " }), new VariableConfig2("alpha", { prefix: "diffuseColor.a = " }), new VariableConfig2("uv", { prefix: "vUv = ", if: GlobalsGeometryHandler.IF_RULE.uv }) ]; } create_variable_configs() { return BaseGlShaderAssembler.create_variable_configs(); } _reset_variable_configs() { this._variable_configs = void 0; this.variable_configs(); } input_names_for_shader_name(root_node, shader_name) { return this.shader_config(shader_name)?.input_names() || []; } _reset_uniforms_time_dependency() { this._uniforms_time_dependent = false; } set_uniforms_time_dependent() { this._uniforms_time_dependent = true; } uniforms_time_dependent() { return this._uniforms_time_dependent; } _reset_resolution_dependency() { this._resolution_dependent = false; } set_resolution_dependent() { this._resolution_dependent = true; } resolution_dependent() { return this._resolution_dependent; } insert_define_after(shader_name) { return INSERT_DEFINE_AFTER_MAP.get(shader_name); } insert_body_after(shader_name) { return INSERT_BODY_AFTER_MAP.get(shader_name); } lines_to_remove(shader_name) { return LINES_TO_REMOVE_MAP.get(shader_name); } _replace_template(template, shader_name) { const function_declaration = this.builder_lines(shader_name, LineType2.FUNCTION_DECLARATION); const define = this.builder_lines(shader_name, LineType2.DEFINE); const body = this.builder_lines(shader_name, LineType2.BODY); let template_lines = template.split("\n"); const new_lines = []; const line_before_define = this.insert_define_after(shader_name); const line_before_body = this.insert_body_after(shader_name); const lines_to_remove = this.lines_to_remove(shader_name); let line_before_define_found = false; let line_before_body_found = false; for (let template_line of template_lines) { if (line_before_define_found == true) { if (function_declaration) { this._insert_lines(new_lines, function_declaration); } if (define) { this._insert_lines(new_lines, define); } line_before_define_found = false; } if (line_before_body_found == true) { if (body) { this._insert_lines(new_lines, body); } line_before_body_found = false; } let line_remove_required = false; if (lines_to_remove) { for (let line_to_remove of lines_to_remove) { if (template_line.indexOf(line_to_remove) >= 0) { line_remove_required = true; } } } if (!line_remove_required) { new_lines.push(template_line); } else { new_lines.push("// removed:"); new_lines.push(`//${template_line}`); } if (line_before_define && template_line.indexOf(line_before_define) >= 0) { line_before_define_found = true; } if (line_before_body && template_line.indexOf(line_before_body) >= 0) { line_before_body_found = true; } } this._lines.set(shader_name, new_lines); } _insert_lines(new_lines, lines_to_add) { if (lines_to_add.length > 0) { for (let i = 0; i < SPACED_LINES; i++) { new_lines.push(""); } for (let line_to_add of lines_to_add) { new_lines.push(line_to_add); } for (let i = 0; i < SPACED_LINES; i++) { new_lines.push(""); } } } get_custom_materials() { return new Map(); } expand_shader(shader_string) { function parseIncludes(string) { var pattern = /^[ \t]*#include +<([\w\d./]+)>/gm; function replace(match, include) { var replace2 = ShaderChunk2[include]; if (replace2 === void 0) { throw new Error("Can not resolve #include <" + include + ">"); } return parseIncludes(replace2); } return string.replace(pattern, replace); } return parseIncludes(shader_string); } }