diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 7c1adeac963..5fb156698b2 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -38,6 +38,10 @@ #include "visual_shader_particle_nodes.h" #include "visual_shader_sdf_nodes.h" +#ifdef MODULE_REGEX_ENABLED +#include "modules/regex/regex.h" +#endif // MODULE_REGEX_ENABLED + String make_unique_id(VisualShader::Type p_type, int p_id, const String &p_name) { static const char *typepf[VisualShader::TYPE_MAX] = { "vtx", "frg", "lgt", "start", "process", "collide", "start_custom", "process_custom", "sky", "fog" }; return p_name + "_" + String(typepf[p_type]) + "_" + itos(p_id); @@ -381,6 +385,10 @@ String VisualShaderNode::generate_global_per_func(Shader::Mode p_mode, VisualSha return String(); } +String VisualShaderNode::generate_global_per_func_multi(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return String(); +} + Vector VisualShaderNode::get_editable_properties() const { return Vector(); } @@ -2018,6 +2026,11 @@ Error VisualShader::_write_node(Type type, StringBuilder *p_global_code, StringB } r_classes.insert(class_name); } + for (int i = 0; i < TYPE_MAX; i++) { + if (p_global_code_per_func) { + (*p_global_code_per_func)[Type(i)] += vsnode->generate_global_per_func_multi(get_mode(), Type(i), p_node); + } + } } if (!vsnode->is_code_generated()) { // just generate globals and ignore locals @@ -4334,6 +4347,35 @@ String VisualShaderNodeParameter::get_warning(Shader::Mode p_mode, VisualShader: return String(); } +int VisualShaderNodeParameter::get_index() const { +#ifdef MODULE_REGEX_ENABLED + RegEx regex = RegEx("\\d+$"); + Ref match = regex.search(parameter_name); + if (match.is_null()) { + return 0; + } + return match->get_strings()[0].to_int(); +#else + String buffer; + for (int i = 0; i < parameter_name.length(); i++) { + int index = parameter_name.length() - i - 1; + String ch = parameter_name.substr(index, 1); + + if (ch.is_valid_int()) { + buffer += ch; + } else { + break; + } + } + + if (buffer.is_empty()) { + return 0; + } + + return buffer.reverse().to_int(); +#endif +} + Vector VisualShaderNodeParameter::get_editable_properties() const { Vector props; props.push_back("qualifier"); diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 8ec52fcaaa0..3f7d4087d8f 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -377,6 +377,7 @@ public: virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const; virtual String generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; + virtual String generate_global_per_func_multi(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; // If no output is connected, the output var passed will be empty. If no input is connected and input is NIL, the input var passed will be empty. virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const = 0; @@ -626,6 +627,8 @@ public: virtual bool is_qualifier_supported(Qualifier p_qual) const = 0; virtual bool is_convertible_to_constant() const = 0; + int get_index() const; + virtual Vector get_editable_properties() const override; virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override; diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index 3db1ab93380..f216ce4471a 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -6758,34 +6758,34 @@ String VisualShaderNodeTextureParameterTriplanar::generate_global_per_node(Shade String code; code += "// " + get_caption() + "\n"; - code += " vec4 triplanar_texture(sampler2D p_sampler, vec3 p_weights, vec3 p_triplanar_pos) {\n"; - code += " vec4 samp = vec4(0.0);\n"; - code += " samp += texture(p_sampler, p_triplanar_pos.xy) * p_weights.z;\n"; - code += " samp += texture(p_sampler, p_triplanar_pos.xz) * p_weights.y;\n"; - code += " samp += texture(p_sampler, p_triplanar_pos.zy * vec2(-1.0, 1.0)) * p_weights.x;\n"; - code += " return samp;\n"; - code += " }\n"; - code += "\n"; - code += " uniform vec3 triplanar_scale = vec3(1.0, 1.0, 1.0);\n"; - code += " uniform vec3 triplanar_offset;\n"; - code += " uniform float triplanar_sharpness = 0.5;\n"; - code += "\n"; - code += " varying vec3 triplanar_power_normal;\n"; - code += " varying vec3 triplanar_pos;\n"; + code += "vec4 triplanar_texture(sampler2D p_sampler, vec3 p_weights, vec3 p_triplanar_pos) {\n"; + code += " vec4 samp = vec4(0.0);\n"; + code += " samp += texture(p_sampler, p_triplanar_pos.xy) * p_weights.z;\n"; + code += " samp += texture(p_sampler, p_triplanar_pos.xz) * p_weights.y;\n"; + code += " samp += texture(p_sampler, p_triplanar_pos.zy * vec2(-1.0, 1.0)) * p_weights.x;\n"; + code += " return samp;\n"; + code += "}\n"; return code; } -String VisualShaderNodeTextureParameterTriplanar::generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { +String VisualShaderNodeTextureParameterTriplanar::generate_global_per_func_multi(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code; if (p_type == VisualShader::TYPE_VERTEX) { + int index = get_index(); + + String index_string; + if (index > 0) { + index_string = itos(index); + } + code += "// " + get_caption() + "\n"; code += " {\n"; - code += " triplanar_power_normal = pow(abs(NORMAL), vec3(triplanar_sharpness));\n"; - code += " triplanar_power_normal /= dot(triplanar_power_normal, vec3(1.0));\n"; - code += " triplanar_pos = VERTEX * triplanar_scale + triplanar_offset;\n"; - code += " triplanar_pos *= vec3(1.0, -1.0, 1.0);\n"; + code += vformat(" triplanar_power_normal%s = pow(abs(NORMAL), vec3(triplanar_sharpness%s));\n", index_string, index_string); + code += vformat(" triplanar_power_normal%s /= dot(triplanar_power_normal%s, vec3(1.0));\n", index_string, index_string); + code += vformat(" triplanar_pos%s = VERTEX * triplanar_scale%s + triplanar_offset%s;\n", index_string, index_string, index_string); + code += vformat(" triplanar_pos%s *= vec3(1.0, -1.0, 1.0);\n", index_string); code += " }\n"; } @@ -6794,21 +6794,42 @@ String VisualShaderNodeTextureParameterTriplanar::generate_global_per_func(Shade String VisualShaderNodeTextureParameterTriplanar::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code = _get_qual_str() + "uniform sampler2D " + get_parameter_name(); + int index = get_index(); + code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source); code += ";\n"; + + String index_string; + if (index > 0) { + index_string = itos(index); + } + + code += vformat("uniform vec3 triplanar_scale%s = vec3(1.0, 1.0, 1.0);\n", index_string); + code += vformat("uniform vec3 triplanar_offset%s;\n", index_string); + code += vformat("uniform float triplanar_sharpness%s = 0.5;\n", index_string); + code += vformat("varying vec3 triplanar_power_normal%s;\n", index_string); + code += vformat("varying vec3 triplanar_pos%s;\n", index_string); + code += "\n"; + return code; } String VisualShaderNodeTextureParameterTriplanar::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String id = get_parameter_name(); + int index = get_index(); + + String index_string; + if (index > 0) { + index_string = itos(index); + } String code; if (p_input_vars[0].is_empty() && p_input_vars[1].is_empty()) { - code += " " + p_output_vars[0] + " = triplanar_texture(" + id + ", triplanar_power_normal, triplanar_pos);\n"; + code += " " + p_output_vars[0] + " = triplanar_texture(" + id + vformat(", triplanar_power_normal%s, triplanar_pos%s);\n", index_string, index_string); } else if (!p_input_vars[0].is_empty() && p_input_vars[1].is_empty()) { - code += " " + p_output_vars[0] + " = triplanar_texture(" + id + ", " + p_input_vars[0] + ", triplanar_pos);\n"; + code += " " + p_output_vars[0] + " = triplanar_texture(" + id + ", " + p_input_vars[0] + vformat(", triplanar_pos%s);\n", index_string); } else if (p_input_vars[0].is_empty() && !p_input_vars[1].is_empty()) { - code += " " + p_output_vars[0] + " = triplanar_texture(" + id + ", triplanar_power_normal, " + p_input_vars[1] + ");\n"; + code += " " + p_output_vars[0] + " = triplanar_texture(" + id + vformat(", triplanar_power_normal%s, ", index_string) + p_input_vars[1] + ");\n"; } else { code += " " + p_output_vars[0] + " = triplanar_texture(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 67dc8f73537..4d2cd7b8efc 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -2625,7 +2625,7 @@ public: virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const override; - virtual String generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + virtual String generate_global_per_func_multi(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;