Implement conversion from `CPUParticles` to `GPUParticles` (3D/2D)
This commit is contained in:
parent
b51ee8b029
commit
7fcb91f077
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -169,6 +169,8 @@ public:
|
|||
|
||||
void restart();
|
||||
Rect2 capture_rect() const;
|
||||
void convert_from_particles(Node *p_particles);
|
||||
|
||||
GPUParticles2D();
|
||||
~GPUParticles2D();
|
||||
};
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue