feat: updated engine version to 4.4-rc1

This commit is contained in:
Sara 2025-02-23 14:38:14 +01:00
parent ee00efde1f
commit 21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions

View file

@ -29,13 +29,14 @@
/**************************************************************************/
#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"
#include "scene/resources/curve_texture.h"
#include "scene/resources/gradient_texture.h"
#include "scene/resources/image_texture.h"
#include "scene/resources/particle_process_material.h"
AABB CPUParticles3D::get_aabb() const {
@ -47,15 +48,22 @@ void CPUParticles3D::set_emitting(bool p_emitting) {
return;
}
if (p_emitting && !use_fixed_seed) {
set_seed(Math::rand());
}
emitting = p_emitting;
if (emitting) {
active = true;
set_process_internal(true);
_set_emitting();
}
}
// first update before rendering to avoid one frame delay after emitting starts
if (time == 0) {
_update_internal();
}
void CPUParticles3D::_set_emitting() {
active = true;
set_process_internal(true);
// first update before rendering to avoid one frame delay after emitting starts
if (time == 0) {
_update_internal();
}
}
@ -232,7 +240,7 @@ PackedStringArray CPUParticles3D::get_configuration_warnings() const {
return warnings;
}
void CPUParticles3D::restart() {
void CPUParticles3D::restart(bool p_keep_seed) {
time = 0;
frame_remainder = 0;
cycle = 0;
@ -246,8 +254,12 @@ void CPUParticles3D::restart() {
w[i].active = false;
}
}
if (!p_keep_seed && !use_fixed_seed) {
seed = Math::rand();
}
set_emitting(true);
emitting = true;
_set_emitting();
}
void CPUParticles3D::set_direction(Vector3 p_direction) {
@ -310,7 +322,7 @@ real_t CPUParticles3D::get_param_max(Parameter p_param) const {
static void _adjust_curve_range(const Ref<Curve> &p_curve, real_t p_min, real_t p_max) {
Ref<Curve> curve = p_curve;
if (!curve.is_valid()) {
if (curve.is_null()) {
return;
}
@ -410,14 +422,17 @@ bool CPUParticles3D::get_particle_flag(ParticleFlags p_particle_flag) const {
void CPUParticles3D::set_emission_shape(EmissionShape p_shape) {
ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX);
emission_shape = p_shape;
update_gizmos();
}
void CPUParticles3D::set_emission_sphere_radius(real_t p_radius) {
emission_sphere_radius = p_radius;
update_gizmos();
}
void CPUParticles3D::set_emission_box_extents(Vector3 p_extents) {
emission_box_extents = p_extents;
update_gizmos();
}
void CPUParticles3D::set_emission_points(const Vector<Vector3> &p_points) {
@ -434,18 +449,27 @@ void CPUParticles3D::set_emission_colors(const Vector<Color> &p_colors) {
void CPUParticles3D::set_emission_ring_axis(Vector3 p_axis) {
emission_ring_axis = p_axis;
update_gizmos();
}
void CPUParticles3D::set_emission_ring_height(real_t p_height) {
emission_ring_height = p_height;
update_gizmos();
}
void CPUParticles3D::set_emission_ring_radius(real_t p_radius) {
emission_ring_radius = p_radius;
update_gizmos();
}
void CPUParticles3D::set_emission_ring_inner_radius(real_t p_radius) {
emission_ring_inner_radius = p_radius;
update_gizmos();
}
void CPUParticles3D::set_emission_ring_cone_angle(real_t p_angle) {
emission_ring_cone_angle = p_angle;
update_gizmos();
}
void CPUParticles3D::set_scale_curve_x(Ref<Curve> p_scale_curve) {
@ -501,6 +525,10 @@ real_t CPUParticles3D::get_emission_ring_inner_radius() const {
return emission_ring_inner_radius;
}
real_t CPUParticles3D::get_emission_ring_cone_angle() const {
return emission_ring_cone_angle;
}
CPUParticles3D::EmissionShape CPUParticles3D::get_emission_shape() const {
return emission_shape;
}
@ -534,7 +562,35 @@ AABB CPUParticles3D::capture_aabb() const {
return RS::get_singleton()->multimesh_get_aabb(multimesh);
}
void CPUParticles3D::set_use_fixed_seed(bool p_use_fixed_seed) {
if (p_use_fixed_seed == use_fixed_seed) {
return;
}
use_fixed_seed = p_use_fixed_seed;
notify_property_list_changed();
}
bool CPUParticles3D::get_use_fixed_seed() const {
return use_fixed_seed;
}
void CPUParticles3D::set_seed(uint32_t p_seed) {
seed = p_seed;
}
uint32_t CPUParticles3D::get_seed() const {
return seed;
}
void CPUParticles3D::request_particles_process(real_t p_requested_process_time) {
_requested_process_time = p_requested_process_time;
}
void CPUParticles3D::_validate_property(PropertyInfo &p_property) const {
if (p_property.name == "emitting") {
p_property.hint = one_shot ? PROPERTY_HINT_ONESHOT : PROPERTY_HINT_NONE;
}
if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
p_property.usage = PROPERTY_USAGE_NONE;
}
@ -562,6 +618,10 @@ void CPUParticles3D::_validate_property(PropertyInfo &p_property) const {
if (p_property.name.begins_with("scale_curve_") && !split_scale) {
p_property.usage = PROPERTY_USAGE_NONE;
}
if (p_property.name == "seed" && !use_fixed_seed) {
p_property.usage = PROPERTY_USAGE_NONE;
}
}
static uint32_t idhash(uint32_t x) {
@ -607,25 +667,27 @@ void CPUParticles3D::_update_internal() {
bool processed = false;
if (time == 0 && pre_process_time > 0.0) {
double frame_time;
if (fixed_fps > 0) {
frame_time = 1.0 / fixed_fps;
} else {
frame_time = 1.0 / 30.0;
}
double todo = pre_process_time;
while (todo >= 0) {
_particles_process(frame_time);
processed = true;
todo -= frame_time;
}
double frame_time;
if (fixed_fps > 0) {
frame_time = 1.0 / fixed_fps;
} else {
frame_time = 1.0 / 30.0;
}
double todo = _requested_process_time;
_requested_process_time = 0.;
if (time == 0 && pre_process_time > 0.0) {
todo += pre_process_time;
}
real_t tmp_speed = speed_scale;
speed_scale = 1.0;
while (todo > 0) {
_particles_process(frame_time);
todo -= frame_time;
}
speed_scale = tmp_speed;
todo = 0.0;
if (fixed_fps > 0) {
double frame_time = 1.0 / fixed_fps;
double decr = frame_time;
double ldelta = delta;
@ -634,7 +696,7 @@ void CPUParticles3D::_update_internal() {
} else if (ldelta <= 0.0) { //unlikely but..
ldelta = 0.001;
}
double todo = frame_remainder + ldelta;
todo = frame_remainder + ldelta;
while (todo >= frame_time) {
_particles_process(frame_time);
@ -698,13 +760,13 @@ void CPUParticles3D::_particles_process(double p_delta) {
double restart_phase = double(i) / double(pcount);
if (randomness_ratio > 0.0) {
uint32_t seed = cycle;
uint32_t _seed = cycle;
if (restart_phase >= system_phase) {
seed -= uint32_t(1);
_seed -= uint32_t(1);
}
seed *= uint32_t(pcount);
seed += uint32_t(i);
double random = double(idhash(seed) % uint32_t(65536)) / 65536.0;
_seed *= uint32_t(pcount);
_seed += uint32_t(i);
double random = double(idhash(_seed) % uint32_t(65536)) / 65536.0;
restart_phase += randomness_ratio * random * 1.0 / double(pcount);
}
@ -765,27 +827,27 @@ void CPUParticles3D::_particles_process(double p_delta) {
tex_anim_offset = curve_parameters[PARAM_ANGLE]->sample(tv);
}
p.seed = Math::rand();
p.angle_rand = Math::randf();
p.scale_rand = Math::randf();
p.hue_rot_rand = Math::randf();
p.anim_offset_rand = Math::randf();
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(Math::randf());
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((Math::randf() * 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], (real_t)Math::randf());
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((Math::randf() * (real_t)2.0 - (real_t)1.0) * spread);
real_t angle2_rad = Math::deg_to_rad((Math::randf() * (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));
@ -805,14 +867,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], (real_t)Math::randf());
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 - Math::randf() * lifetime_randomness);
p.custom[3] = (1.0 - rng->randf() * lifetime_randomness);
p.transform = Transform3D();
p.time = 0;
p.lifetime = lifetime * p.custom[3];
@ -823,20 +885,20 @@ void CPUParticles3D::_particles_process(double p_delta) {
//do none
} break;
case EMISSION_SHAPE_SPHERE: {
real_t s = 2.0 * Math::randf() - 1.0;
real_t t = Math_TAU * Math::randf();
real_t x = Math::randf();
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 * Math::randf() - 1.0;
real_t t = Math_TAU * Math::randf();
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(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0, Math::randf() * 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: {
@ -878,8 +940,14 @@ void CPUParticles3D::_particles_process(double p_delta) {
}
} break;
case EMISSION_SHAPE_RING: {
real_t ring_random_angle = Math::randf() * Math_TAU;
real_t ring_random_radius = Math::sqrt(Math::randf() * (emission_ring_radius * emission_ring_radius - emission_ring_inner_radius * emission_ring_inner_radius) + emission_ring_inner_radius * emission_ring_inner_radius);
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 = 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 = 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;
if (axis.abs() == Vector3(1.0, 0.0, 0.0)) {
@ -890,7 +958,7 @@ void CPUParticles3D::_particles_process(double p_delta) {
ortho_axis = ortho_axis.normalized();
ortho_axis.rotate(axis, ring_random_angle);
ortho_axis = ortho_axis.normalized();
p.transform.origin = ortho_axis * ring_random_radius + (Math::randf() * emission_ring_height - emission_ring_height / 2.0) * axis;
p.transform.origin = ortho_axis * ring_random_radius + (y_pos * emission_ring_height - emission_ring_height / 2.0) * axis;
} break;
case EMISSION_SHAPE_MAX: { // Max value for validity check.
break;
@ -1392,6 +1460,11 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) {
set_emission_shape(EmissionShape(material->get_emission_shape()));
set_emission_sphere_radius(material->get_emission_sphere_radius());
set_emission_box_extents(material->get_emission_box_extents());
set_emission_ring_height(material->get_emission_ring_height());
set_emission_ring_radius(material->get_emission_ring_radius());
set_emission_ring_inner_radius(material->get_emission_ring_inner_radius());
set_emission_ring_cone_angle(material->get_emission_ring_cone_angle());
Ref<CurveXYZTexture> scale3D = material->get_param_texture(ParticleProcessMaterial::PARAM_SCALE);
if (scale3D.is_valid()) {
split_scale = true;
@ -1464,17 +1537,28 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &CPUParticles3D::set_mesh);
ClassDB::bind_method(D_METHOD("get_mesh"), &CPUParticles3D::get_mesh);
ClassDB::bind_method(D_METHOD("restart"), &CPUParticles3D::restart);
ClassDB::bind_method(D_METHOD("set_use_fixed_seed", "use_fixed_seed"), &CPUParticles3D::set_use_fixed_seed);
ClassDB::bind_method(D_METHOD("get_use_fixed_seed"), &CPUParticles3D::get_use_fixed_seed);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
ClassDB::bind_method(D_METHOD("set_seed", "seed"), &CPUParticles3D::set_seed);
ClassDB::bind_method(D_METHOD("get_seed"), &CPUParticles3D::get_seed);
ClassDB::bind_method(D_METHOD("restart", "keep_seed"), &CPUParticles3D::restart, DEFVAL(false));
ClassDB::bind_method(D_METHOD("request_particles_process", "process_time"), &CPUParticles3D::request_particles_process);
ClassDB::bind_method(D_METHOD("capture_aabb"), &CPUParticles3D::capture_aabb);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting", PROPERTY_HINT_ONESHOT), "set_emitting", "is_emitting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); // FIXME: Evaluate support for `exp` in integer properties, or remove this.
ADD_GROUP("Time", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,exp,suffix:s"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01,exp,suffix:s"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,10.0,0.01,or_greater,exp,suffix:s"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_fixed_seed"), "set_use_fixed_seed", "get_use_fixed_seed");
ADD_PROPERTY(PropertyInfo(Variant::INT, "seed", PROPERTY_HINT_RANGE, "0," + itos(UINT32_MAX) + ",1"), "set_seed", "get_seed");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1,suffix:FPS"), "set_fixed_fps", "get_fixed_fps");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
@ -1488,6 +1572,8 @@ void CPUParticles3D::_bind_methods() {
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH);
ADD_PROPERTY_DEFAULT("seed", 0);
////////////////////////////////
ClassDB::bind_method(D_METHOD("set_direction", "direction"), &CPUParticles3D::set_direction);
@ -1550,6 +1636,9 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emission_ring_inner_radius", "inner_radius"), &CPUParticles3D::set_emission_ring_inner_radius);
ClassDB::bind_method(D_METHOD("get_emission_ring_inner_radius"), &CPUParticles3D::get_emission_ring_inner_radius);
ClassDB::bind_method(D_METHOD("set_emission_ring_cone_angle", "cone_angle"), &CPUParticles3D::set_emission_ring_cone_angle);
ClassDB::bind_method(D_METHOD("get_emission_ring_cone_angle"), &CPUParticles3D::get_emission_ring_cone_angle);
ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles3D::get_gravity);
ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles3D::set_gravity);
@ -1577,9 +1666,10 @@ void CPUParticles3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_ring_axis"), "set_emission_ring_axis", "get_emission_ring_axis");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_height"), "set_emission_ring_height", "get_emission_ring_height");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_radius"), "set_emission_ring_radius", "get_emission_ring_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_inner_radius"), "set_emission_ring_inner_radius", "get_emission_ring_inner_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_height", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_emission_ring_height", "get_emission_ring_height");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_radius", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_emission_ring_radius", "get_emission_ring_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_inner_radius", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_emission_ring_inner_radius", "get_emission_ring_inner_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_cone_angle", PROPERTY_HINT_RANGE, "0,90,0.01,degrees"), "set_emission_ring_cone_angle", "get_emission_ring_cone_angle");
ADD_GROUP("Particle Flags", "particle_flag_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_rotate_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ROTATE_Y);
@ -1684,6 +1774,9 @@ CPUParticles3D::CPUParticles3D() {
set_emitting(true);
set_amount(8);
set_seed(Math::rand());
rng.instantiate();
set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0);
set_param_min(PARAM_ANGULAR_VELOCITY, 0);
@ -1716,6 +1809,7 @@ CPUParticles3D::CPUParticles3D() {
set_emission_ring_height(1);
set_emission_ring_radius(1);
set_emission_ring_inner_radius(0);
set_emission_ring_cone_angle(90);
set_gravity(Vector3(0, -9.8, 0));