summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/gpu_particles_2d.cpp206
-rw-r--r--scene/2d/gpu_particles_2d.h24
-rw-r--r--scene/3d/gpu_particles_3d.cpp13
-rw-r--r--scene/3d/gpu_particles_3d.h5
-rw-r--r--scene/resources/particles_material.cpp2
5 files changed, 239 insertions, 11 deletions
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index 774a194e39..066835ef0a 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -140,6 +140,62 @@ void GPUParticles2D::set_process_material(const Ref<Material> &p_material) {
update_configuration_warnings();
}
+void GPUParticles2D::set_trail_enabled(bool p_enabled) {
+ trail_enabled = p_enabled;
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+ update_configuration_warnings();
+ update();
+
+ RS::get_singleton()->particles_set_transform_align(particles, p_enabled ? RS::PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY : RS::PARTICLES_TRANSFORM_ALIGN_DISABLED);
+}
+void GPUParticles2D::set_trail_length(float p_seconds) {
+ ERR_FAIL_COND(p_seconds < 0.001);
+ trail_length = p_seconds;
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+ update();
+}
+
+void GPUParticles2D::set_trail_sections(int p_sections) {
+ ERR_FAIL_COND(p_sections < 2);
+ ERR_FAIL_COND(p_sections > 128);
+
+ trail_sections = p_sections;
+ update();
+}
+void GPUParticles2D::set_trail_section_subdivisions(int p_subdivisions) {
+ ERR_FAIL_COND(trail_section_subdivisions < 1);
+ ERR_FAIL_COND(trail_section_subdivisions > 1024);
+
+ trail_section_subdivisions = p_subdivisions;
+ update();
+}
+
+bool GPUParticles2D::is_trail_enabled() const {
+ return trail_enabled;
+}
+float GPUParticles2D::get_trail_length() const {
+ return trail_length;
+}
+
+void GPUParticles2D::_update_collision_size() {
+ float csize = collision_base_size;
+
+ if (texture.is_valid()) {
+ csize *= (texture->get_width() + texture->get_height()) / 4.0; //half size since its a radius
+ }
+
+ RS::get_singleton()->particles_set_collision_base_size(particles, csize);
+}
+
+void GPUParticles2D::set_collision_base_size(float p_size) {
+ collision_base_size = p_size;
+ _update_collision_size();
+}
+
+float GPUParticles2D::get_collision_base_size() const {
+ return collision_base_size;
+}
+
void GPUParticles2D::set_speed_scale(float p_scale) {
speed_scale = p_scale;
RS::get_singleton()->particles_set_speed_scale(particles, p_scale);
@@ -157,6 +213,13 @@ float GPUParticles2D::get_lifetime() const {
return lifetime;
}
+int GPUParticles2D::get_trail_sections() const {
+ return trail_sections;
+}
+int GPUParticles2D::get_trail_section_subdivisions() const {
+ return trail_section_subdivisions;
+}
+
bool GPUParticles2D::get_one_shot() const {
return one_shot;
}
@@ -253,6 +316,7 @@ Rect2 GPUParticles2D::capture_rect() const {
void GPUParticles2D::set_texture(const Ref<Texture2D> &p_texture) {
texture = p_texture;
+ _update_collision_size();
update();
}
@@ -271,10 +335,119 @@ void GPUParticles2D::restart() {
void GPUParticles2D::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
RID texture_rid;
+ Size2 size;
if (texture.is_valid()) {
texture_rid = texture->get_rid();
+ size = texture->get_size();
+ } else {
+ size = Size2(1, 1);
}
+ if (trail_enabled) {
+ RS::get_singleton()->mesh_clear(mesh);
+ PackedVector2Array points;
+ PackedVector2Array uvs;
+ PackedInt32Array bone_indices;
+ PackedFloat32Array bone_weights;
+ PackedInt32Array indices;
+
+ int total_segments = trail_sections * trail_section_subdivisions;
+ float depth = size.height * trail_sections;
+
+ for (int j = 0; j <= total_segments; j++) {
+ float v = j;
+ v /= total_segments;
+
+ float y = depth * v;
+ y = (depth * 0.5) - y;
+
+ int bone = j / trail_section_subdivisions;
+ float blend = 1.0 - float(j % trail_section_subdivisions) / float(trail_section_subdivisions);
+
+ float s = size.width;
+
+ points.push_back(Vector2(-s * 0.5, 0));
+ points.push_back(Vector2(+s * 0.5, 0));
+
+ uvs.push_back(Vector2(0, v));
+ uvs.push_back(Vector2(1, v));
+
+ for (int i = 0; i < 2; i++) {
+ bone_indices.push_back(bone);
+ bone_indices.push_back(MIN(trail_sections, bone + 1));
+ bone_indices.push_back(0);
+ bone_indices.push_back(0);
+
+ bone_weights.push_back(blend);
+ bone_weights.push_back(1.0 - blend);
+ bone_weights.push_back(0);
+ bone_weights.push_back(0);
+ }
+
+ if (j > 0) {
+ int base = j * 2 - 2;
+ indices.push_back(base + 0);
+ indices.push_back(base + 1);
+ indices.push_back(base + 2);
+
+ indices.push_back(base + 1);
+ indices.push_back(base + 3);
+ indices.push_back(base + 2);
+ }
+ }
+
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ arr[RS::ARRAY_VERTEX] = points;
+ arr[RS::ARRAY_TEX_UV] = uvs;
+ arr[RS::ARRAY_BONES] = bone_indices;
+ arr[RS::ARRAY_WEIGHTS] = bone_weights;
+ arr[RS::ARRAY_INDEX] = indices;
+
+ RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
+
+ Vector<Transform> xforms;
+ for (int i = 0; i <= trail_sections; i++) {
+ Transform xform;
+ /*
+ xform.origin.y = depth / 2.0 - size.height * float(i);
+ xform.origin.y = -xform.origin.y; //bind is an inverse transform, so negate y */
+ xforms.push_back(xform);
+ }
+
+ RS::get_singleton()->particles_set_trail_bind_poses(particles, xforms);
+
+ } else {
+ RS::get_singleton()->mesh_clear(mesh);
+ Vector<Vector2> points;
+ points.resize(4);
+ points.write[0] = Vector2(-size.x / 2.0, -size.y / 2.0);
+ points.write[1] = Vector2(size.x / 2.0, -size.y / 2.0);
+ points.write[2] = Vector2(size.x / 2.0, size.y / 2.0);
+ points.write[3] = Vector2(-size.x / 2.0, size.y / 2.0);
+ Vector<Vector2> uvs;
+ uvs.resize(4);
+ uvs.write[0] = Vector2(0, 0);
+ uvs.write[1] = Vector2(1, 0);
+ uvs.write[2] = Vector2(1, 1);
+ uvs.write[3] = Vector2(0, 1);
+ Vector<int> indices;
+ indices.resize(6);
+ indices.write[0] = 0;
+ indices.write[1] = 1;
+ indices.write[2] = 2;
+ indices.write[3] = 0;
+ indices.write[4] = 2;
+ indices.write[5] = 3;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ arr[RS::ARRAY_VERTEX] = points;
+ arr[RS::ARRAY_TEX_UV] = uvs;
+ arr[RS::ARRAY_INDEX] = indices;
+
+ RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
+ RS::get_singleton()->particles_set_trail_bind_poses(particles, Vector<Transform>());
+ }
RS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid);
#ifdef TOOLS_ENABLED
@@ -318,6 +491,7 @@ void GPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &GPUParticles2D::set_fractional_delta);
ClassDB::bind_method(D_METHOD("set_process_material", "material"), &GPUParticles2D::set_process_material);
ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &GPUParticles2D::set_speed_scale);
+ ClassDB::bind_method(D_METHOD("set_collision_base_size", "size"), &GPUParticles2D::set_collision_base_size);
ClassDB::bind_method(D_METHOD("is_emitting"), &GPUParticles2D::is_emitting);
ClassDB::bind_method(D_METHOD("get_amount"), &GPUParticles2D::get_amount);
@@ -332,6 +506,7 @@ void GPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_fractional_delta"), &GPUParticles2D::get_fractional_delta);
ClassDB::bind_method(D_METHOD("get_process_material"), &GPUParticles2D::get_process_material);
ClassDB::bind_method(D_METHOD("get_speed_scale"), &GPUParticles2D::get_speed_scale);
+ ClassDB::bind_method(D_METHOD("get_collision_base_size"), &GPUParticles2D::get_collision_base_size);
ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &GPUParticles2D::set_draw_order);
ClassDB::bind_method(D_METHOD("get_draw_order"), &GPUParticles2D::get_draw_order);
@@ -343,6 +518,18 @@ void GPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("restart"), &GPUParticles2D::restart);
+ ClassDB::bind_method(D_METHOD("set_trail_enabled", "enabled"), &GPUParticles2D::set_trail_enabled);
+ ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles2D::set_trail_length);
+
+ ClassDB::bind_method(D_METHOD("is_trail_enabled"), &GPUParticles2D::is_trail_enabled);
+ ClassDB::bind_method(D_METHOD("get_trail_length"), &GPUParticles2D::get_trail_length);
+
+ ClassDB::bind_method(D_METHOD("set_trail_sections", "sections"), &GPUParticles2D::set_trail_sections);
+ ClassDB::bind_method(D_METHOD("get_trail_sections"), &GPUParticles2D::get_trail_sections);
+
+ ClassDB::bind_method(D_METHOD("set_trail_section_subdivisions", "subdivisions"), &GPUParticles2D::set_trail_section_subdivisions);
+ ClassDB::bind_method(D_METHOD("get_trail_section_subdivisions"), &GPUParticles2D::get_trail_section_subdivisions);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
ADD_GROUP("Time", "");
@@ -354,10 +541,17 @@ void GPUParticles2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
+ ADD_GROUP("Collision", "collision_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_base_size", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_collision_base_size", "get_collision_base_size");
ADD_GROUP("Drawing", "");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "visibility_rect"), "set_visibility_rect", "get_visibility_rect");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,Reverse Lifetime"), "set_draw_order", "get_draw_order");
+ ADD_GROUP("Trails", "trail_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_trail_enabled", "is_trail_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_trail_length", "get_trail_length");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_trail_sections", "get_trail_sections");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_section_subdivisions", PROPERTY_HINT_RANGE, "1,1024,1"), "set_trail_section_subdivisions", "get_trail_section_subdivisions");
ADD_GROUP("Process Material", "process_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
ADD_GROUP("Textures", "");
@@ -365,12 +559,17 @@ void GPUParticles2D::_bind_methods() {
BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
+ BIND_ENUM_CONSTANT(DRAW_ORDER_REVERSE_LIFETIME);
}
GPUParticles2D::GPUParticles2D() {
particles = RS::get_singleton()->particles_create();
RS::get_singleton()->particles_set_mode(particles, RS::PARTICLES_MODE_2D);
+ mesh = RS::get_singleton()->mesh_create();
+ RS::get_singleton()->particles_set_draw_passes(particles, 1);
+ RS::get_singleton()->particles_set_draw_pass_mesh(particles, 0, mesh);
+
one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
set_emitting(true);
set_one_shot(false);
@@ -383,10 +582,13 @@ GPUParticles2D::GPUParticles2D() {
set_randomness_ratio(0);
set_visibility_rect(Rect2(Vector2(-100, -100), Vector2(200, 200)));
set_use_local_coordinates(true);
- set_draw_order(DRAW_ORDER_INDEX);
+ set_draw_order(DRAW_ORDER_LIFETIME);
set_speed_scale(1);
+ set_fixed_fps(30);
+ set_collision_base_size(collision_base_size);
}
GPUParticles2D::~GPUParticles2D() {
RS::get_singleton()->free(particles);
+ RS::get_singleton()->free(mesh);
}
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index 20f9f768ed..9d8e61daf7 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -43,6 +43,7 @@ public:
enum DrawOrder {
DRAW_ORDER_INDEX,
DRAW_ORDER_LIFETIME,
+ DRAW_ORDER_REVERSE_LIFETIME,
};
private:
@@ -68,11 +69,23 @@ private:
void _update_particle_emission_transform();
+ NodePath sub_emitter;
+ float collision_base_size = 1.0;
+
+ bool trail_enabled = false;
+ float trail_length = 0.3;
+ int trail_sections = 8;
+ int trail_section_subdivisions = 4;
+
+ RID mesh;
+
protected:
static void _bind_methods();
virtual void _validate_property(PropertyInfo &property) const override;
void _notification(int p_what);
+ void _update_collision_size();
+
public:
void set_emitting(bool p_emitting);
void set_amount(int p_amount);
@@ -85,6 +98,11 @@ public:
void set_use_local_coordinates(bool p_enable);
void set_process_material(const Ref<Material> &p_material);
void set_speed_scale(float p_scale);
+ void set_collision_base_size(float p_ratio);
+ void set_trail_enabled(bool p_enabled);
+ void set_trail_length(float p_seconds);
+ void set_trail_sections(int p_sections);
+ void set_trail_section_subdivisions(int p_subdivisions);
bool is_emitting() const;
int get_amount() const;
@@ -98,6 +116,12 @@ public:
Ref<Material> get_process_material() const;
float get_speed_scale() const;
+ float get_collision_base_size() const;
+ bool is_trail_enabled() const;
+ float get_trail_length() const;
+ int get_trail_sections() const;
+ int get_trail_section_subdivisions() const;
+
void set_fixed_fps(int p_count);
int get_fixed_fps() const;
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index 50044ddc67..83181064c3 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -181,7 +181,7 @@ void GPUParticles3D::set_draw_order(DrawOrder p_order) {
RS::get_singleton()->particles_set_draw_order(particles, RS::ParticlesDrawOrder(p_order));
}
-void GPUParticles3D::set_enable_trail(bool p_enabled) {
+void GPUParticles3D::set_trail_enabled(bool p_enabled) {
trail_enabled = p_enabled;
RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
update_configuration_warnings();
@@ -552,7 +552,7 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles3D::emit_particle);
- ClassDB::bind_method(D_METHOD("set_enable_trail", "enabled"), &GPUParticles3D::set_enable_trail);
+ ClassDB::bind_method(D_METHOD("set_trail_enabled", "enabled"), &GPUParticles3D::set_trail_enabled);
ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles3D::set_trail_length);
ClassDB::bind_method(D_METHOD("is_trail_enabled"), &GPUParticles3D::is_trail_enabled);
@@ -579,11 +579,11 @@ void GPUParticles3D::_bind_methods() {
ADD_GROUP("Drawing", "");
ADD_PROPERTY(PropertyInfo(Variant::AABB, "visibility_aabb"), "set_visibility_aabb", "get_visibility_aabb");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,Reverse Lifetime,View Depth"), "set_draw_order", "get_draw_order");
ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_align", PROPERTY_HINT_ENUM, "Disabled,ZBillboard,YToVelocity,ZBillboardYToVelocity"), "set_transform_align", "get_transform_align");
ADD_GROUP("Trails", "trail_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_enable_trail", "is_trail_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,4,0.01"), "set_trail_length", "get_trail_length");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_trail_enabled", "is_trail_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_trail_length", "get_trail_length");
ADD_GROUP("Process Material", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
ADD_GROUP("Draw Passes", "draw_");
@@ -595,6 +595,7 @@ void GPUParticles3D::_bind_methods() {
BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
+ BIND_ENUM_CONSTANT(DRAW_ORDER_REVERSE_LIFETIME);
BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH);
BIND_ENUM_CONSTANT(EMIT_FLAG_POSITION);
@@ -632,7 +633,7 @@ GPUParticles3D::GPUParticles3D() {
set_draw_passes(1);
set_draw_order(DRAW_ORDER_INDEX);
set_speed_scale(1);
- set_collision_base_size(0.01);
+ set_collision_base_size(collision_base_size);
set_transform_align(TRANSFORM_ALIGN_DISABLED);
}
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index 1f9cea79b6..1b354b0d2a 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -44,6 +44,7 @@ public:
enum DrawOrder {
DRAW_ORDER_INDEX,
DRAW_ORDER_LIFETIME,
+ DRAW_ORDER_REVERSE_LIFETIME,
DRAW_ORDER_VIEW_DEPTH,
};
@@ -74,7 +75,7 @@ private:
bool fractional_delta;
bool interpolate = true;
NodePath sub_emitter;
- float collision_base_size;
+ float collision_base_size = 0.01;
bool trail_enabled = false;
float trail_length = 0.3;
@@ -113,7 +114,7 @@ public:
void set_process_material(const Ref<Material> &p_material);
void set_speed_scale(float p_scale);
void set_collision_base_size(float p_ratio);
- void set_enable_trail(bool p_enabled);
+ void set_trail_enabled(bool p_enabled);
void set_trail_length(float p_seconds);
bool is_emitting() const;
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index 59e699326d..a965317c81 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -1391,7 +1391,7 @@ ParticlesMaterial::ParticlesMaterial() :
set_sub_emitter_keep_velocity(false);
set_attractor_interaction_enabled(true);
- set_collision_enabled(true);
+ set_collision_enabled(false);
set_collision_bounce(0.0);
set_collision_friction(0.0);
set_collision_use_scale(false);