Merge pull request #102249 from Arnklit/particles2d-emission-shapes

Add emission shape gizmos to Particles2D
This commit is contained in:
Thaddeus Crews 2025-03-11 14:01:00 -05:00
commit e54a4408ad
No known key found for this signature in database
GPG key ID: 62181B86FE9E5D84
6 changed files with 186 additions and 19 deletions

View file

@ -144,7 +144,22 @@ void GPUParticles2D::_update_particle_emission_transform() {
}
void GPUParticles2D::set_process_material(const Ref<Material> &p_material) {
if (process_material == p_material) {
return;
}
if (process_material.is_valid() && process_material->is_class("ParticleProcessMaterial")) {
process_material->disconnect("emission_shape_changed", callable_mp((CanvasItem *)this, &GPUParticles2D::queue_redraw));
}
process_material = p_material;
if (process_material.is_valid() && process_material->is_class("ParticleProcessMaterial")) {
process_material->connect("emission_shape_changed", callable_mp((CanvasItem *)this, &GPUParticles2D::queue_redraw));
}
queue_redraw();
Ref<ParticleProcessMaterial> pm = p_material;
if (pm.is_valid() && !pm->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) {
// Likely a new (3D) material, modify it to match 2D space
@ -198,8 +213,11 @@ void GPUParticles2D::set_interp_to_end(float p_interp) {
}
#ifdef TOOLS_ENABLED
void GPUParticles2D::set_show_visibility_rect(bool p_show_visibility_rect) {
show_visibility_rect = p_show_visibility_rect;
void GPUParticles2D::set_show_gizmos(bool p_show_gizmos) {
if (show_gizmos == p_show_gizmos) {
return;
}
show_gizmos = p_show_gizmos;
queue_redraw();
}
#endif
@ -707,8 +725,9 @@ void GPUParticles2D::_notification(int p_what) {
RS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid);
#ifdef TOOLS_ENABLED
if (show_visibility_rect) {
if (show_gizmos) {
draw_rect(visibility_rect, Color(0, 0.7, 0.9, 0.4), false);
_draw_emission_gizmo();
}
#endif
} break;
@ -784,6 +803,60 @@ void GPUParticles2D::_notification(int p_what) {
}
}
#ifdef TOOLS_ENABLED
void GPUParticles2D::_draw_emission_gizmo() {
Ref<ParticleProcessMaterial> pm = process_material;
Color emission_ring_color = Color(0.8, 0.7, 0.4, 0.4);
if (pm.is_null()) {
return;
}
draw_set_transform(
Vector2(pm->get_emission_shape_offset().x, pm->get_emission_shape_offset().y),
0.0,
Vector2(pm->get_emission_shape_scale().x, pm->get_emission_shape_scale().y));
switch (pm->get_emission_shape()) {
case ParticleProcessMaterial::EmissionShape::EMISSION_SHAPE_BOX: {
Vector2 extents2d = Vector2(pm->get_emission_box_extents().x, pm->get_emission_box_extents().y);
draw_rect(Rect2(-extents2d, extents2d * 2.0), emission_ring_color, false);
break;
}
case ParticleProcessMaterial::EmissionShape::EMISSION_SHAPE_SPHERE:
case ParticleProcessMaterial::EmissionShape::EMISSION_SHAPE_SPHERE_SURFACE: {
draw_circle(Vector2(), pm->get_emission_sphere_radius(), emission_ring_color, false);
break;
}
case ParticleProcessMaterial::EmissionShape::EMISSION_SHAPE_RING: {
Vector3 ring_axis = pm->get_emission_ring_axis();
if (ring_axis.is_equal_approx(Vector3(0.0, 0.0, 1.0)) || ring_axis.is_zero_approx()) {
draw_circle(Vector2(), pm->get_emission_ring_inner_radius(), emission_ring_color, false);
draw_circle(Vector2(), pm->get_emission_ring_radius(), emission_ring_color, false);
} else {
Vector2 a = Vector2(pm->get_emission_ring_height() / -2.0, pm->get_emission_ring_radius() / -1.0);
Vector2 b = Vector2(-a.x, MIN(a.y + tan((90.0 - pm->get_emission_ring_cone_angle()) * 0.01745329) * pm->get_emission_ring_height(), 0.0));
Vector2 c = Vector2(b.x, -b.y);
Vector2 d = Vector2(a.x, -a.y);
if (ring_axis.is_equal_approx(Vector3(1.0, 0.0, 0.0))) {
Vector<Vector2> pos = { a, b, b, c, c, d, d, a };
draw_multiline(pos, emission_ring_color);
} else if (ring_axis.is_equal_approx(Vector3(0.0, 1.0, 0.0))) {
a = Vector2(a.y, a.x);
b = Vector2(b.y, b.x);
c = Vector2(c.y, c.x);
d = Vector2(d.y, d.x);
Vector<Vector2> pos = { a, b, b, c, c, d, d, a };
draw_multiline(pos, emission_ring_color);
}
}
break;
}
default: {
break;
}
}
}
#endif
void GPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &GPUParticles2D::set_emitting);
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &GPUParticles2D::set_amount);