From c8b0509b7c3af26a82e6d3197bd981e06e95ad04 Mon Sep 17 00:00:00 2001 From: Qbieshay Date: Tue, 21 Jan 2025 12:00:31 +0100 Subject: [PATCH] Fixed cpuparticles randomness regression caused by #92089 --- scene/2d/cpu_particles_2d.cpp | 29 +++++++++++---------- scene/2d/cpu_particles_2d.h | 4 +++ scene/3d/cpu_particles_3d.cpp | 47 +++++++++++++++++++---------------- scene/3d/cpu_particles_3d.h | 4 +++ 4 files changed, 49 insertions(+), 35 deletions(-) diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index e322afa61bf..ba0232945ca 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -31,6 +31,7 @@ #include "cpu_particles_2d.h" #include "cpu_particles_2d.compat.inc" +#include "core/math/random_number_generator.h" #include "scene/2d/gpu_particles_2d.h" #include "scene/resources/atlas_texture.h" #include "scene/resources/canvas_item_material.h" @@ -769,22 +770,22 @@ void CPUParticles2D::_particles_process(double p_delta) { } p.seed = seed + uint32_t(i) + i + cycle; - uint32_t _seed = p.seed; + rng->set_seed(p.seed); - p.angle_rand = rand_from_seed(_seed); - p.scale_rand = rand_from_seed(_seed); - p.hue_rot_rand = rand_from_seed(_seed); - p.anim_offset_rand = rand_from_seed(_seed); + p.angle_rand = rng->randf(); + p.scale_rand = rng->randf(); + p.hue_rot_rand = rng->randf(); + p.anim_offset_rand = rng->randf(); if (color_initial_ramp.is_valid()) { - p.start_color_rand = color_initial_ramp->get_color_at_offset(rand_from_seed(_seed)); + p.start_color_rand = color_initial_ramp->get_color_at_offset(rng->randf()); } else { p.start_color_rand = Color(1, 1, 1, 1); } - real_t angle1_rad = direction.angle() + Math::deg_to_rad((rand_from_seed(_seed) * 2.0 - 1.0) * spread); + real_t angle1_rad = direction.angle() + Math::deg_to_rad((rng->randf() * 2.0 - 1.0) * spread); Vector2 rot = Vector2(Math::cos(angle1_rad), Math::sin(angle1_rad)); - p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], (real_t)rand_from_seed(_seed)); + p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], rng->randf()); real_t base_angle = tex_angle * Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand); p.rotation = Math::deg_to_rad(base_angle); @@ -792,7 +793,7 @@ void CPUParticles2D::_particles_process(double p_delta) { p.custom[0] = 0.0; // unused p.custom[1] = 0.0; // phase [0..1] p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand); - p.custom[3] = (1.0 - rand_from_seed(_seed) * lifetime_randomness); + p.custom[3] = (1.0 - rng->randf() * lifetime_randomness); p.transform = Transform2D(); p.time = 0; p.lifetime = lifetime * p.custom[3]; @@ -803,17 +804,17 @@ void CPUParticles2D::_particles_process(double p_delta) { //do none } break; case EMISSION_SHAPE_SPHERE: { - real_t t = Math_TAU * rand_from_seed(_seed); - real_t radius = emission_sphere_radius * rand_from_seed(_seed); + real_t t = Math_TAU * rng->randf(); + real_t radius = emission_sphere_radius * rng->randf(); p.transform[2] = Vector2(Math::cos(t), Math::sin(t)) * radius; } break; case EMISSION_SHAPE_SPHERE_SURFACE: { - real_t s = rand_from_seed(_seed), t = Math_TAU * rand_from_seed(_seed); + real_t s = rng->randf(), t = Math_TAU * rng->randf(); real_t radius = emission_sphere_radius * Math::sqrt(1.0 - s * s); p.transform[2] = Vector2(Math::cos(t), Math::sin(t)) * radius; } break; case EMISSION_SHAPE_RECTANGLE: { - p.transform[2] = Vector2(rand_from_seed(_seed) * 2.0 - 1.0, rand_from_seed(_seed) * 2.0 - 1.0) * emission_rect_extents; + p.transform[2] = Vector2(rng->randf() * 2.0 - 1.0, rng->randf() * 2.0 - 1.0) * emission_rect_extents; } break; case EMISSION_SHAPE_POINTS: case EMISSION_SHAPE_DIRECTED_POINTS: { @@ -1523,6 +1524,8 @@ CPUParticles2D::CPUParticles2D() { set_amount(8); set_use_local_coordinates(false); + rng.instantiate(); + set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0); set_param_min(PARAM_ANGULAR_VELOCITY, 0); set_param_min(PARAM_ORBIT_VELOCITY, 0); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index 1f100d401d4..f6f1d8a00ae 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -33,6 +33,8 @@ #include "scene/2d/node_2d.h" +class RandomNumberGenerator; + class CPUParticles2D : public Node2D { private: GDCLASS(CPUParticles2D, Node2D); @@ -179,6 +181,8 @@ private: Vector2 gravity = Vector2(0, 980); + Ref rng; + void _update_internal(); void _particles_process(double p_delta); void _update_particle_data_buffer(); diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index 0f9b57e0c50..f150e07bcaa 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -31,6 +31,7 @@ #include "cpu_particles_3d.h" #include "cpu_particles_3d.compat.inc" +#include "core/math/random_number_generator.h" #include "scene/3d/camera_3d.h" #include "scene/3d/gpu_particles_3d.h" #include "scene/main/viewport.h" @@ -818,27 +819,27 @@ void CPUParticles3D::_particles_process(double p_delta) { tex_anim_offset = curve_parameters[PARAM_ANGLE]->sample(tv); } - p.seed = seed; - uint32_t _seed = seed + uint32_t(1) + i + cycle; - p.angle_rand = rand_from_seed(_seed); - p.scale_rand = rand_from_seed(_seed); - p.hue_rot_rand = rand_from_seed(_seed); - p.anim_offset_rand = rand_from_seed(_seed); + p.seed = seed + uint32_t(1) + i + cycle; + rng->set_seed(p.seed); + p.angle_rand = rng->randf(); + p.scale_rand = rng->randf(); + p.hue_rot_rand = rng->randf(); + p.anim_offset_rand = rng->randf(); if (color_initial_ramp.is_valid()) { - p.start_color_rand = color_initial_ramp->get_color_at_offset(rand_from_seed(_seed)); + p.start_color_rand = color_initial_ramp->get_color_at_offset(rng->randf()); } else { p.start_color_rand = Color(1, 1, 1, 1); } if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - real_t angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg_to_rad((rand_from_seed(_seed) * 2.0 - 1.0) * spread); + real_t angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg_to_rad((rng->randf() * 2.0 - 1.0) * spread); Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0); - p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], rand_from_seed(_seed)); + p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], rng->randf()); } else { //initiate velocity spread in 3D - real_t angle1_rad = Math::deg_to_rad((rand_from_seed(_seed) * (real_t)2.0 - (real_t)1.0) * spread); - real_t angle2_rad = Math::deg_to_rad((rand_from_seed(_seed) * (real_t)2.0 - (real_t)1.0) * ((real_t)1.0 - flatness) * spread); + real_t angle1_rad = Math::deg_to_rad((rng->randf() * (real_t)2.0 - (real_t)1.0) * spread); + real_t angle2_rad = Math::deg_to_rad((rng->randf() * (real_t)2.0 - (real_t)1.0) * ((real_t)1.0 - flatness) * spread); Vector3 direction_xz = Vector3(Math::sin(angle1_rad), 0, Math::cos(angle1_rad)); Vector3 direction_yz = Vector3(0, Math::sin(angle2_rad), Math::cos(angle2_rad)); @@ -858,14 +859,14 @@ void CPUParticles3D::_particles_process(double p_delta) { binormal.normalize(); Vector3 normal = binormal.cross(direction_nrm); spread_direction = binormal * spread_direction.x + normal * spread_direction.y + direction_nrm * spread_direction.z; - p.velocity = spread_direction * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], rand_from_seed(_seed)); + p.velocity = spread_direction * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], rng->randf()); } real_t base_angle = tex_angle * Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand); p.custom[0] = Math::deg_to_rad(base_angle); //angle p.custom[1] = 0.0; //phase p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand); //animation offset (0-1) - p.custom[3] = (1.0 - rand_from_seed(_seed) * lifetime_randomness); + p.custom[3] = (1.0 - rng->randf() * lifetime_randomness); p.transform = Transform3D(); p.time = 0; p.lifetime = lifetime * p.custom[3]; @@ -876,20 +877,20 @@ void CPUParticles3D::_particles_process(double p_delta) { //do none } break; case EMISSION_SHAPE_SPHERE: { - real_t s = 2.0 * rand_from_seed(_seed) - 1.0; - real_t t = Math_TAU * rand_from_seed(_seed); - real_t x = rand_from_seed(_seed); + real_t s = 2.0 * rng->randf() - 1.0; + real_t t = Math_TAU * rng->randf(); + real_t x = rng->randf(); real_t radius = emission_sphere_radius * Math::sqrt(1.0 - s * s); p.transform.origin = Vector3(0, 0, 0).lerp(Vector3(radius * Math::cos(t), radius * Math::sin(t), emission_sphere_radius * s), x); } break; case EMISSION_SHAPE_SPHERE_SURFACE: { - real_t s = 2.0 * rand_from_seed(_seed) - 1.0; - real_t t = Math_TAU * rand_from_seed(_seed); + real_t s = 2.0 * rng->randf() - 1.0; + real_t t = Math_TAU * rng->randf(); real_t radius = emission_sphere_radius * Math::sqrt(1.0 - s * s); p.transform.origin = Vector3(radius * Math::cos(t), radius * Math::sin(t), emission_sphere_radius * s); } break; case EMISSION_SHAPE_BOX: { - p.transform.origin = Vector3(rand_from_seed(_seed) * 2.0 - 1.0, rand_from_seed(_seed) * 2.0 - 1.0, rand_from_seed(_seed) * 2.0 - 1.0) * emission_box_extents; + p.transform.origin = Vector3(rng->randf() * 2.0 - 1.0, rng->randf() * 2.0 - 1.0, rng->randf() * 2.0 - 1.0) * emission_box_extents; } break; case EMISSION_SHAPE_POINTS: case EMISSION_SHAPE_DIRECTED_POINTS: { @@ -933,11 +934,11 @@ void CPUParticles3D::_particles_process(double p_delta) { case EMISSION_SHAPE_RING: { real_t radius_clamped = MAX(0.001, emission_ring_radius); real_t top_radius = MAX(radius_clamped - Math::tan(Math::deg_to_rad(90.0 - emission_ring_cone_angle)) * emission_ring_height, 0.0); - real_t y_pos = rand_from_seed(_seed); + real_t y_pos = rng->randf(); real_t skew = MAX(MIN(radius_clamped, top_radius) / MAX(radius_clamped, top_radius), 0.5); y_pos = radius_clamped < top_radius ? Math::pow(y_pos, skew) : 1.0 - Math::pow(y_pos, skew); - real_t ring_random_angle = rand_from_seed(_seed) * Math_TAU; - real_t ring_random_radius = Math::sqrt(rand_from_seed(_seed) * (radius_clamped * radius_clamped - emission_ring_inner_radius * emission_ring_inner_radius) + emission_ring_inner_radius * emission_ring_inner_radius); + real_t ring_random_angle = rng->randf() * Math_TAU; + real_t ring_random_radius = Math::sqrt(rng->randf() * (radius_clamped * radius_clamped - emission_ring_inner_radius * emission_ring_inner_radius) + emission_ring_inner_radius * emission_ring_inner_radius); ring_random_radius = Math::lerp(ring_random_radius, ring_random_radius * (top_radius / radius_clamped), y_pos); Vector3 axis = emission_ring_axis == Vector3(0.0, 0.0, 0.0) ? Vector3(0.0, 0.0, 1.0) : emission_ring_axis.normalized(); Vector3 ortho_axis; @@ -1764,6 +1765,8 @@ CPUParticles3D::CPUParticles3D() { set_emitting(true); set_amount(8); + rng.instantiate(); + set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0); set_param_min(PARAM_ANGULAR_VELOCITY, 0); set_param_min(PARAM_ORBIT_VELOCITY, 0); diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h index 081d9a62532..64699e8b04b 100644 --- a/scene/3d/cpu_particles_3d.h +++ b/scene/3d/cpu_particles_3d.h @@ -33,6 +33,8 @@ #include "scene/3d/visual_instance_3d.h" +class RandomNumberGenerator; + class CPUParticles3D : public GeometryInstance3D { private: GDCLASS(CPUParticles3D, GeometryInstance3D); @@ -190,6 +192,8 @@ private: Vector3 gravity = Vector3(0, -9.8, 0); + Ref rng; + void _update_internal(); void _particles_process(double p_delta); void _update_particle_data_buffer();