Renamed Particle to GPUParticle and Particle2D to GPUParticle2D pt4.

This commit is contained in:
Relintai 2024-07-16 16:59:21 +02:00
parent a97a334ebd
commit 85cddb07b4
17 changed files with 705 additions and 5 deletions

View File

@ -134,6 +134,8 @@
#include "editor/plugins/navigation_obstacle_2d_editor_plugin.h" #include "editor/plugins/navigation_obstacle_2d_editor_plugin.h"
#include "editor/plugins/navigation_obstacle_3d_editor_plugin.h" #include "editor/plugins/navigation_obstacle_3d_editor_plugin.h"
#include "editor/plugins/packed_scene_editor_plugin.h" #include "editor/plugins/packed_scene_editor_plugin.h"
#include "editor/plugins/gpu_particles_2d_editor_plugin.h"
#include "editor/plugins/particles_editor_plugin.h"
#include "editor/plugins/path_2d_editor_plugin.h" #include "editor/plugins/path_2d_editor_plugin.h"
#include "editor/plugins/path_editor_plugin.h" #include "editor/plugins/path_editor_plugin.h"
#include "editor/plugins/polygon_2d_editor_plugin.h" #include "editor/plugins/polygon_2d_editor_plugin.h"
@ -7164,6 +7166,7 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(AnimationTreeEditorPlugin(this))); add_editor_plugin(memnew(AnimationTreeEditorPlugin(this)));
add_editor_plugin(memnew(StyleBoxEditorPlugin(this))); add_editor_plugin(memnew(StyleBoxEditorPlugin(this)));
add_editor_plugin(memnew(SpriteEditorPlugin(this))); add_editor_plugin(memnew(SpriteEditorPlugin(this)));
add_editor_plugin(memnew(GPUParticlesEditorPlugin(this)));
add_editor_plugin(memnew(CPUParticles2DEditorPlugin(this))); add_editor_plugin(memnew(CPUParticles2DEditorPlugin(this)));
add_editor_plugin(memnew(CPUParticlesEditorPlugin(this))); add_editor_plugin(memnew(CPUParticlesEditorPlugin(this)));
add_editor_plugin(memnew(ResourcePreloaderEditorPlugin(this))); add_editor_plugin(memnew(ResourcePreloaderEditorPlugin(this)));
@ -7173,6 +7176,7 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(SpriteFramesEditorPlugin(this))); add_editor_plugin(memnew(SpriteFramesEditorPlugin(this)));
add_editor_plugin(memnew(TextureRegionEditorPlugin(this))); add_editor_plugin(memnew(TextureRegionEditorPlugin(this)));
add_editor_plugin(memnew(BakedLightmapEditorPlugin(this))); add_editor_plugin(memnew(BakedLightmapEditorPlugin(this)));
add_editor_plugin(memnew(GPUParticles2DEditorPlugin(this)));
add_editor_plugin(memnew(RoomManagerEditorPlugin(this))); add_editor_plugin(memnew(RoomManagerEditorPlugin(this)));
add_editor_plugin(memnew(RoomEditorPlugin(this))); add_editor_plugin(memnew(RoomEditorPlugin(this)));
add_editor_plugin(memnew(OccluderEditorPlugin(this))); add_editor_plugin(memnew(OccluderEditorPlugin(this)));

View File

Before

Width:  |  Height:  |  Size: 470 B

After

Width:  |  Height:  |  Size: 470 B

View File

Before

Width:  |  Height:  |  Size: 448 B

After

Width:  |  Height:  |  Size: 448 B

View File

@ -66,6 +66,7 @@
#include "editor/scene_tree_dock.h" #include "editor/scene_tree_dock.h"
#include "editor/script_editor_debugger.h" #include "editor/script_editor_debugger.h"
#include "scene/2d/light_2d.h" #include "scene/2d/light_2d.h"
#include "scene/2d/gpu_particles_2d.h"
#include "scene/2d/polygon_2d.h" #include "scene/2d/polygon_2d.h"
#include "scene/main/node_2d.h" #include "scene/main/node_2d.h"
@ -6141,6 +6142,8 @@ void CanvasItemEditorViewport::_perform_drop_data() {
Node *child; Node *child;
if (default_type == "Light2D") { if (default_type == "Light2D") {
child = memnew(Light2D); child = memnew(Light2D);
} else if (default_type == "GPUParticles2D") {
child = memnew(GPUParticles2D);
} else if (default_type == "Polygon2D") { } else if (default_type == "Polygon2D") {
child = memnew(Polygon2D); child = memnew(Polygon2D);
} else if (default_type == "TouchScreenButton") { } else if (default_type == "TouchScreenButton") {

View File

@ -110,8 +110,7 @@ void GPUParticles2DEditorPlugin::_menu_callback(int p_idx) {
} break; } break;
case MENU_OPTION_CONVERT_TO_CPU_PARTICLES: { case MENU_OPTION_CONVERT_TO_CPU_PARTICLES: {
CPUParticles2D *cpu_particles = memnew(CPUParticles2D); CPUParticles2D *cpu_particles = memnew(CPUParticles2D);
//TODO cpu_particles->convert_from_particles(particles);
//cpu_particles->convert_from_particles(particles);
cpu_particles->set_name(particles->get_name()); cpu_particles->set_name(particles->get_name());
cpu_particles->set_transform(particles->get_transform()); cpu_particles->set_transform(particles->get_transform());
cpu_particles->set_visible(particles->is_visible()); cpu_particles->set_visible(particles->is_visible());

View File

@ -56,8 +56,13 @@
#include "scene/gui/dialogs.h" #include "scene/gui/dialogs.h"
#include "scene/gui/option_button.h" #include "scene/gui/option_button.h"
#include "scene/gui/spin_box.h" #include "scene/gui/spin_box.h"
#include "scene/gui/popup_menu.h"
#include "scene/main/node.h" #include "scene/main/node.h"
#include "scene/main/spatial.h" #include "scene/main/spatial.h"
#include "scene/3d/gpu_particles.h"
#include "scene/3d/cpu_particles.h"
#include "scene/resources/material/particles_material.h"
#include "editor/plugins/spatial_editor_plugin.h"
bool ParticlesEditorBase::_generate(PoolVector<Vector3> &points, PoolVector<Vector3> &normals) { bool ParticlesEditorBase::_generate(PoolVector<Vector3> &points, PoolVector<Vector3> &normals) {
bool use_normals = emission_fill->get_selected() == 1; bool use_normals = emission_fill->get_selected() == 1;
@ -261,3 +266,266 @@ ParticlesEditorBase::ParticlesEditorBase() {
emission_file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE); emission_file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
} }
void GPUParticlesEditor::_node_removed(Node *p_node) {
if (p_node == node) {
node = nullptr;
hide();
}
}
void GPUParticlesEditor::_notification(int p_notification) {
if (p_notification == NOTIFICATION_ENTER_TREE) {
options->set_icon(options->get_popup()->get_theme_icon("GPUParticles", "EditorIcons"));
get_tree()->connect("node_removed", this, "_node_removed");
}
}
void GPUParticlesEditor::_menu_option(int p_option) {
switch (p_option) {
case MENU_OPTION_GENERATE_AABB: {
// Add one second to the default generation lifetime, since the progress is updated every second.
generate_seconds->set_value(MAX(1.0, trunc(node->get_lifetime()) + 1.0));
if (generate_seconds->get_value() >= 11.0 + CMP_EPSILON) {
// Only pop up the time dialog if the particle's lifetime is long enough to warrant shortening it.
generate_aabb->popup_centered_minsize();
} else {
// Generate the visibility AABB immediately.
_generate_aabb();
}
} break;
case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH: {
Ref<ParticlesMaterial> material = node->get_process_material();
if (material.is_null()) {
EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required."));
return;
}
emission_file_dialog->popup_centered_ratio();
} break;
case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: {
Ref<ParticlesMaterial> material = node->get_process_material();
if (material.is_null()) {
EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required."));
return;
}
emission_tree_dialog->popup_centered_ratio();
} break;
case MENU_OPTION_CONVERT_TO_CPU_PARTICLES: {
CPUParticles *cpu_particles = memnew(CPUParticles);
cpu_particles->convert_from_particles(node);
cpu_particles->set_name(node->get_name());
cpu_particles->set_transform(node->get_transform());
cpu_particles->set_visible(node->is_visible());
cpu_particles->set_pause_mode(node->get_pause_mode());
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Convert to CPUParticles"));
ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, cpu_particles, true, false);
ur->add_do_reference(cpu_particles);
ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", cpu_particles, node, false, false);
ur->add_undo_reference(node);
ur->commit_action();
} break;
case MENU_OPTION_RESTART: {
node->restart();
} break;
}
}
void GPUParticlesEditor::_generate_aabb() {
float time = generate_seconds->get_value();
float running = 0.0;
EditorProgress ep("gen_aabb", TTR("Generating Visibility AABB (Waiting for Particle Simulation)"), int(time));
bool was_emitting = node->is_emitting();
if (!was_emitting) {
node->set_emitting(true);
OS::get_singleton()->delay_usec(1000);
}
AABB rect;
while (running < time) {
uint64_t ticks = OS::get_singleton()->get_ticks_usec();
ep.step("Generating...", int(running), true);
OS::get_singleton()->delay_usec(1000);
AABB capture = node->capture_aabb();
if (rect == AABB()) {
rect = capture;
} else {
rect.merge_with(capture);
}
running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0;
}
if (!was_emitting) {
node->set_emitting(false);
}
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Generate Visibility AABB"));
ur->add_do_method(node, "set_visibility_aabb", rect);
ur->add_undo_method(node, "set_visibility_aabb", node->get_visibility_aabb());
ur->commit_action();
}
void GPUParticlesEditor::edit(GPUParticles *p_particles) {
base_node = p_particles;
node = p_particles;
}
void GPUParticlesEditor::_generate_emission_points() {
/// hacer codigo aca
PoolVector<Vector3> points;
PoolVector<Vector3> normals;
if (!_generate(points, normals)) {
return;
}
int point_count = points.size();
int w = 2048;
int h = (point_count / 2048) + 1;
PoolVector<uint8_t> point_img;
point_img.resize(w * h * 3 * sizeof(float));
{
PoolVector<uint8_t>::Write iw = point_img.write();
memset(iw.ptr(), 0, w * h * 3 * sizeof(float));
PoolVector<Vector3>::Read r = points.read();
float *wf = (float *)iw.ptr();
for (int i = 0; i < point_count; i++) {
wf[i * 3 + 0] = r[i].x;
wf[i * 3 + 1] = r[i].y;
wf[i * 3 + 2] = r[i].z;
}
}
Ref<Image> image = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img));
Ref<ImageTexture> tex;
tex.instance();
tex->create_from_image(image, Texture::FLAG_FILTER);
Ref<ParticlesMaterial> material = node->get_process_material();
ERR_FAIL_COND(material.is_null());
if (normals.size() > 0) {
material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
material->set_emission_point_count(point_count);
material->set_emission_point_texture(tex);
PoolVector<uint8_t> point_img2;
point_img2.resize(w * h * 3 * sizeof(float));
{
PoolVector<uint8_t>::Write iw = point_img2.write();
memset(iw.ptr(), 0, w * h * 3 * sizeof(float));
PoolVector<Vector3>::Read r = normals.read();
float *wf = (float *)iw.ptr();
for (int i = 0; i < point_count; i++) {
wf[i * 3 + 0] = r[i].x;
wf[i * 3 + 1] = r[i].y;
wf[i * 3 + 2] = r[i].z;
}
}
Ref<Image> image2 = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img2));
Ref<ImageTexture> tex2;
tex2.instance();
tex2->create_from_image(image2, Texture::FLAG_FILTER);
material->set_emission_normal_texture(tex2);
} else {
material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS);
material->set_emission_point_count(point_count);
material->set_emission_point_texture(tex);
}
}
void GPUParticlesEditor::_bind_methods() {
ClassDB::bind_method("_menu_option", &GPUParticlesEditor::_menu_option);
ClassDB::bind_method("_generate_aabb", &GPUParticlesEditor::_generate_aabb);
ClassDB::bind_method("_node_removed", &GPUParticlesEditor::_node_removed);
}
GPUParticlesEditor::GPUParticlesEditor() {
node = nullptr;
particles_editor_hb = memnew(HBoxContainer);
SpatialEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb);
options = memnew(MenuButton);
options->set_switch_on_hover(true);
particles_editor_hb->add_child(options);
particles_editor_hb->hide();
options->set_text(TTR("GPUParticles"));
options->get_popup()->add_item(TTR("Generate Visibility AABB"), MENU_OPTION_GENERATE_AABB);
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("Create Emission Points From Mesh"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH);
options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE);
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("Convert to CPUParticles"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES);
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("Restart"), MENU_OPTION_RESTART);
options->get_popup()->connect("id_pressed", this, "_menu_option");
generate_aabb = memnew(ConfirmationDialog);
generate_aabb->set_title(TTR("Generate Visibility AABB"));
VBoxContainer *genvb = memnew(VBoxContainer);
generate_aabb->add_child(genvb);
generate_seconds = memnew(SpinBox);
genvb->add_margin_child(TTR("Generation Time (sec):"), generate_seconds);
generate_seconds->set_min(0.1);
generate_seconds->set_max(25);
generate_seconds->set_value(2);
add_child(generate_aabb);
generate_aabb->connect("confirmed", this, "_generate_aabb");
}
void GPUParticlesEditorPlugin::edit(Object *p_object) {
particles_editor->edit(Object::cast_to<GPUParticles>(p_object));
}
bool GPUParticlesEditorPlugin::handles(Object *p_object) const {
return p_object->is_class("GPUParticles");
}
void GPUParticlesEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
particles_editor->show();
particles_editor->particles_editor_hb->show();
} else {
particles_editor->particles_editor_hb->hide();
particles_editor->hide();
particles_editor->edit(nullptr);
}
}
GPUParticlesEditorPlugin::GPUParticlesEditorPlugin(EditorNode *p_node) {
editor = p_node;
particles_editor = memnew(GPUParticlesEditor);
editor->get_viewport()->add_child(particles_editor);
particles_editor->hide();
}
GPUParticlesEditorPlugin::~GPUParticlesEditorPlugin() {
}

View File

@ -49,6 +49,7 @@ class Panel;
class SceneTreeDialog; class SceneTreeDialog;
class Spatial; class Spatial;
class SpinBox; class SpinBox;
class GPUParticles;
struct Vector3; struct Vector3;
class ParticlesEditorBase : public Control { class ParticlesEditorBase : public Control {
@ -79,4 +80,58 @@ public:
ParticlesEditorBase(); ParticlesEditorBase();
}; };
class GPUParticlesEditor : public ParticlesEditorBase {
GDCLASS(GPUParticlesEditor, ParticlesEditorBase);
ConfirmationDialog *generate_aabb;
SpinBox *generate_seconds;
GPUParticles *node;
enum Menu {
MENU_OPTION_GENERATE_AABB,
MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE,
MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH,
MENU_OPTION_CLEAR_EMISSION_VOLUME,
MENU_OPTION_CONVERT_TO_CPU_PARTICLES,
MENU_OPTION_RESTART,
};
void _generate_aabb();
void _menu_option(int);
friend class GPUParticlesEditorPlugin;
virtual void _generate_emission_points();
protected:
void _notification(int p_notification);
void _node_removed(Node *p_node);
static void _bind_methods();
public:
void edit(GPUParticles *p_particles);
GPUParticlesEditor();
};
class GPUParticlesEditorPlugin : public EditorPlugin {
GDCLASS(GPUParticlesEditorPlugin, EditorPlugin);
GPUParticlesEditor *particles_editor;
EditorNode *editor;
public:
virtual String get_name() const { return "GPUParticles"; }
bool has_main_screen() const { return false; }
virtual void edit(Object *p_object);
virtual bool handles(Object *p_object) const;
virtual void make_visible(bool p_visible);
GPUParticlesEditorPlugin(EditorNode *p_node);
~GPUParticlesEditorPlugin();
};
#endif // PARTICLES_EDITOR_PLUGIN_H #endif // PARTICLES_EDITOR_PLUGIN_H

View File

@ -7186,6 +7186,7 @@ void SpatialEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<SpringArmSpatialGizmoPlugin>(memnew(SpringArmSpatialGizmoPlugin))); add_gizmo_plugin(Ref<SpringArmSpatialGizmoPlugin>(memnew(SpringArmSpatialGizmoPlugin)));
add_gizmo_plugin(Ref<VehicleWheelSpatialGizmoPlugin>(memnew(VehicleWheelSpatialGizmoPlugin))); add_gizmo_plugin(Ref<VehicleWheelSpatialGizmoPlugin>(memnew(VehicleWheelSpatialGizmoPlugin)));
add_gizmo_plugin(Ref<VisibilityNotifierGizmoPlugin>(memnew(VisibilityNotifierGizmoPlugin))); add_gizmo_plugin(Ref<VisibilityNotifierGizmoPlugin>(memnew(VisibilityNotifierGizmoPlugin)));
add_gizmo_plugin(Ref<GPUParticlesGizmoPlugin>(memnew(GPUParticlesGizmoPlugin)));
add_gizmo_plugin(Ref<CPUParticlesGizmoPlugin>(memnew(CPUParticlesGizmoPlugin))); add_gizmo_plugin(Ref<CPUParticlesGizmoPlugin>(memnew(CPUParticlesGizmoPlugin)));
add_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin))); add_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin)));
add_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin))); add_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin)));

View File

@ -82,6 +82,7 @@
#include "scene/3d/sprite_3d.h" #include "scene/3d/sprite_3d.h"
#include "scene/3d/vehicle_body.h" #include "scene/3d/vehicle_body.h"
#include "scene/3d/visibility_notifier.h" #include "scene/3d/visibility_notifier.h"
#include "scene/3d/gpu_particles.h"
#include "scene/main/control.h" #include "scene/main/control.h"
#include "scene/main/node.h" #include "scene/main/node.h"
#include "scene/main/scene_tree.h" #include "scene/main/scene_tree.h"
@ -2661,6 +2662,169 @@ void CPUParticlesGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
//// ////
GPUParticlesGizmoPlugin::GPUParticlesGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4));
create_material("particles_material", gizmo_color);
gizmo_color.a = 0.1;
create_material("particles_solid_material", gizmo_color);
create_icon_material("particles_icon", SpatialEditor::get_singleton()->get_theme_icon("GizmoParticles", "EditorIcons"));
create_handle_material("handles");
}
bool GPUParticlesGizmoPlugin::has_gizmo(Spatial *p_spatial) {
return Object::cast_to<GPUParticles>(p_spatial) != nullptr;
}
String GPUParticlesGizmoPlugin::get_gizmo_name() const {
return "GPUParticles";
}
int GPUParticlesGizmoPlugin::get_priority() const {
return -1;
}
bool GPUParticlesGizmoPlugin::is_selectable_when_hidden() const {
return true;
}
String GPUParticlesGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary) const {
switch (p_id) {
case 0:
return "Size X";
case 1:
return "Size Y";
case 2:
return "Size Z";
case 3:
return "Pos X";
case 4:
return "Pos Y";
case 5:
return "Pos Z";
}
return "";
}
Variant GPUParticlesGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary) const {
GPUParticles *particles = Object::cast_to<GPUParticles>(p_gizmo->get_spatial_node());
return particles->get_visibility_aabb();
}
void GPUParticlesGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary, Camera *p_camera, const Point2 &p_point) {
GPUParticles *particles = Object::cast_to<GPUParticles>(p_gizmo->get_spatial_node());
Transform gt = particles->get_global_transform();
Transform gi = gt.affine_inverse();
bool move = p_id >= 3;
p_id = p_id % 3;
AABB aabb = particles->get_visibility_aabb();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
Vector3 ofs = aabb.position + aabb.size * 0.5;
Vector3 axis;
axis[p_id] = 1.0;
if (move) {
Vector3 ra, rb;
Geometry::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb);
float d = ra[p_id];
if (SpatialEditor::get_singleton()->is_snap_enabled()) {
d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
}
aabb.position[p_id] = d - 1.0 - aabb.size[p_id] * 0.5;
particles->set_visibility_aabb(aabb);
} else {
Vector3 ra, rb;
Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb);
float d = ra[p_id] - ofs[p_id];
if (SpatialEditor::get_singleton()->is_snap_enabled()) {
d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap());
}
if (d < 0.001) {
d = 0.001;
}
//resize
aabb.position[p_id] = (aabb.position[p_id] + aabb.size[p_id] * 0.5) - d;
aabb.size[p_id] = d * 2;
particles->set_visibility_aabb(aabb);
}
}
void GPUParticlesGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
GPUParticles *particles = Object::cast_to<GPUParticles>(p_gizmo->get_spatial_node());
if (p_cancel) {
particles->set_visibility_aabb(p_restore);
return;
}
UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
ur->create_action(TTR("Change Particles AABB"));
ur->add_do_method(particles, "set_visibility_aabb", particles->get_visibility_aabb());
ur->add_undo_method(particles, "set_visibility_aabb", p_restore);
ur->commit_action();
}
void GPUParticlesGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
GPUParticles *particles = Object::cast_to<GPUParticles>(p_gizmo->get_spatial_node());
p_gizmo->clear();
Vector<Vector3> lines;
AABB aabb = particles->get_visibility_aabb();
for (int i = 0; i < 12; i++) {
Vector3 a, b;
aabb.get_edge(i, a, b);
lines.push_back(a);
lines.push_back(b);
}
Vector<Vector3> handles;
for (int i = 0; i < 3; i++) {
Vector3 ax;
ax[i] = aabb.position[i] + aabb.size[i];
ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5;
ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5;
handles.push_back(ax);
}
Vector3 center = aabb.position + aabb.size * 0.5;
for (int i = 0; i < 3; i++) {
Vector3 ax;
ax[i] = 1.0;
handles.push_back(center + ax);
lines.push_back(center);
lines.push_back(center + ax);
}
Ref<Material> material = get_material("particles_material", p_gizmo);
Ref<Material> icon = get_material("particles_icon", p_gizmo);
p_gizmo->add_lines(lines, material);
if (p_gizmo->is_selected()) {
Ref<Material> solid_material = get_material("particles_solid_material", p_gizmo);
p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0);
}
p_gizmo->add_handles(handles, get_material("handles"));
p_gizmo->add_unscaled_billboard(icon, 0.05);
}
////
ReflectionProbeGizmoPlugin::ReflectionProbeGizmoPlugin() { ReflectionProbeGizmoPlugin::ReflectionProbeGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5)); Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5));

View File

@ -436,6 +436,24 @@ public:
CPUParticlesGizmoPlugin(); CPUParticlesGizmoPlugin();
}; };
class GPUParticlesGizmoPlugin : public EditorSpatialGizmoPlugin {
GDCLASS(GPUParticlesGizmoPlugin, EditorSpatialGizmoPlugin);
public:
bool has_gizmo(Spatial *p_spatial);
String get_gizmo_name() const;
int get_priority() const;
bool is_selectable_when_hidden() const;
void redraw(EditorSpatialGizmo *p_gizmo);
String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary) const;
Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary) const;
void set_handle(EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary, Camera *p_camera, const Point2 &p_point);
void commit_handle(EditorSpatialGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false);
GPUParticlesGizmoPlugin();
};
class ReflectionProbeGizmoPlugin : public EditorSpatialGizmoPlugin { class ReflectionProbeGizmoPlugin : public EditorSpatialGizmoPlugin {
GDCLASS(ReflectionProbeGizmoPlugin, EditorSpatialGizmoPlugin); GDCLASS(ReflectionProbeGizmoPlugin, EditorSpatialGizmoPlugin);

View File

@ -37,6 +37,7 @@
#include "core/os/os.h" #include "core/os/os.h"
#include "scene/main/canvas_item.h" #include "scene/main/canvas_item.h"
#include "scene/2d/gpu_particles_2d.h"
#include "scene/resources/material/particles_material.h" #include "scene/resources/material/particles_material.h"
#include "scene/resources/texture.h" #include "scene/resources/texture.h"
#include "servers/rendering_server.h" #include "servers/rendering_server.h"
@ -1282,6 +1283,86 @@ void CPUParticles2D::_notification(int p_what) {
#endif #endif
} }
void CPUParticles2D::convert_from_particles(Node *p_particles) {
GPUParticles2D *particles = Object::cast_to<GPUParticles2D>(p_particles);
ERR_FAIL_COND_MSG(!particles, "Only GPUParticles2D nodes can be converted to CPUParticles2D.");
set_emitting(particles->is_emitting());
set_amount(particles->get_amount());
set_lifetime(particles->get_lifetime());
set_one_shot(particles->get_one_shot());
set_pre_process_time(particles->get_pre_process_time());
set_explosiveness_ratio(particles->get_explosiveness_ratio());
set_randomness_ratio(particles->get_randomness_ratio());
set_use_local_coordinates(particles->get_use_local_coordinates());
set_fixed_fps(particles->get_fixed_fps());
set_fractional_delta(particles->get_fractional_delta());
set_speed_scale(particles->get_speed_scale());
set_draw_order(DrawOrder(particles->get_draw_order()));
set_texture(particles->get_texture());
Ref<Material> mat = particles->get_material();
if (mat.is_valid()) {
set_material(mat);
}
Ref<ParticlesMaterial> material = particles->get_process_material();
if (material.is_null()) {
return;
}
Vector3 dir = material->get_direction();
set_direction(Vector2(dir.x, dir.y));
set_spread(material->get_spread());
set_color(material->get_color());
Ref<GradientTexture> gt = material->get_color_ramp();
if (gt.is_valid()) {
set_color_ramp(gt->get_gradient());
}
Ref<GradientTexture> gti = material->get_color_initial_ramp();
if (gti.is_valid()) {
set_color_initial_ramp(gti->get_gradient());
}
set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY));
set_emission_shape(EmissionShape(material->get_emission_shape()));
set_emission_sphere_radius(material->get_emission_sphere_radius());
Vector2 rect_extents = Vector2(material->get_emission_box_extents().x, material->get_emission_box_extents().y);
set_emission_rect_extents(rect_extents);
Vector2 gravity = Vector2(material->get_gravity().x, material->get_gravity().y);
set_gravity(gravity);
set_lifetime_randomness(material->get_lifetime_randomness());
#define CONVERT_PARAM(m_param) \
set_param(m_param, material->get_param(ParticlesMaterial::m_param)); \
{ \
Ref<CurveTexture> ctex = material->get_param_texture(ParticlesMaterial::m_param); \
if (ctex.is_valid()) \
set_param_curve(m_param, ctex->get_curve()); \
} \
set_param_randomness(m_param, material->get_param_randomness(ParticlesMaterial::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 CPUParticles2D::_bind_methods() { void CPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &CPUParticles2D::set_emitting); ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &CPUParticles2D::set_emitting);
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &CPUParticles2D::set_amount); ClassDB::bind_method(D_METHOD("set_amount", "amount"), &CPUParticles2D::set_amount);
@ -1393,6 +1474,8 @@ void CPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles2D::get_gravity); ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles2D::get_gravity);
ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles2D::set_gravity); ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles2D::set_gravity);
ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles2D::convert_from_particles);
ClassDB::bind_method(D_METHOD("_update_render_thread"), &CPUParticles2D::_update_render_thread); ClassDB::bind_method(D_METHOD("_update_render_thread"), &CPUParticles2D::_update_render_thread);
ClassDB::bind_method(D_METHOD("_texture_changed"), &CPUParticles2D::_texture_changed); ClassDB::bind_method(D_METHOD("_texture_changed"), &CPUParticles2D::_texture_changed);

View File

@ -356,6 +356,8 @@ public:
void restart(); void restart();
void convert_from_particles(Node *p_particles);
CPUParticles2D(); CPUParticles2D();
~CPUParticles2D(); ~CPUParticles2D();
}; };

View File

@ -32,6 +32,7 @@
#include "visibility_notifier_2d.h" #include "visibility_notifier_2d.h"
#include "core/config/engine.h" #include "core/config/engine.h"
#include "gpu_particles_2d.h"
#include "scene/2d/animated_sprite.h" #include "scene/2d/animated_sprite.h"
#include "scene/2d/physics_body_2d.h" #include "scene/2d/physics_body_2d.h"
#include "scene/animation/animation_player.h" #include "scene/animation/animation_player.h"
@ -215,6 +216,13 @@ void VisibilityEnabler2D::_find_nodes(Node *p_node) {
} }
} }
{
GPUParticles2D *ps = Object::cast_to<GPUParticles2D>(p_node);
if (ps) {
add = true;
}
}
if (add) { if (add) {
p_node->connect(SceneStringNames::get_singleton()->tree_exiting, this, "_node_removed", varray(p_node), CONNECT_ONESHOT); p_node->connect(SceneStringNames::get_singleton()->tree_exiting, this, "_node_removed", varray(p_node), CONNECT_ONESHOT);
nodes[p_node] = meta; nodes[p_node] = meta;
@ -309,6 +317,14 @@ void VisibilityEnabler2D::_change_node_state(Node *p_node, bool p_enabled) {
} }
} }
} }
if (enabler[ENABLER_PAUSE_PARTICLES]) {
GPUParticles2D *ps = Object::cast_to<GPUParticles2D>(p_node);
if (ps) {
ps->set_emitting(p_enabled);
}
}
} }
void VisibilityEnabler2D::_node_removed(Node *p_node) { void VisibilityEnabler2D::_node_removed(Node *p_node) {

View File

@ -33,6 +33,7 @@
#include "core/os/os.h" #include "core/os/os.h"
#include "scene/3d/camera.h" #include "scene/3d/camera.h"
#include "scene/3d/gpu_particles.h"
#include "scene/main/viewport.h" #include "scene/main/viewport.h"
#include "scene/resources/curve.h" #include "scene/resources/curve.h"
#include "scene/resources/gradient.h" #include "scene/resources/gradient.h"
@ -1313,6 +1314,85 @@ void CPUParticles::_notification(int p_what) {
} }
} }
void CPUParticles::convert_from_particles(Node *p_particles) {
GPUParticles *particles = Object::cast_to<GPUParticles>(p_particles);
ERR_FAIL_COND_MSG(!particles, "Only GPUParticles nodes can be converted to CPUParticles.");
set_emitting(particles->is_emitting());
set_amount(particles->get_amount());
set_lifetime(particles->get_lifetime());
set_one_shot(particles->get_one_shot());
set_pre_process_time(particles->get_pre_process_time());
set_explosiveness_ratio(particles->get_explosiveness_ratio());
set_randomness_ratio(particles->get_randomness_ratio());
set_use_local_coordinates(particles->get_use_local_coordinates());
set_fixed_fps(particles->get_fixed_fps());
set_fractional_delta(particles->get_fractional_delta());
set_speed_scale(particles->get_speed_scale());
set_draw_order(DrawOrder(particles->get_draw_order()));
set_mesh(particles->get_draw_pass_mesh(0));
Ref<ParticlesMaterial> material = particles->get_process_material();
if (material.is_null()) {
return;
}
set_direction(material->get_direction());
set_spread(material->get_spread());
set_flatness(material->get_flatness());
set_color(material->get_color());
Ref<GradientTexture> gt = material->get_color_ramp();
if (gt.is_valid()) {
set_color_ramp(gt->get_gradient());
}
Ref<GradientTexture> gti = material->get_color_initial_ramp();
if (gti.is_valid()) {
set_color_initial_ramp(gti->get_gradient());
}
set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY));
set_particle_flag(FLAG_ROTATE_Y, material->get_flag(ParticlesMaterial::FLAG_ROTATE_Y));
set_particle_flag(FLAG_DISABLE_Z, material->get_flag(ParticlesMaterial::FLAG_DISABLE_Z));
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_inner_radius(material->get_emission_ring_inner_radius());
set_emission_ring_radius(material->get_emission_ring_radius());
set_emission_ring_axis(material->get_emission_ring_axis());
set_gravity(material->get_gravity());
set_lifetime_randomness(material->get_lifetime_randomness());
#define CONVERT_PARAM(m_param) \
set_param(m_param, material->get_param(ParticlesMaterial::m_param)); \
{ \
Ref<CurveTexture> ctex = material->get_param_texture(ParticlesMaterial::m_param); \
if (ctex.is_valid()) \
set_param_curve(m_param, ctex->get_curve()); \
} \
set_param_randomness(m_param, material->get_param_randomness(ParticlesMaterial::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 CPUParticles::_bind_methods() { void CPUParticles::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &CPUParticles::set_emitting); ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &CPUParticles::set_emitting);
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &CPUParticles::set_amount); ClassDB::bind_method(D_METHOD("set_amount", "amount"), &CPUParticles::set_amount);
@ -1435,6 +1515,8 @@ void CPUParticles::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles::get_gravity); ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles::get_gravity);
ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles::set_gravity); ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles::set_gravity);
ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles::convert_from_particles);
ClassDB::bind_method(D_METHOD("_update_render_thread"), &CPUParticles::_update_render_thread); ClassDB::bind_method(D_METHOD("_update_render_thread"), &CPUParticles::_update_render_thread);
ADD_GROUP("Emission Shape", "emission_"); ADD_GROUP("Emission Shape", "emission_");

View File

@ -357,6 +357,8 @@ public:
void restart(); void restart();
void convert_from_particles(Node *p_particles);
CPUParticles(); CPUParticles();
~CPUParticles(); ~CPUParticles();
}; };

View File

@ -44,6 +44,7 @@
#include "room_group.h" #include "room_group.h"
#include "scene/3d/camera.h" #include "scene/3d/camera.h"
#include "scene/3d/light.h" #include "scene/3d/light.h"
#include "scene/3d/gpu_particles.h"
#include "scene/3d/sprite_3d.h" #include "scene/3d/sprite_3d.h"
#include "scene/resources/mesh/multimesh.h" #include "scene/resources/mesh/multimesh.h"
#include "scene/resources/world_3d.h" #include "scene/resources/world_3d.h"
@ -1869,13 +1870,11 @@ bool RoomManager::_bound_findpoints_geom_instance(GeometryInstance *p_gi, Vector
} }
// Particles have a "visibility aabb" we can use for this // Particles have a "visibility aabb" we can use for this
/* GPUParticles *particles = Object::cast_to<GPUParticles>(p_gi);
Particles *particles = Object::cast_to<Particles>(p_gi);
if (particles) { if (particles) {
r_aabb = particles->get_global_transform().xform(particles->get_visibility_aabb()); r_aabb = particles->get_global_transform().xform(particles->get_visibility_aabb());
return true; return true;
} }
*/
// Fallback path for geometry that is not recognised // Fallback path for geometry that is not recognised
// (including CPUParticles, which will need to rely on an expansion margin) // (including CPUParticles, which will need to rely on an expansion margin)

View File

@ -59,6 +59,7 @@
#include "scene/2d/navigation_polygon_instance.h" #include "scene/2d/navigation_polygon_instance.h"
#include "scene/2d/parallax_background.h" #include "scene/2d/parallax_background.h"
#include "scene/2d/parallax_layer.h" #include "scene/2d/parallax_layer.h"
#include "scene/2d/gpu_particles_2d.h"
#include "scene/2d/path_2d.h" #include "scene/2d/path_2d.h"
#include "scene/2d/physics_body_2d.h" #include "scene/2d/physics_body_2d.h"
#include "scene/2d/polygon_2d.h" #include "scene/2d/polygon_2d.h"
@ -213,6 +214,7 @@
#include "scene/3d/navigation_obstacle.h" #include "scene/3d/navigation_obstacle.h"
#include "scene/3d/occluder.h" #include "scene/3d/occluder.h"
#include "scene/3d/path.h" #include "scene/3d/path.h"
#include "scene/3d/gpu_particles.h"
#include "scene/3d/physics_body.h" #include "scene/3d/physics_body.h"
#include "scene/3d/physics_joint.h" #include "scene/3d/physics_joint.h"
#include "scene/3d/portal.h" #include "scene/3d/portal.h"
@ -460,6 +462,7 @@ void register_scene_types() {
ClassDB::register_class<OmniLight>(); ClassDB::register_class<OmniLight>();
ClassDB::register_class<SpotLight>(); ClassDB::register_class<SpotLight>();
ClassDB::register_class<ReflectionProbe>(); ClassDB::register_class<ReflectionProbe>();
ClassDB::register_class<GPUParticles>();
ClassDB::register_class<BakedLightmap>(); ClassDB::register_class<BakedLightmap>();
ClassDB::register_class<BakedLightmapData>(); ClassDB::register_class<BakedLightmapData>();
ClassDB::register_class<CPUParticles>(); ClassDB::register_class<CPUParticles>();
@ -536,6 +539,7 @@ void register_scene_types() {
CanvasItemMaterial::init_shaders(); CanvasItemMaterial::init_shaders();
ClassDB::register_class<Node2D>(); ClassDB::register_class<Node2D>();
ClassDB::register_class<CPUParticles2D>(); ClassDB::register_class<CPUParticles2D>();
ClassDB::register_class<GPUParticles2D>();
//ClassDB::register_class<ParticleAttractor2D>(); //ClassDB::register_class<ParticleAttractor2D>();
ClassDB::register_class<Sprite>(); ClassDB::register_class<Sprite>();
//ClassDB::register_type<ViewportSprite>(); //ClassDB::register_type<ViewportSprite>();