diff options
-rw-r--r-- | doc/classes/GPUParticles2D.xml | 7 | ||||
-rw-r--r-- | doc/classes/GPUParticles3D.xml | 7 | ||||
-rw-r--r-- | editor/plugins/cpu_particles_2d_editor_plugin.cpp | 20 | ||||
-rw-r--r-- | editor/plugins/cpu_particles_2d_editor_plugin.h | 3 | ||||
-rw-r--r-- | editor/plugins/cpu_particles_3d_editor_plugin.cpp | 17 | ||||
-rw-r--r-- | editor/plugins/cpu_particles_3d_editor_plugin.h | 4 | ||||
-rw-r--r-- | scene/2d/gpu_particles_2d.cpp | 96 | ||||
-rw-r--r-- | scene/2d/gpu_particles_2d.h | 2 | ||||
-rw-r--r-- | scene/3d/gpu_particles_3d.cpp | 93 | ||||
-rw-r--r-- | scene/3d/gpu_particles_3d.h | 2 |
10 files changed, 246 insertions, 5 deletions
diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml index d5a4c146e0..ee55288783 100644 --- a/doc/classes/GPUParticles2D.xml +++ b/doc/classes/GPUParticles2D.xml @@ -21,6 +21,13 @@ [b]Note:[/b] When using threaded rendering this method synchronizes the rendering thread. Calling it often may have a negative impact on performance. </description> </method> + <method name="convert_from_particles"> + <return type="void" /> + <param index="0" name="particles" type="Node" /> + <description> + Sets this node's properties to match a given [CPUParticles2D] node. + </description> + </method> <method name="emit_particle"> <return type="void" /> <param index="0" name="xform" type="Transform2D" /> diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml index 31f1f9e66e..fe21a486bd 100644 --- a/doc/classes/GPUParticles3D.xml +++ b/doc/classes/GPUParticles3D.xml @@ -18,6 +18,13 @@ Returns the axis-aligned bounding box that contains all the particles that are active in the current frame. </description> </method> + <method name="convert_from_particles"> + <return type="void" /> + <param index="0" name="particles" type="Node" /> + <description> + Sets this node's properties to match a given [CPUParticles3D] node. + </description> + </method> <method name="emit_particle"> <return type="void" /> <param index="0" name="xform" type="Transform3D" /> diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index 7be0d6c172..3ac9fee03f 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -33,8 +33,11 @@ #include "canvas_item_editor_plugin.h" #include "core/io/image_loader.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/gui/editor_file_dialog.h" +#include "editor/scene_tree_dock.h" #include "scene/2d/cpu_particles_2d.h" +#include "scene/2d/gpu_particles_2d.h" #include "scene/gui/check_box.h" #include "scene/gui/menu_button.h" #include "scene/gui/option_button.h" @@ -67,14 +70,26 @@ void CPUParticles2DEditorPlugin::_menu_callback(int p_idx) { switch (p_idx) { case MENU_LOAD_EMISSION_MASK: { file->popup_file_dialog(); - } break; case MENU_CLEAR_EMISSION_MASK: { emission_mask->popup_centered(); } break; case MENU_RESTART: { particles->restart(); - } + } break; + case MENU_CONVERT_TO_GPU_PARTICLES: { + GPUParticles2D *gpu_particles = memnew(GPUParticles2D); + gpu_particles->convert_from_particles(particles); + gpu_particles->set_name(particles->get_name()); + gpu_particles->set_transform(particles->get_transform()); + gpu_particles->set_visible(particles->is_visible()); + gpu_particles->set_process_mode(particles->get_process_mode()); + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Convert to GPUParticles3D")); + SceneTreeDock::get_singleton()->replace_node(particles, gpu_particles); + ur->commit_action(false); + } break; } } @@ -257,6 +272,7 @@ CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin() { menu = memnew(MenuButton); menu->get_popup()->add_item(TTR("Restart"), MENU_RESTART); menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK); + menu->get_popup()->add_item(TTR("Convert to GPUParticles2D"), MENU_CONVERT_TO_GPU_PARTICLES); menu->set_text(TTR("CPUParticles2D")); menu->set_switch_on_hover(true); toolbar->add_child(menu); diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.h b/editor/plugins/cpu_particles_2d_editor_plugin.h index ff8e171208..5077827ce8 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.h +++ b/editor/plugins/cpu_particles_2d_editor_plugin.h @@ -49,7 +49,8 @@ class CPUParticles2DEditorPlugin : public EditorPlugin { enum { MENU_LOAD_EMISSION_MASK, MENU_CLEAR_EMISSION_MASK, - MENU_RESTART + MENU_RESTART, + MENU_CONVERT_TO_GPU_PARTICLES, }; enum EmissionMode { diff --git a/editor/plugins/cpu_particles_3d_editor_plugin.cpp b/editor/plugins/cpu_particles_3d_editor_plugin.cpp index 6edfc2ef2e..1f1bc0e561 100644 --- a/editor/plugins/cpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_3d_editor_plugin.cpp @@ -31,8 +31,10 @@ #include "cpu_particles_3d_editor_plugin.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/gui/scene_tree_editor.h" #include "editor/plugins/node_3d_editor_plugin.h" +#include "editor/scene_tree_dock.h" #include "scene/gui/menu_button.h" void CPUParticles3DEditor::_node_removed(Node *p_node) { @@ -59,6 +61,20 @@ void CPUParticles3DEditor::_menu_option(int p_option) { case MENU_OPTION_RESTART: { node->restart(); + } break; + + case MENU_OPTION_CONVERT_TO_GPU_PARTICLES: { + GPUParticles3D *gpu_particles = memnew(GPUParticles3D); + gpu_particles->convert_from_particles(node); + gpu_particles->set_name(node->get_name()); + gpu_particles->set_transform(node->get_transform()); + gpu_particles->set_visible(node->is_visible()); + gpu_particles->set_process_mode(node->get_process_mode()); + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Convert to GPUParticles3D")); + SceneTreeDock::get_singleton()->replace_node(node, gpu_particles); + ur->commit_action(false); } break; } @@ -102,6 +118,7 @@ CPUParticles3DEditor::CPUParticles3DEditor() { options->set_text(TTR("CPUParticles3D")); options->get_popup()->add_item(TTR("Restart"), MENU_OPTION_RESTART); options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE); + options->get_popup()->add_item(TTR("Convert to GPUParticles3D"), MENU_OPTION_CONVERT_TO_GPU_PARTICLES); options->get_popup()->connect("id_pressed", callable_mp(this, &CPUParticles3DEditor::_menu_option)); } diff --git a/editor/plugins/cpu_particles_3d_editor_plugin.h b/editor/plugins/cpu_particles_3d_editor_plugin.h index 894e0dfb31..6de23fc2b8 100644 --- a/editor/plugins/cpu_particles_3d_editor_plugin.h +++ b/editor/plugins/cpu_particles_3d_editor_plugin.h @@ -40,8 +40,8 @@ class CPUParticles3DEditor : public GPUParticles3DEditorBase { enum Menu { MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE, MENU_OPTION_CLEAR_EMISSION_VOLUME, - MENU_OPTION_RESTART - + MENU_OPTION_RESTART, + MENU_OPTION_CONVERT_TO_GPU_PARTICLES, }; CPUParticles3D *node = nullptr; diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index 8c5782dc41..70c72dab07 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -30,7 +30,10 @@ #include "gpu_particles_2d.h" +#include "scene/2d/cpu_particles_2d.h" #include "scene/resources/atlas_texture.h" +#include "scene/resources/curve_texture.h" +#include "scene/resources/gradient_texture.h" #include "scene/resources/particle_process_material.h" #include "scene/scene_string_names.h" @@ -435,6 +438,97 @@ void GPUParticles2D::restart() { } } +void GPUParticles2D::convert_from_particles(Node *p_particles) { + CPUParticles2D *cpu_particles = Object::cast_to<CPUParticles2D>(p_particles); + ERR_FAIL_NULL_MSG(cpu_particles, "Only CPUParticles2D nodes can be converted to GPUParticles2D."); + + set_emitting(cpu_particles->is_emitting()); + set_amount(cpu_particles->get_amount()); + set_lifetime(cpu_particles->get_lifetime()); + set_one_shot(cpu_particles->get_one_shot()); + set_pre_process_time(cpu_particles->get_pre_process_time()); + set_explosiveness_ratio(cpu_particles->get_explosiveness_ratio()); + set_randomness_ratio(cpu_particles->get_randomness_ratio()); + set_use_local_coordinates(cpu_particles->get_use_local_coordinates()); + set_fixed_fps(cpu_particles->get_fixed_fps()); + set_fractional_delta(cpu_particles->get_fractional_delta()); + set_speed_scale(cpu_particles->get_speed_scale()); + set_draw_order(DrawOrder(cpu_particles->get_draw_order())); + set_texture(cpu_particles->get_texture()); + + Ref<Material> mat = cpu_particles->get_material(); + if (mat.is_valid()) { + set_material(mat); + } + + Ref<ParticleProcessMaterial> proc_mat = memnew(ParticleProcessMaterial); + set_process_material(proc_mat); + Vector2 dir = cpu_particles->get_direction(); + proc_mat->set_direction(Vector3(dir.x, dir.y, 0)); + proc_mat->set_spread(cpu_particles->get_spread()); + proc_mat->set_color(cpu_particles->get_color()); + + Ref<Gradient> color_grad = cpu_particles->get_color_ramp(); + if (color_grad.is_valid()) { + Ref<GradientTexture1D> tex = memnew(GradientTexture1D); + tex->set_gradient(color_grad); + proc_mat->set_color_ramp(tex); + } + + Ref<Gradient> color_init_grad = cpu_particles->get_color_initial_ramp(); + if (color_init_grad.is_valid()) { + Ref<GradientTexture1D> tex = memnew(GradientTexture1D); + tex->set_gradient(color_init_grad); + proc_mat->set_color_initial_ramp(tex); + } + + proc_mat->set_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, cpu_particles->get_particle_flag(CPUParticles2D::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY)); + + proc_mat->set_emission_shape(ParticleProcessMaterial::EmissionShape(cpu_particles->get_emission_shape())); + proc_mat->set_emission_sphere_radius(cpu_particles->get_emission_sphere_radius()); + + Vector2 rect_extents = cpu_particles->get_emission_rect_extents(); + proc_mat->set_emission_box_extents(Vector3(rect_extents.x, rect_extents.y, 0)); + + if (cpu_particles->get_split_scale()) { + Ref<CurveXYZTexture> scale3D = memnew(CurveXYZTexture); + scale3D->set_curve_x(cpu_particles->get_scale_curve_x()); + scale3D->set_curve_y(cpu_particles->get_scale_curve_y()); + proc_mat->set_param_texture(ParticleProcessMaterial::PARAM_SCALE, scale3D); + } + + Vector2 gravity = cpu_particles->get_gravity(); + proc_mat->set_gravity(Vector3(gravity.x, gravity.y, 0)); + proc_mat->set_lifetime_randomness(cpu_particles->get_lifetime_randomness()); + +#define CONVERT_PARAM(m_param) \ + proc_mat->set_param_min(ParticleProcessMaterial::m_param, cpu_particles->get_param_min(CPUParticles2D::m_param)); \ + { \ + Ref<Curve> curve = cpu_particles->get_param_curve(CPUParticles2D::m_param); \ + if (curve.is_valid()) { \ + Ref<CurveTexture> tex = memnew(CurveTexture); \ + tex->set_curve(curve); \ + proc_mat->set_param_texture(ParticleProcessMaterial::m_param, tex); \ + } \ + } \ + proc_mat->set_param_max(ParticleProcessMaterial::m_param, cpu_particles->get_param_max(CPUParticles2D::m_param)); + + CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY); + CONVERT_PARAM(PARAM_ANGULAR_VELOCITY); + CONVERT_PARAM(PARAM_ORBIT_VELOCITY); + CONVERT_PARAM(PARAM_LINEAR_ACCEL); + CONVERT_PARAM(PARAM_RADIAL_ACCEL); + CONVERT_PARAM(PARAM_TANGENTIAL_ACCEL); + CONVERT_PARAM(PARAM_DAMPING); + CONVERT_PARAM(PARAM_ANGLE); + CONVERT_PARAM(PARAM_SCALE); + CONVERT_PARAM(PARAM_HUE_VARIATION); + CONVERT_PARAM(PARAM_ANIM_SPEED); + CONVERT_PARAM(PARAM_ANIM_OFFSET); + +#undef CONVERT_PARAM +} + void GPUParticles2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_DRAW: { @@ -680,6 +774,8 @@ void GPUParticles2D::_bind_methods() { 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); + ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &GPUParticles2D::convert_from_particles); + ADD_SIGNAL(MethodInfo("finished")); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h index 3131698e5c..97690b07fa 100644 --- a/scene/2d/gpu_particles_2d.h +++ b/scene/2d/gpu_particles_2d.h @@ -169,6 +169,8 @@ public: void restart(); Rect2 capture_rect() const; + void convert_from_particles(Node *p_particles); + GPUParticles2D(); ~GPUParticles2D(); }; diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index 3a23cbcff1..a7667267a6 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -30,6 +30,9 @@ #include "gpu_particles_3d.h" +#include "scene/3d/cpu_particles_3d.h" +#include "scene/resources/curve_texture.h" +#include "scene/resources/gradient_texture.h" #include "scene/resources/particle_process_material.h" #include "scene/scene_string_names.h" @@ -546,10 +549,98 @@ void GPUParticles3D::set_transform_align(TransformAlign p_align) { transform_align = p_align; RS::get_singleton()->particles_set_transform_align(particles, RS::ParticlesTransformAlign(transform_align)); } + GPUParticles3D::TransformAlign GPUParticles3D::get_transform_align() const { return transform_align; } +void GPUParticles3D::convert_from_particles(Node *p_particles) { + CPUParticles3D *cpu_particles = Object::cast_to<CPUParticles3D>(p_particles); + ERR_FAIL_NULL_MSG(cpu_particles, "Only CPUParticles3D nodes can be converted to GPUParticles3D."); + + set_emitting(cpu_particles->is_emitting()); + set_amount(cpu_particles->get_amount()); + set_lifetime(cpu_particles->get_lifetime()); + set_one_shot(cpu_particles->get_one_shot()); + set_pre_process_time(cpu_particles->get_pre_process_time()); + set_explosiveness_ratio(cpu_particles->get_explosiveness_ratio()); + set_randomness_ratio(cpu_particles->get_randomness_ratio()); + set_use_local_coordinates(cpu_particles->get_use_local_coordinates()); + set_fixed_fps(cpu_particles->get_fixed_fps()); + set_fractional_delta(cpu_particles->get_fractional_delta()); + set_speed_scale(cpu_particles->get_speed_scale()); + set_draw_order(DrawOrder(cpu_particles->get_draw_order())); + set_draw_pass_mesh(0, cpu_particles->get_mesh()); + + Ref<ParticleProcessMaterial> proc_mat = memnew(ParticleProcessMaterial); + set_process_material(proc_mat); + + proc_mat->set_direction(cpu_particles->get_direction()); + proc_mat->set_spread(cpu_particles->get_spread()); + proc_mat->set_flatness(cpu_particles->get_flatness()); + proc_mat->set_color(cpu_particles->get_color()); + + Ref<Gradient> grad = cpu_particles->get_color_ramp(); + if (grad.is_valid()) { + Ref<GradientTexture1D> tex = memnew(GradientTexture1D); + tex->set_gradient(grad); + proc_mat->set_color_ramp(tex); + } + + Ref<Gradient> grad_init = cpu_particles->get_color_initial_ramp(); + if (grad_init.is_valid()) { + Ref<GradientTexture1D> tex = memnew(GradientTexture1D); + tex->set_gradient(grad_init); + proc_mat->set_color_initial_ramp(tex); + } + + proc_mat->set_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, cpu_particles->get_particle_flag(CPUParticles3D::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY)); + proc_mat->set_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ROTATE_Y, cpu_particles->get_particle_flag(CPUParticles3D::PARTICLE_FLAG_ROTATE_Y)); + proc_mat->set_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_DISABLE_Z, cpu_particles->get_particle_flag(CPUParticles3D::PARTICLE_FLAG_DISABLE_Z)); + + proc_mat->set_emission_shape(ParticleProcessMaterial::EmissionShape(cpu_particles->get_emission_shape())); + proc_mat->set_emission_sphere_radius(cpu_particles->get_emission_sphere_radius()); + proc_mat->set_emission_box_extents(cpu_particles->get_emission_box_extents()); + + if (cpu_particles->get_split_scale()) { + Ref<CurveXYZTexture> scale3D = memnew(CurveXYZTexture); + scale3D->set_curve_x(cpu_particles->get_scale_curve_x()); + scale3D->set_curve_y(cpu_particles->get_scale_curve_y()); + scale3D->set_curve_z(cpu_particles->get_scale_curve_z()); + proc_mat->set_param_texture(ParticleProcessMaterial::PARAM_SCALE, scale3D); + } + + proc_mat->set_gravity(cpu_particles->get_gravity()); + proc_mat->set_lifetime_randomness(cpu_particles->get_lifetime_randomness()); + +#define CONVERT_PARAM(m_param) \ + proc_mat->set_param_min(ParticleProcessMaterial::m_param, cpu_particles->get_param_min(CPUParticles3D::m_param)); \ + { \ + Ref<Curve> curve = cpu_particles->get_param_curve(CPUParticles3D::m_param); \ + if (curve.is_valid()) { \ + Ref<CurveTexture> tex = memnew(CurveTexture); \ + tex->set_curve(curve); \ + proc_mat->set_param_texture(ParticleProcessMaterial::m_param, tex); \ + } \ + } \ + proc_mat->set_param_max(ParticleProcessMaterial::m_param, cpu_particles->get_param_max(CPUParticles3D::m_param)); + + CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY); + CONVERT_PARAM(PARAM_ANGULAR_VELOCITY); + CONVERT_PARAM(PARAM_ORBIT_VELOCITY); + CONVERT_PARAM(PARAM_LINEAR_ACCEL); + CONVERT_PARAM(PARAM_RADIAL_ACCEL); + CONVERT_PARAM(PARAM_TANGENTIAL_ACCEL); + CONVERT_PARAM(PARAM_DAMPING); + CONVERT_PARAM(PARAM_ANGLE); + CONVERT_PARAM(PARAM_SCALE); + CONVERT_PARAM(PARAM_HUE_VARIATION); + CONVERT_PARAM(PARAM_ANIM_SPEED); + CONVERT_PARAM(PARAM_ANIM_OFFSET); + +#undef CONVERT_PARAM +} + void GPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &GPUParticles3D::set_emitting); ClassDB::bind_method(D_METHOD("set_amount", "amount"), &GPUParticles3D::set_amount); @@ -613,6 +704,8 @@ void GPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transform_align", "align"), &GPUParticles3D::set_transform_align); ClassDB::bind_method(D_METHOD("get_transform_align"), &GPUParticles3D::get_transform_align); + ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &GPUParticles3D::convert_from_particles); + ADD_SIGNAL(MethodInfo("finished")); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h index dba6a8f2ab..6e9083bda2 100644 --- a/scene/3d/gpu_particles_3d.h +++ b/scene/3d/gpu_particles_3d.h @@ -178,6 +178,8 @@ public: void emit_particle(const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags); AABB capture_aabb() const; + void convert_from_particles(Node *p_particles); + GPUParticles3D(); ~GPUParticles3D(); }; |