mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2024-12-22 20:06:49 +01:00
Ported from godot: CPUParticles2D - Add ability to follow physics interpolated target
Allows a non-interpolated particle system to closely follow an interpolated target without tracking ahead of the target, by performing fixed timestep interpolation on the particle system global transform, and using this for emission.
- lawnjelly
3e19cf834a
This commit is contained in:
parent
f4339d2a49
commit
cc012d3f92
@ -229,6 +229,7 @@
|
|||||||
<member name="orbit_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
|
<member name="orbit_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0">
|
||||||
Orbital velocity randomness ratio.
|
Orbital velocity randomness ratio.
|
||||||
</member>
|
</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">
|
<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.
|
Particle system starts as if it had already run for this many seconds.
|
||||||
</member>
|
</member>
|
||||||
|
@ -304,8 +304,10 @@ void Camera2D::_notification(int p_what) {
|
|||||||
|
|
||||||
if (is_physics_interpolated_and_enabled()) {
|
if (is_physics_interpolated_and_enabled()) {
|
||||||
_ensure_update_interpolation_data();
|
_ensure_update_interpolation_data();
|
||||||
|
if (Engine::get_singleton()->is_in_physics_frame()) {
|
||||||
_interpolation_data.xform_curr = get_camera_transform();
|
_interpolation_data.xform_curr = get_camera_transform();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_ENTER_TREE: {
|
case NOTIFICATION_ENTER_TREE: {
|
||||||
ERR_FAIL_COND(!is_inside_tree());
|
ERR_FAIL_COND(!is_inside_tree());
|
||||||
|
@ -497,6 +497,20 @@ Transform2D CanvasItem::get_global_transform() const {
|
|||||||
return global_transform;
|
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() {
|
void CanvasItem::_toplevel_raise_self() {
|
||||||
if (!is_inside_tree()) {
|
if (!is_inside_tree()) {
|
||||||
return;
|
return;
|
||||||
|
@ -231,6 +231,7 @@ protected:
|
|||||||
|
|
||||||
void item_rect_changed(bool p_size_changed = true);
|
void item_rect_changed(bool p_size_changed = true);
|
||||||
void set_canvas_item_use_identity_transform(bool p_enable);
|
void set_canvas_item_use_identity_transform(bool p_enable);
|
||||||
|
Transform2D get_global_transform_const() const;
|
||||||
|
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
@ -32,6 +32,9 @@
|
|||||||
#include "core/containers/rid.h"
|
#include "core/containers/rid.h"
|
||||||
#include "core/core_string_names.h"
|
#include "core/core_string_names.h"
|
||||||
#include "core/os/os.h"
|
#include "core/os/os.h"
|
||||||
|
#include "core/containers/fixed_array.h"
|
||||||
|
#include "core/math/transform_interpolator.h"
|
||||||
|
|
||||||
#include "scene/2d/canvas_item.h"
|
#include "scene/2d/canvas_item.h"
|
||||||
#include "scene/resources/particles_material.h"
|
#include "scene/resources/particles_material.h"
|
||||||
#include "scene/resources/texture.h"
|
#include "scene/resources/texture.h"
|
||||||
@ -121,6 +124,10 @@ void CPUParticles2D::set_use_local_coordinates(bool p_enable) {
|
|||||||
// When not using legacy, there is never a need for NOTIFICATION_TRANSFORM_CHANGED,
|
// When not using legacy, there is never a need for NOTIFICATION_TRANSFORM_CHANGED,
|
||||||
// so we leave it at the default (false).
|
// so we leave it at the default (false).
|
||||||
set_canvas_item_use_identity_transform(!local_coords);
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -757,7 +764,11 @@ void CPUParticles2D::_particles_process(float p_delta) {
|
|||||||
Transform2D emission_xform;
|
Transform2D emission_xform;
|
||||||
Transform2D velocity_xform;
|
Transform2D velocity_xform;
|
||||||
if (!local_coords) {
|
if (!local_coords) {
|
||||||
|
if (!_interpolation_data.interpolated_follow) {
|
||||||
emission_xform = get_global_transform();
|
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 = emission_xform;
|
||||||
velocity_xform[2] = Vector2();
|
velocity_xform[2] = Vector2();
|
||||||
}
|
}
|
||||||
@ -1085,7 +1096,14 @@ void CPUParticles2D::_refresh_interpolation_state() {
|
|||||||
}
|
}
|
||||||
bool interpolated = is_physics_interpolated_and_enabled();
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1096,14 +1114,13 @@ void CPUParticles2D::_refresh_interpolation_state() {
|
|||||||
_set_redraw(false);
|
_set_redraw(false);
|
||||||
|
|
||||||
_interpolated = interpolated;
|
_interpolated = interpolated;
|
||||||
|
_interpolation_data.interpolated_follow = follow;
|
||||||
|
|
||||||
#ifdef PANDEMONIUM_CPU_PARTICLES_2D_LEGACY_COMPATIBILITY
|
|
||||||
// Refresh local coords state, blank inv_emission_transform.
|
// Refresh local coords state, blank inv_emission_transform.
|
||||||
set_use_local_coordinates(local_coords);
|
set_use_local_coordinates(local_coords);
|
||||||
#endif
|
|
||||||
|
|
||||||
set_process_internal(!_interpolated);
|
set_process_internal(!_interpolated);
|
||||||
set_physics_process_internal(_interpolated);
|
set_physics_process_internal(_interpolated || _interpolation_data.interpolated_follow);
|
||||||
|
|
||||||
// Re-establish all connections.
|
// Re-establish all connections.
|
||||||
_set_redraw(curr_redraw);
|
_set_redraw(curr_redraw);
|
||||||
@ -1165,6 +1182,13 @@ void CPUParticles2D::_notification(int p_what) {
|
|||||||
if (_interpolated) {
|
if (_interpolated) {
|
||||||
_update_internal(true);
|
_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) {
|
if (p_what == NOTIFICATION_EXIT_TREE) {
|
||||||
@ -1199,8 +1223,16 @@ void CPUParticles2D::_notification(int p_what) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
|
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
|
||||||
|
if (_interpolated) {
|
||||||
_update_internal(true);
|
_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 PANDEMONIUM_CPU_PARTICLES_2D_LEGACY_COMPATIBILITY
|
#ifdef PANDEMONIUM_CPU_PARTICLES_2D_LEGACY_COMPATIBILITY
|
||||||
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
|
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
|
||||||
if (!_interpolated && !local_coords) {
|
if (!_interpolated && !local_coords) {
|
||||||
@ -1232,6 +1264,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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1450,6 +1496,7 @@ CPUParticles2D::CPUParticles2D() {
|
|||||||
redraw = false;
|
redraw = false;
|
||||||
emitting = false;
|
emitting = false;
|
||||||
_interpolated = false;
|
_interpolated = false;
|
||||||
|
_interpolation_data.interpolated_follow = false;
|
||||||
|
|
||||||
mesh = RID_PRIME(RenderingServer::get_singleton()->mesh_create());
|
mesh = RID_PRIME(RenderingServer::get_singleton()->mesh_create());
|
||||||
multimesh = RID_PRIME(RenderingServer::get_singleton()->multimesh_create());
|
multimesh = RID_PRIME(RenderingServer::get_singleton()->multimesh_create());
|
||||||
@ -1501,6 +1548,12 @@ CPUParticles2D::CPUParticles2D() {
|
|||||||
set_color(Color(1, 1, 1, 1));
|
set_color(Color(1, 1, 1, 1));
|
||||||
|
|
||||||
_update_mesh_texture();
|
_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() {
|
CPUParticles2D::~CPUParticles2D() {
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
class RID;
|
class RID;
|
||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
#define PANDEMONIUM_CPU_PARTICLES_2D_LEGACY_COMPATIBILITY
|
//#define PANDEMONIUM_CPU_PARTICLES_2D_LEGACY_COMPATIBILITY
|
||||||
|
|
||||||
class CPUParticles2D : public Node2D {
|
class CPUParticles2D : public Node2D {
|
||||||
private:
|
private:
|
||||||
@ -200,8 +200,18 @@ private:
|
|||||||
void _update_particle_data_buffer();
|
void _update_particle_data_buffer();
|
||||||
|
|
||||||
Mutex update_mutex;
|
Mutex update_mutex;
|
||||||
|
// Whether this particle system is interpolated.
|
||||||
bool _interpolated;
|
bool _interpolated;
|
||||||
|
|
||||||
|
struct InterpolationData {
|
||||||
|
// Whether this particle is non-interpolated, but following an interpolated parent.
|
||||||
|
bool interpolated_follow;
|
||||||
|
|
||||||
|
// 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_render_thread();
|
||||||
|
|
||||||
void _update_mesh_texture();
|
void _update_mesh_texture();
|
||||||
|
@ -1189,10 +1189,8 @@ void Node::set_physics_interpolation_mode(PhysicsInterpolationMode p_mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Node::reset_physics_interpolation() {
|
void Node::reset_physics_interpolation() {
|
||||||
if (is_physics_interpolated_and_enabled()) {
|
|
||||||
propagate_notification(NOTIFICATION_RESET_PHYSICS_INTERPOLATION);
|
propagate_notification(NOTIFICATION_RESET_PHYSICS_INTERPOLATION);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
float Node::get_physics_process_delta_time() const {
|
float Node::get_physics_process_delta_time() const {
|
||||||
if (data.tree) {
|
if (data.tree) {
|
||||||
|
Loading…
Reference in New Issue
Block a user