From 027014464480c596055e9846c13264e58540ee0a Mon Sep 17 00:00:00 2001 From: Yuri Roubinsky Date: Thu, 18 Nov 2021 13:30:51 +0300 Subject: [PATCH] Enchance `VisualShaderNodeMeshEmitter`, add more ports and fix bugs --- scene/resources/visual_shader.cpp | 1 + .../visual_shader_particle_nodes.cpp | 299 +++++++++++++----- .../resources/visual_shader_particle_nodes.h | 14 +- 3 files changed, 235 insertions(+), 79 deletions(-) diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 0bdc81330e3..87ff225de92 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -1835,6 +1835,7 @@ void VisualShader::_update_shader() const { code += " float __scalar_buff1;\n"; code += " float __scalar_buff2;\n"; code += " int __scalar_ibuff;\n"; + code += " vec4 __vec4_buff;\n"; code += " vec3 __ndiff = normalize(__diff);\n\n"; } if (has_start) { diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp index 7dd4eed15be..1a829968e3c 100644 --- a/scene/resources/visual_shader_particle_nodes.cpp +++ b/scene/resources/visual_shader_particle_nodes.cpp @@ -264,7 +264,7 @@ String VisualShaderNodeParticleMeshEmitter::get_caption() const { } int VisualShaderNodeParticleMeshEmitter::get_output_port_count() const { - return 2; + return 6; } VisualShaderNodeParticleBoxEmitter::PortType VisualShaderNodeParticleMeshEmitter::get_output_port_type(int p_port) const { @@ -273,6 +273,14 @@ VisualShaderNodeParticleBoxEmitter::PortType VisualShaderNodeParticleMeshEmitter return PORT_TYPE_VECTOR; // position case 1: return PORT_TYPE_VECTOR; // normal + case 2: + return PORT_TYPE_VECTOR; // color + case 3: + return PORT_TYPE_SCALAR; // alpha + case 4: + return PORT_TYPE_VECTOR; // uv + case 5: + return PORT_TYPE_VECTOR; // uv2 } return PORT_TYPE_SCALAR; } @@ -283,6 +291,14 @@ String VisualShaderNodeParticleMeshEmitter::get_output_port_name(int p_port) con return "position"; case 1: return "normal"; + case 2: + return "color"; + case 3: + return "alpha"; + case 4: + return "uv"; + case 5: + return "uv2"; } return String(); } @@ -299,135 +315,263 @@ String VisualShaderNodeParticleMeshEmitter::get_input_port_name(int p_port) cons return String(); } -String VisualShaderNodeParticleMeshEmitter::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { +String VisualShaderNodeParticleMeshEmitter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code; if (mesh.is_valid()) { - code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_vx") + ";\n"; - code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_nm") + ";\n"; + if (is_output_port_connected(0)) { // position + code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_vx") + ";\n"; + } + + if (is_output_port_connected(1)) { // normal + code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_nm") + ";\n"; + } + + if (is_output_port_connected(2) || is_output_port_connected(3)) { // color & alpha + code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_col") + ";\n"; + } + + if (is_output_port_connected(4)) { // uv + code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_uv") + ";\n"; + } + + if (is_output_port_connected(5)) { // uv2 + code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_uv2") + ";\n"; + } } return code; } +String VisualShaderNodeParticleMeshEmitter::_generate_code(VisualShader::Type p_type, int p_id, const String *p_output_vars, int p_index, const String &p_texture_name, bool p_ignore_mode2d) const { + String code; + if (is_output_port_connected(p_index)) { + if (mode_2d && !p_ignore_mode2d) { + code += " " + p_output_vars[p_index] + " = vec3("; + code += "texelFetch("; + code += make_unique_id(p_type, p_id, p_texture_name) + ", "; + code += "ivec2(__scalar_ibuff, 0), 0).xy, 0.0);\n"; + } else { + code += " " + p_output_vars[p_index] + " = texelFetch("; + code += make_unique_id(p_type, p_id, p_texture_name) + ", "; + code += "ivec2(__scalar_ibuff, 0), 0).xyz;\n"; + } + } + return code; +} + String VisualShaderNodeParticleMeshEmitter::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 code; - code += " __scalar_ibuff = int(__rand_from_seed(__seed) * 65535.0) % " + itos(position_texture->get_width()) + ";\n"; - if (position_texture->get_width() == 0) { - code += " " + p_output_vars[0] + " = vec3(0.0);\n"; - } else { - if (mode_2d) { - code += " " + p_output_vars[0] + " = vec3("; - code += "texelFetch("; - code += make_unique_id(p_type, p_id, "mesh_vx") + ", "; - code += "ivec2(__scalar_ibuff, 0), 0).xy, 0.0);\n"; + code += _generate_code(p_type, p_id, p_output_vars, 0, "mesh_vx"); + code += _generate_code(p_type, p_id, p_output_vars, 1, "mesh_nm"); + + if (is_output_port_connected(2) || is_output_port_connected(3)) { + code += " __vec4_buff = texelFetch("; + code += make_unique_id(p_type, p_id, "mesh_col") + ", "; + code += "ivec2(__scalar_ibuff, 0), 0);\n"; + if (is_output_port_connected(2)) { + code += " " + p_output_vars[2] + " = __vec4_buff.rgb;\n"; } else { - code += " " + p_output_vars[0] + " = texelFetch("; - code += make_unique_id(p_type, p_id, "mesh_vx") + ", "; - code += "ivec2(__scalar_ibuff, 0), 0).xyz;\n"; + code += " " + p_output_vars[2] + " = vec3(0.0);\n"; + } + if (is_output_port_connected(3)) { + code += " " + p_output_vars[3] + " = __vec4_buff.a;\n"; + } else { + code += " " + p_output_vars[3] + " = 0.0;\n"; } } - if (normal_texture->get_width() == 0) { - code += " " + p_output_vars[1] + " = vec3(0.0);\n"; - } else { - if (mode_2d) { - code += " " + p_output_vars[1] + " = vec3("; - code += "texelFetch("; - code += make_unique_id(p_type, p_id, "mesh_nm") + ", "; - code += "ivec2(__scalar_ibuff, 0), 0).xy, 0.0);\n"; - } else { - code += " " + p_output_vars[1] + " = texelFetch("; - code += make_unique_id(p_type, p_id, "mesh_nm") + ", "; - code += "ivec2(__scalar_ibuff, 0), 0).xyz;\n"; - } - } + code += _generate_code(p_type, p_id, p_output_vars, 4, "mesh_uv", true); + code += _generate_code(p_type, p_id, p_output_vars, 5, "mesh_uv2", true); return code; } Vector VisualShaderNodeParticleMeshEmitter::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { - VisualShader::DefaultTextureParam dtp_vx; - dtp_vx.name = make_unique_id(p_type, p_id, "mesh_vx"); - dtp_vx.params.push_back(position_texture); - - VisualShader::DefaultTextureParam dtp_nm; - dtp_nm.name = make_unique_id(p_type, p_id, "mesh_nm"); - dtp_nm.params.push_back(normal_texture); - Vector ret; - ret.push_back(dtp_vx); - ret.push_back(dtp_nm); + + if (is_output_port_connected(0)) { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "mesh_vx"); + dtp.params.push_back(position_texture); + ret.push_back(dtp); + } + + if (is_output_port_connected(1)) { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "mesh_nm"); + dtp.params.push_back(normal_texture); + ret.push_back(dtp); + } + + if (is_output_port_connected(2) || is_output_port_connected(3)) { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "mesh_col"); + dtp.params.push_back(color_texture); + ret.push_back(dtp); + } + + if (is_output_port_connected(4)) { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "mesh_uv"); + dtp.params.push_back(uv_texture); + ret.push_back(dtp); + } + + if (is_output_port_connected(5)) { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "mesh_uv2"); + dtp.params.push_back(uv2_texture); + ret.push_back(dtp); + } + return ret; } -void VisualShaderNodeParticleMeshEmitter::update_texture() { +void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector &p_array, Ref &r_texture) { + Ref image; + image.instantiate(); + + if (p_array.size() == 0) { + image->create(1, 1, false, Image::Format::FORMAT_RGBF); + } else { + image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF); + } + + for (int i = 0; i < p_array.size(); i++) { + Vector2 v = p_array[i]; + image->set_pixel(i, 0, Color(v.x, v.y, 0)); + } + if (r_texture->get_width() != p_array.size() || p_array.size() == 0) { + r_texture->create_from_image(image); + } else { + r_texture->update(image); + } +} + +void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector &p_array, Ref &r_texture) { + Ref image; + image.instantiate(); + + if (p_array.size() == 0) { + image->create(1, 1, false, Image::Format::FORMAT_RGBF); + } else { + image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF); + } + + for (int i = 0; i < p_array.size(); i++) { + Vector3 v = p_array[i]; + image->set_pixel(i, 0, Color(v.x, v.y, v.z)); + } + if (r_texture->get_width() != p_array.size() || p_array.size() == 0) { + r_texture->create_from_image(image); + } else { + r_texture->update(image); + } +} + +void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector &p_array, Ref &r_texture) { + Ref image; + image.instantiate(); + + if (p_array.size() == 0) { + image->create(1, 1, false, Image::Format::FORMAT_RGBA8); + } else { + image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBA8); + } + + for (int i = 0; i < p_array.size(); i++) { + image->set_pixel(i, 0, p_array[i]); + } + if (r_texture->get_width() != p_array.size() || p_array.size() == 0) { + r_texture->create_from_image(image); + } else { + r_texture->update(image); + } +} + +void VisualShaderNodeParticleMeshEmitter::_update_textures() { if (!mesh.is_valid()) { return; } Vector vertices; Vector normals; + Vector colors; + Vector uvs; + Vector uvs2; if (use_all_surfaces) { for (int i = 0; i < max_surface_index; i++) { + // position Array vertex_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_VERTEX]; for (int j = 0; j < vertex_array.size(); j++) { vertices.push_back((Vector3)vertex_array[j]); } + // normal Array normal_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_NORMAL]; - for (int j = 0; j < vertex_array.size(); j++) { - normals.push_back((Vector3)vertex_array[j]); + for (int j = 0; j < normal_array.size(); j++) { + normals.push_back((Vector3)normal_array[j]); + } + + // color + Array color_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_COLOR]; + for (int j = 0; j < color_array.size(); j++) { + colors.push_back((Color)color_array[j]); + } + + // uv + Array uv_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_TEX_UV]; + for (int j = 0; j < uv_array.size(); j++) { + uvs.push_back((Vector2)uv_array[j]); + } + + // uv2 + Array uv2_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_TEX_UV2]; + for (int j = 0; j < uv2_array.size(); j++) { + uvs2.push_back((Vector2)uv2_array[j]); } } } else { + // position Array vertex_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_VERTEX]; for (int i = 0; i < vertex_array.size(); i++) { vertices.push_back((Vector3)vertex_array[i]); } + // normal Array normal_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_NORMAL]; for (int i = 0; i < normal_array.size(); i++) { normals.push_back((Vector3)normal_array[i]); } - } - // vertices - { - Ref image; - image.instantiate(); - image->create(vertices.size(), 1, false, Image::Format::FORMAT_RGBF); - - for (int i = 0; i < vertices.size(); i++) { - Vector3 v = vertices[i]; - image->set_pixel(i, 0, Color(v.x, v.y, v.z)); + // color + Array color_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_COLOR]; + for (int i = 0; i < color_array.size(); i++) { + colors.push_back((Color)color_array[i]); } - if (position_texture->get_width() != vertices.size()) { - position_texture->create_from_image(image); - } else { - position_texture->update(image); + + // uv + Array uv_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_TEX_UV]; + for (int j = 0; j < uv_array.size(); j++) { + uvs.push_back((Vector2)uv_array[j]); + } + + // uv2 + Array uv2_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_TEX_UV2]; + for (int j = 0; j < uv2_array.size(); j++) { + uvs2.push_back((Vector2)uv2_array[j]); } } - // normals - { - Ref image; - image.instantiate(); - image->create(normals.size(), 1, false, Image::Format::FORMAT_RGBF); - - for (int i = 0; i < normals.size(); i++) { - Vector3 v = normals[i]; - image->set_pixel(i, 0, Color(v.x, v.y, v.z)); - } - if (normal_texture->get_width() != normals.size()) { - normal_texture->create_from_image(image); - } else { - normal_texture->update(image); - } - } + _update_texture(vertices, position_texture); + _update_texture(normals, normal_texture); + _update_texture(colors, color_texture); + _update_texture(uvs, uv_texture); + _update_texture(uvs2, uv2_texture); } void VisualShaderNodeParticleMeshEmitter::set_mesh(Ref p_mesh) { @@ -442,7 +586,7 @@ void VisualShaderNodeParticleMeshEmitter::set_mesh(Ref p_mesh) { } if (mesh.is_valid()) { - Callable callable = callable_mp(this, &VisualShaderNodeParticleMeshEmitter::update_texture); + Callable callable = callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures); if (mesh->is_connected(CoreStringNames::get_singleton()->changed, callable)) { mesh->disconnect(CoreStringNames::get_singleton()->changed, callable); @@ -452,7 +596,7 @@ void VisualShaderNodeParticleMeshEmitter::set_mesh(Ref p_mesh) { mesh = p_mesh; if (mesh.is_valid()) { - Callable callable = callable_mp(this, &VisualShaderNodeParticleMeshEmitter::update_texture); + Callable callable = callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures); if (!mesh->is_connected(CoreStringNames::get_singleton()->changed, callable)) { mesh->connect(CoreStringNames::get_singleton()->changed, callable); @@ -528,10 +672,13 @@ void VisualShaderNodeParticleMeshEmitter::_bind_methods() { } VisualShaderNodeParticleMeshEmitter::VisualShaderNodeParticleMeshEmitter() { - connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &VisualShaderNodeParticleMeshEmitter::update_texture)); + connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures)); position_texture.instantiate(); normal_texture.instantiate(); + color_texture.instantiate(); + uv_texture.instantiate(); + uv2_texture.instantiate(); } // VisualShaderNodeParticleMultiplyByAxisAngle diff --git a/scene/resources/visual_shader_particle_nodes.h b/scene/resources/visual_shader_particle_nodes.h index 0d0f21e4bfe..79459432f1c 100644 --- a/scene/resources/visual_shader_particle_nodes.h +++ b/scene/resources/visual_shader_particle_nodes.h @@ -115,6 +115,16 @@ class VisualShaderNodeParticleMeshEmitter : public VisualShaderNodeParticleEmitt Ref position_texture; Ref normal_texture; + Ref color_texture; + Ref uv_texture; + Ref uv2_texture; + + String _generate_code(VisualShader::Type p_type, int p_id, const String *p_output_vars, int p_index, const String &p_texture_name, bool p_ignore_mode2d = false) const; + + void _update_texture(const Vector &p_array, Ref &r_texture); + void _update_texture(const Vector &p_array, Ref &r_texture); + void _update_texture(const Vector &p_array, Ref &r_texture); + void _update_textures(); protected: static void _bind_methods(); @@ -130,11 +140,9 @@ public: virtual PortType get_input_port_type(int p_port) const override; virtual String get_input_port_name(int p_port) const override; - virtual String generate_global_per_node(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; - void update_texture(); - void set_mesh(Ref p_mesh); Ref get_mesh() const;