From 6dd593d5791ad1ac972397671328f09669da5793 Mon Sep 17 00:00:00 2001 From: Raffaele Picca Date: Fri, 10 Dec 2021 16:35:25 +0100 Subject: [PATCH] Random initial color for all Particle Nodes --- doc/classes/CPUParticles.xml | 3 +++ doc/classes/CPUParticles2D.xml | 3 +++ doc/classes/ParticlesMaterial.xml | 3 +++ scene/2d/cpu_particles_2d.cpp | 25 +++++++++++++++++++++- scene/2d/cpu_particles_2d.h | 5 +++++ scene/3d/cpu_particles.cpp | 25 +++++++++++++++++++++- scene/3d/cpu_particles.h | 5 +++++ scene/resources/particles_material.cpp | 29 ++++++++++++++++++++++++++ scene/resources/particles_material.h | 7 +++++++ 9 files changed, 103 insertions(+), 2 deletions(-) diff --git a/doc/classes/CPUParticles.xml b/doc/classes/CPUParticles.xml index 346fdd100fb0..2ee7cca537a6 100644 --- a/doc/classes/CPUParticles.xml +++ b/doc/classes/CPUParticles.xml @@ -129,6 +129,9 @@ Each particle's initial color. To have particle display color in a [SpatialMaterial] make sure to set [member SpatialMaterial.vertex_color_use_as_albedo] to [code]true[/code]. + + Each particle's initial color will vary along this [GradientTexture] (multiplied with [member color]). + Each particle's color will vary along this [GradientTexture] over its lifetime (multiplied with [member color]). diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml index d6e22399e1c0..f37f8f7efc51 100644 --- a/doc/classes/CPUParticles2D.xml +++ b/doc/classes/CPUParticles2D.xml @@ -130,6 +130,9 @@ Each particle's initial color. If [member texture] is defined, it will be multiplied by this color. + + Each particle's initial color will vary along this [GradientTexture] (multiplied with [member color]). + Each particle's color will vary along this [Gradient] (multiplied with [member color]). diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticlesMaterial.xml index 99b59799b1cf..52fda5813108 100644 --- a/doc/classes/ParticlesMaterial.xml +++ b/doc/classes/ParticlesMaterial.xml @@ -114,6 +114,9 @@ Each particle's initial color. If the [Particles2D]'s [code]texture[/code] is defined, it will be multiplied by this color. To have particle display color in a [SpatialMaterial] make sure to set [member SpatialMaterial.vertex_color_use_as_albedo] to [code]true[/code]. + + Each particle's initial color will vary along this [GradientTexture] (multiplied with [member color]). + Each particle's color will vary along this [GradientTexture] over its lifetime (multiplied with [member color]). diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 2897a7486eb0..e1e4461e9ad0 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -393,6 +393,14 @@ Ref CPUParticles2D::get_color_ramp() const { return color_ramp; } +void CPUParticles2D::set_color_initial_ramp(const Ref &p_ramp) { + color_initial_ramp = p_ramp; +} + +Ref CPUParticles2D::get_color_initial_ramp() const { + return color_initial_ramp; +} + void CPUParticles2D::set_particle_flag(Flags p_flag, bool p_enable) { ERR_FAIL_INDEX(p_flag, FLAG_MAX); flags[p_flag] = p_enable; @@ -690,6 +698,12 @@ void CPUParticles2D::_particles_process(float p_delta) { p.hue_rot_rand = Math::randf(); p.anim_offset_rand = Math::randf(); + if (color_initial_ramp.is_valid()) { + p.start_color_rand = color_initial_ramp->get_color_at_offset(Math::randf()); + } else { + p.start_color_rand = Color(1, 1, 1, 1); + } + float angle1_rad = Math::atan2(direction.y, direction.x) + (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0; Vector2 rot = Vector2(Math::cos(angle1_rad), Math::sin(angle1_rad)); p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]); @@ -895,7 +909,7 @@ void CPUParticles2D::_particles_process(float p_delta) { p.color.g = color_rgb.y; p.color.b = color_rgb.z; - p.color *= p.base_color; + p.color *= p.base_color * p.start_color_rand; if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { if (p.velocity.length() > 0.0) { @@ -1127,6 +1141,11 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) { set_color_ramp(gt->get_gradient()); } + Ref gti = material->get_color_initial_ramp(); + if (gti.is_valid()) { + set_color_initial_ramp(gti->get_gradient()); + } + set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY)); set_emission_shape(EmissionShape(material->get_emission_shape())); @@ -1247,6 +1266,9 @@ void CPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &CPUParticles2D::set_color_ramp); ClassDB::bind_method(D_METHOD("get_color_ramp"), &CPUParticles2D::get_color_ramp); + ClassDB::bind_method(D_METHOD("set_color_initial_ramp", "ramp"), &CPUParticles2D::set_color_initial_ramp); + ClassDB::bind_method(D_METHOD("get_color_initial_ramp"), &CPUParticles2D::get_color_initial_ramp); + ClassDB::bind_method(D_METHOD("set_particle_flag", "flag", "enable"), &CPUParticles2D::set_particle_flag); ClassDB::bind_method(D_METHOD("get_particle_flag", "flag"), &CPUParticles2D::get_particle_flag); @@ -1328,6 +1350,7 @@ void CPUParticles2D::_bind_methods() { ADD_GROUP("Color", ""); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_initial_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_initial_ramp", "get_color_initial_ramp"); ADD_GROUP("Hue Variation", "hue_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param", "get_param", PARAM_HUE_VARIATION); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index 88c7ab684a00..d7f2744c827f 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -94,6 +94,7 @@ class CPUParticles2D : public Node2D { float scale_rand; float hue_rot_rand; float anim_offset_rand; + Color start_color_rand; float time; float lifetime; Color base_color; @@ -162,6 +163,7 @@ class CPUParticles2D : public Node2D { Ref curve_parameters[PARAM_MAX]; Color color; Ref color_ramp; + Ref color_initial_ramp; bool flags[FLAG_MAX]; @@ -255,6 +257,9 @@ class CPUParticles2D : public Node2D { void set_color_ramp(const Ref &p_ramp); Ref get_color_ramp() const; + void set_color_initial_ramp(const Ref &p_ramp); + Ref get_color_initial_ramp() const; + void set_particle_flag(Flags p_flag, bool p_enable); bool get_particle_flag(Flags p_flag) const; diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp index eba5e65892a9..37a045ab0cb1 100644 --- a/scene/3d/cpu_particles.cpp +++ b/scene/3d/cpu_particles.cpp @@ -351,6 +351,14 @@ Ref CPUParticles::get_color_ramp() const { return color_ramp; } +void CPUParticles::set_color_initial_ramp(const Ref &p_ramp) { + color_initial_ramp = p_ramp; +} + +Ref CPUParticles::get_color_initial_ramp() const { + return color_initial_ramp; +} + void CPUParticles::set_particle_flag(Flags p_flag, bool p_enable) { ERR_FAIL_INDEX(p_flag, FLAG_MAX); flags[p_flag] = p_enable; @@ -687,6 +695,12 @@ void CPUParticles::_particles_process(float p_delta) { p.hue_rot_rand = Math::randf(); p.anim_offset_rand = Math::randf(); + if (color_initial_ramp.is_valid()) { + p.start_color_rand = color_initial_ramp->get_color_at_offset(Math::randf()); + } else { + p.start_color_rand = Color(1, 1, 1, 1); + } + if (flags[FLAG_DISABLE_Z]) { float angle1_rad = Math::atan2(direction.y, direction.x) + (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0; Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0); @@ -963,7 +977,7 @@ void CPUParticles::_particles_process(float p_delta) { p.color.g = color_rgb.y; p.color.b = color_rgb.z; - p.color *= p.base_color; + p.color *= p.base_color * p.start_color_rand; if (flags[FLAG_DISABLE_Z]) { if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { @@ -1245,6 +1259,11 @@ void CPUParticles::convert_from_particles(Node *p_particles) { set_color_ramp(gt->get_gradient()); } + Ref gti = material->get_color_initial_ramp(); + if (gti.is_valid()) { + set_color_initial_ramp(gti->get_gradient()); + } + set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY)); set_particle_flag(FLAG_ROTATE_Y, material->get_flag(ParticlesMaterial::FLAG_ROTATE_Y)); set_particle_flag(FLAG_DISABLE_Z, material->get_flag(ParticlesMaterial::FLAG_DISABLE_Z)); @@ -1368,6 +1387,9 @@ void CPUParticles::_bind_methods() { ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &CPUParticles::set_color_ramp); ClassDB::bind_method(D_METHOD("get_color_ramp"), &CPUParticles::get_color_ramp); + ClassDB::bind_method(D_METHOD("set_color_initial_ramp", "ramp"), &CPUParticles::set_color_initial_ramp); + ClassDB::bind_method(D_METHOD("get_color_initial_ramp"), &CPUParticles::get_color_initial_ramp); + ClassDB::bind_method(D_METHOD("set_particle_flag", "flag", "enable"), &CPUParticles::set_particle_flag); ClassDB::bind_method(D_METHOD("get_particle_flag", "flag"), &CPUParticles::get_particle_flag); @@ -1468,6 +1490,7 @@ void CPUParticles::_bind_methods() { ADD_GROUP("Color", ""); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_initial_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_initial_ramp", "get_color_initial_ramp"); ADD_GROUP("Hue Variation", "hue_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param", "get_param", PARAM_HUE_VARIATION); diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h index e7b58f11f560..93967d1e3fda 100644 --- a/scene/3d/cpu_particles.h +++ b/scene/3d/cpu_particles.h @@ -94,6 +94,7 @@ class CPUParticles : public GeometryInstance { float scale_rand; float hue_rot_rand; float anim_offset_rand; + Color start_color_rand; float time; float lifetime; Color base_color; @@ -163,6 +164,7 @@ class CPUParticles : public GeometryInstance { Ref curve_parameters[PARAM_MAX]; Color color; Ref color_ramp; + Ref color_initial_ramp; bool flags[FLAG_MAX]; @@ -259,6 +261,9 @@ class CPUParticles : public GeometryInstance { void set_color_ramp(const Ref &p_ramp); Ref get_color_ramp() const; + void set_color_initial_ramp(const Ref &p_ramp); + Ref get_color_initial_ramp() const; + void set_particle_flag(Flags p_flag, bool p_enable); bool get_particle_flag(Flags p_flag) const; diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index a330e56f6ff6..0342443441c0 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -85,6 +85,7 @@ void ParticlesMaterial::init_shaders() { shader_names->color = "color_value"; shader_names->color_ramp = "color_ramp"; + shader_names->color_initial_ramp = "color_initial_ramp"; shader_names->emission_sphere_radius = "emission_sphere_radius"; shader_names->emission_box_extents = "emission_box_extents"; @@ -217,6 +218,10 @@ void ParticlesMaterial::_update_shader() { code += "uniform sampler2D color_ramp;\n"; } + if (color_initial_ramp.is_valid()) { + code += "uniform sampler2D color_initial_ramp;\n"; + } + if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { code += "uniform sampler2D linear_velocity_texture;\n"; } @@ -299,6 +304,9 @@ void ParticlesMaterial::_update_shader() { code += " float scale_rand = rand_from_seed(alt_seed);\n"; code += " float hue_rot_rand = rand_from_seed(alt_seed);\n"; code += " float anim_offset_rand = rand_from_seed(alt_seed);\n"; + if (color_initial_ramp.is_valid()) { + code += " float color_initial_rand = rand_from_seed(alt_seed);\n"; + } code += " float pi = 3.14159;\n"; code += " float degree_to_rad = pi / 180.0;\n"; code += "\n"; @@ -593,6 +601,12 @@ void ParticlesMaterial::_update_shader() { } else { code += " COLOR = hue_rot_mat * color_value;\n"; } + + if (color_initial_ramp.is_valid()) { + code += " vec4 start_color = textureLod(color_initial_ramp, vec2(color_initial_rand, 0.0), 0.0);\n"; + code += " COLOR *= start_color;\n"; + } + if (emission_color_texture.is_valid() && (emission_shape == EMISSION_SHAPE_POINTS || emission_shape == EMISSION_SHAPE_DIRECTED_POINTS)) { code += " COLOR *= texelFetch(emission_texture_color, emission_tex_ofs, 0);\n"; } @@ -933,6 +947,17 @@ Ref ParticlesMaterial::get_color_ramp() const { return color_ramp; } +void ParticlesMaterial::set_color_initial_ramp(const Ref &p_texture) { + color_initial_ramp = p_texture; + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->color_initial_ramp, p_texture); + _queue_shader_change(); + _change_notify(); +} + +Ref ParticlesMaterial::get_color_initial_ramp() const { + return color_initial_ramp; +} + void ParticlesMaterial::set_flag(Flags p_flag, bool p_enable) { ERR_FAIL_INDEX(p_flag, FLAG_MAX); flags[p_flag] = p_enable; @@ -1167,6 +1192,9 @@ void ParticlesMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &ParticlesMaterial::set_color_ramp); ClassDB::bind_method(D_METHOD("get_color_ramp"), &ParticlesMaterial::get_color_ramp); + ClassDB::bind_method(D_METHOD("set_color_initial_ramp", "ramp"), &ParticlesMaterial::set_color_initial_ramp); + ClassDB::bind_method(D_METHOD("get_color_initial_ramp"), &ParticlesMaterial::get_color_initial_ramp); + ClassDB::bind_method(D_METHOD("set_flag", "flag", "enable"), &ParticlesMaterial::set_flag); ClassDB::bind_method(D_METHOD("get_flag", "flag"), &ParticlesMaterial::get_flag); @@ -1285,6 +1313,7 @@ void ParticlesMaterial::_bind_methods() { ADD_GROUP("Color", ""); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_color_ramp", "get_color_ramp"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_initial_ramp", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_color_initial_ramp", "get_color_initial_ramp"); ADD_GROUP("Hue Variation", "hue_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param", "get_param", PARAM_HUE_VARIATION); diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h index 3d564c7880aa..e15d36f9151c 100644 --- a/scene/resources/particles_material.h +++ b/scene/resources/particles_material.h @@ -80,6 +80,7 @@ class ParticlesMaterial : public Material { struct { uint32_t texture_mask : 16; uint32_t texture_color : 1; + uint32_t texture_initial_color : 1; uint32_t flags : 4; uint32_t emission_shape : 3; uint32_t trail_size_texture : 1; @@ -119,6 +120,7 @@ class ParticlesMaterial : public Material { } mk.texture_color = color_ramp.is_valid() ? 1 : 0; + mk.texture_initial_color = color_initial_ramp.is_valid() ? 1 : 0; mk.emission_shape = emission_shape; mk.trail_color_texture = trail_color_modifier.is_valid() ? 1 : 0; mk.trail_size_texture = trail_size_modifier.is_valid() ? 1 : 0; @@ -174,6 +176,7 @@ class ParticlesMaterial : public Material { StringName color; StringName color_ramp; + StringName color_initial_ramp; StringName emission_sphere_radius; StringName emission_box_extents; @@ -214,6 +217,7 @@ class ParticlesMaterial : public Material { Ref tex_parameters[PARAM_MAX]; Color color; Ref color_ramp; + Ref color_initial_ramp; bool flags[FLAG_MAX]; @@ -271,6 +275,9 @@ class ParticlesMaterial : public Material { void set_color_ramp(const Ref &p_texture); Ref get_color_ramp() const; + void set_color_initial_ramp(const Ref &p_texture); + Ref get_color_initial_ramp() const; + void set_flag(Flags p_flag, bool p_enable); bool get_flag(Flags p_flag) const;