Merge pull request #80931 from lawnjelly/cpuparticles2d_mega_pr
[3.x] `CPUParticles2D` - Add ability to follow physics interpolated target
This commit is contained in:
commit
501517a97d
7 changed files with 89 additions and 11 deletions
|
@ -236,6 +236,7 @@
|
|||
<member name="orbit_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
|
||||
Orbital velocity randomness ratio.
|
||||
</member>
|
||||
<member name="physics_interpolation_mode" type="int" setter="set_physics_interpolation_mode" getter="get_physics_interpolation_mode" overrides="Node" enum="Node.PhysicsInterpolationMode" default="1" />
|
||||
<member name="preprocess" type="float" setter="set_pre_process_time" getter="get_pre_process_time" default="0.0">
|
||||
Particle system starts as if it had already run for this many seconds.
|
||||
</member>
|
||||
|
|
|
@ -301,8 +301,10 @@ void Camera2D::_notification(int p_what) {
|
|||
}
|
||||
if (is_physics_interpolated_and_enabled()) {
|
||||
_ensure_update_interpolation_data();
|
||||
if (Engine::get_singleton()->is_in_physics_frame()) {
|
||||
_interpolation_data.xform_curr = get_camera_transform();
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
|
|
|
@ -490,6 +490,20 @@ Transform2D CanvasItem::get_global_transform() const {
|
|||
return global_transform;
|
||||
}
|
||||
|
||||
// Same as get_global_transform() but no reset for `global_invalid`.
|
||||
Transform2D CanvasItem::get_global_transform_const() const {
|
||||
if (global_invalid) {
|
||||
const CanvasItem *pi = get_parent_item();
|
||||
if (pi) {
|
||||
global_transform = pi->get_global_transform_const() * get_transform();
|
||||
} else {
|
||||
global_transform = get_transform();
|
||||
}
|
||||
}
|
||||
|
||||
return global_transform;
|
||||
}
|
||||
|
||||
void CanvasItem::_toplevel_raise_self() {
|
||||
if (!is_inside_tree()) {
|
||||
return;
|
||||
|
|
|
@ -238,6 +238,7 @@ protected:
|
|||
|
||||
void item_rect_changed(bool p_size_changed = true);
|
||||
void set_canvas_item_use_identity_transform(bool p_enable);
|
||||
Transform2D get_global_transform_const() const;
|
||||
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
#include "cpu_particles_2d.h"
|
||||
#include "core/core_string_names.h"
|
||||
#include "core/fixed_array.h"
|
||||
#include "core/math/transform_interpolator.h"
|
||||
#include "core/os/os.h"
|
||||
#include "scene/2d/canvas_item.h"
|
||||
#include "scene/2d/particles_2d.h"
|
||||
|
@ -119,6 +121,10 @@ void CPUParticles2D::set_use_local_coordinates(bool p_enable) {
|
|||
// When not using legacy, there is never a need for NOTIFICATION_TRANSFORM_CHANGED,
|
||||
// so we leave it at the default (false).
|
||||
set_canvas_item_use_identity_transform(!local_coords);
|
||||
|
||||
// We only need NOTIFICATION_TRANSFORM_CHANGED
|
||||
// when following an interpolated target.
|
||||
set_notify_transform(_interpolation_data.interpolated_follow);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -755,7 +761,11 @@ void CPUParticles2D::_particles_process(float p_delta) {
|
|||
Transform2D emission_xform;
|
||||
Transform2D velocity_xform;
|
||||
if (!local_coords) {
|
||||
if (!_interpolation_data.interpolated_follow) {
|
||||
emission_xform = get_global_transform();
|
||||
} else {
|
||||
TransformInterpolator::interpolate_transform_2d(_interpolation_data.global_xform_prev, _interpolation_data.global_xform_curr, emission_xform, Engine::get_singleton()->get_physics_interpolation_fraction());
|
||||
}
|
||||
velocity_xform = emission_xform;
|
||||
velocity_xform[2] = Vector2();
|
||||
}
|
||||
|
@ -1082,7 +1092,14 @@ void CPUParticles2D::_refresh_interpolation_state() {
|
|||
}
|
||||
bool interpolated = is_physics_interpolated_and_enabled();
|
||||
|
||||
if (_interpolated == interpolated) {
|
||||
// The logic for whether to do an interpolated follow.
|
||||
// This is rather complex, but basically:
|
||||
// If project setting interpolation is ON but this particle system is switched OFF,
|
||||
// and in global mode, we will follow the INTERPOLATED position rather than the actual position.
|
||||
// This is so that particles aren't generated AHEAD of the interpolated parent.
|
||||
bool follow = !interpolated && !local_coords && get_tree()->is_physics_interpolation_enabled();
|
||||
|
||||
if ((_interpolated == interpolated) && (follow == _interpolation_data.interpolated_follow)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1093,14 +1110,13 @@ void CPUParticles2D::_refresh_interpolation_state() {
|
|||
_set_redraw(false);
|
||||
|
||||
_interpolated = interpolated;
|
||||
_interpolation_data.interpolated_follow = follow;
|
||||
|
||||
#ifdef GODOT_CPU_PARTICLES_2D_LEGACY_COMPATIBILITY
|
||||
// Refresh local coords state, blank inv_emission_transform.
|
||||
set_use_local_coordinates(local_coords);
|
||||
#endif
|
||||
|
||||
set_process_internal(!_interpolated);
|
||||
set_physics_process_internal(_interpolated);
|
||||
set_physics_process_internal(_interpolated || _interpolation_data.interpolated_follow);
|
||||
|
||||
// Re-establish all connections.
|
||||
_set_redraw(curr_redraw);
|
||||
|
@ -1161,6 +1177,13 @@ void CPUParticles2D::_notification(int p_what) {
|
|||
if (_interpolated) {
|
||||
_update_internal(true);
|
||||
}
|
||||
|
||||
// If we are interpolated following, then reset physics interpolation
|
||||
// when first appearing. This won't be called by canvas item, as in
|
||||
// following mode, is_interpolated() is actually FALSE.
|
||||
if (_interpolation_data.interpolated_follow) {
|
||||
notification(NOTIFICATION_RESET_PHYSICS_INTERPOLATION);
|
||||
}
|
||||
}
|
||||
|
||||
if (p_what == NOTIFICATION_EXIT_TREE) {
|
||||
|
@ -1194,8 +1217,16 @@ void CPUParticles2D::_notification(int p_what) {
|
|||
_update_internal(false);
|
||||
}
|
||||
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
|
||||
if (_interpolated) {
|
||||
_update_internal(true);
|
||||
}
|
||||
if (_interpolation_data.interpolated_follow) {
|
||||
// Keep the interpolated follow target updated.
|
||||
DEV_CHECK_ONCE(!_interpolated);
|
||||
_interpolation_data.global_xform_prev = _interpolation_data.global_xform_curr;
|
||||
_interpolation_data.global_xform_curr = get_global_transform();
|
||||
}
|
||||
}
|
||||
#ifdef GODOT_CPU_PARTICLES_2D_LEGACY_COMPATIBILITY
|
||||
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
|
||||
if (!_interpolated && !local_coords) {
|
||||
|
@ -1227,6 +1258,20 @@ void CPUParticles2D::_notification(int p_what) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
|
||||
if (_interpolation_data.interpolated_follow) {
|
||||
// If the transform has been updated AFTER the physics tick, keep data flowing.
|
||||
if (Engine::get_singleton()->is_in_physics_frame()) {
|
||||
_interpolation_data.global_xform_curr = get_global_transform();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p_what == NOTIFICATION_RESET_PHYSICS_INTERPOLATION) {
|
||||
// Make sure current is up to date with any pending global transform changes.
|
||||
_interpolation_data.global_xform_curr = get_global_transform_const();
|
||||
_interpolation_data.global_xform_prev = _interpolation_data.global_xform_curr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1577,6 +1622,12 @@ CPUParticles2D::CPUParticles2D() {
|
|||
set_color(Color(1, 1, 1, 1));
|
||||
|
||||
_update_mesh_texture();
|
||||
|
||||
// CPUParticles2D defaults to interpolation off.
|
||||
// This is because the result often looks better when the particles are updated every frame.
|
||||
// Note that children will need to explicitly turn back on interpolation if they want to use it,
|
||||
// rather than relying on inherit mode.
|
||||
set_physics_interpolation_mode(Node::PHYSICS_INTERPOLATION_MODE_OFF);
|
||||
}
|
||||
|
||||
CPUParticles2D::~CPUParticles2D() {
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include "scene/2d/node_2d.h"
|
||||
#include "scene/resources/texture.h"
|
||||
|
||||
#define GODOT_CPU_PARTICLES_2D_LEGACY_COMPATIBILITY
|
||||
// #define GODOT_CPU_PARTICLES_2D_LEGACY_COMPATIBILITY
|
||||
|
||||
class CPUParticles2D : public Node2D {
|
||||
private:
|
||||
|
@ -200,8 +200,19 @@ private:
|
|||
void _update_particle_data_buffer();
|
||||
|
||||
Mutex update_mutex;
|
||||
|
||||
// Whether this particle system is interpolated.
|
||||
bool _interpolated = false;
|
||||
|
||||
struct InterpolationData {
|
||||
// Whether this particle is non-interpolated, but following an interpolated parent.
|
||||
bool interpolated_follow = false;
|
||||
|
||||
// If doing interpolated follow, we need to keep these updated per tick.
|
||||
Transform2D global_xform_curr;
|
||||
Transform2D global_xform_prev;
|
||||
} _interpolation_data;
|
||||
|
||||
void _update_render_thread();
|
||||
|
||||
void _update_mesh_texture();
|
||||
|
|
|
@ -882,9 +882,7 @@ void Node::set_physics_interpolation_mode(PhysicsInterpolationMode p_mode) {
|
|||
}
|
||||
|
||||
void Node::reset_physics_interpolation() {
|
||||
if (is_physics_interpolated_and_enabled()) {
|
||||
propagate_notification(NOTIFICATION_RESET_PHYSICS_INTERPOLATION);
|
||||
}
|
||||
}
|
||||
|
||||
float Node::get_physics_process_delta_time() const {
|
||||
|
|
Loading…
Reference in a new issue