From 0ab077fceff82d73b8919f51dde51596c698e5d6 Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Sat, 7 May 2022 13:16:38 +0100 Subject: [PATCH] Physics Interpolation - add interpolation mode property to node Exposes the "interpolated" flag on nodes via a property, physics_interpolation_mode. Mode can be INHERIT, OFF and ON. This makes it easy to turn off interpolation for nodes in the editor, versus via code. --- doc/classes/Node.xml | 25 ++++++++++------- scene/main/node.cpp | 67 +++++++++++++++++++++++++++++++++++++++----- scene/main/node.h | 15 ++++++++-- 3 files changed, 88 insertions(+), 19 deletions(-) diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index aa16679af87..e5f871099e4 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -391,14 +391,14 @@ - Returns [code]true[/code] if the physics interpolated flag is set for this Node (see [method set_physics_interpolated]). + Returns [code]true[/code] if the physics interpolated flag is set for this Node (see [member physics_interpolation_mode]). [b]Note:[/b] Interpolation will only be active is both the flag is set [b]and[/b] physics interpolation is enabled within the [SceneTree]. This can be tested using [method is_physics_interpolated_and_enabled]. - Returns [code]true[/code] if physics interpolation is enabled (see [method set_physics_interpolated]) [b]and[/b] enabled in the [SceneTree]. + Returns [code]true[/code] if physics interpolation is enabled (see [member physics_interpolation_mode]) [b]and[/b] enabled in the [SceneTree]. This is a convenience version of [method is_physics_interpolated] that also checks whether physics interpolation is enabled globally. See [member SceneTree.physics_interpolation] and [member ProjectSettings.physics/common/physics_interpolation]. @@ -660,14 +660,6 @@ Sets the node's network master to the peer with the given peer ID. The network master is the peer that has authority over the node on the network. Useful in conjunction with the [code]master[/code] and [code]puppet[/code] keywords. Inherited from the parent node by default, which ultimately defaults to peer ID 1 (the server). If [code]recursive[/code], the given peer is recursively set as the master for all children of this node. - - - - - Enables or disables physics interpolation per node, offering a finer grain of control than turning physics interpolation on and off globally. - [b]Note:[/b] This can be especially useful for [Camera]s, where custom interpolation can sometimes give superior results. - - @@ -755,6 +747,10 @@ Pause mode. How the node will behave if the [SceneTree] is paused. + + Allows enabling or disabling physics interpolation per node, offering a finer grain of control than turning physics interpolation on and off globally. + [b]Note:[/b] This can be especially useful for [Camera]s, where custom interpolation can sometimes give superior results. + The node's priority in the execution order of the enabled processing callbacks (i.e. [constant NOTIFICATION_PROCESS], [constant NOTIFICATION_PHYSICS_PROCESS] and their internal counterparts). Nodes whose process priority value is [i]lower[/i] will have their processing callbacks executed first. @@ -925,6 +921,15 @@ Continue to process regardless of the [SceneTree] pause state. + + Inherits physics interpolation mode from the node's parent. For the root node, it is equivalent to [constant PHYSICS_INTERPOLATION_MODE_ON]. Default. + + + Turn off physics interpolation in this node and children set to [constant PHYSICS_INTERPOLATION_MODE_INHERIT]. + + + Turn on physics interpolation in this node and children set to [constant PHYSICS_INTERPOLATION_MODE_INHERIT]. + Duplicate the node's signals. diff --git a/scene/main/node.cpp b/scene/main/node.cpp index c7fc746f676..58c30564f07 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -45,6 +45,7 @@ #endif VARIANT_ENUM_CAST(Node::PauseMode); +VARIANT_ENUM_CAST(Node::PhysicsInterpolationMode); int Node::orphan_node_count = 0; @@ -79,6 +80,14 @@ void Node::_notification(int p_notification) { data.pause_owner = this; } + if (data.physics_interpolation_mode == PHYSICS_INTERPOLATION_MODE_INHERIT) { + bool interpolate = true; // Root node default is for interpolation to be on + if (data.parent) { + interpolate = data.parent->is_physics_interpolated(); + } + _propagate_physics_interpolated(interpolate); + } + if (data.input) { add_to_group("_vp_input" + itos(get_viewport()->get_instance_id())); } @@ -183,6 +192,23 @@ void Node::_propagate_ready() { } void Node::_propagate_physics_interpolated(bool p_interpolated) { + switch (data.physics_interpolation_mode) { + case PHYSICS_INTERPOLATION_MODE_INHERIT: + // keep the parent p_interpolated + break; + case PHYSICS_INTERPOLATION_MODE_OFF: { + p_interpolated = false; + } break; + case PHYSICS_INTERPOLATION_MODE_ON: { + p_interpolated = true; + } break; + } + + // no change? no need to propagate further + if (data.physics_interpolated == p_interpolated) { + return; + } + data.physics_interpolated = p_interpolated; // allow a call to the VisualServer etc in derived classes @@ -800,14 +826,36 @@ bool Node::can_process() const { return true; } -void Node::set_physics_interpolated(bool p_interpolated) { +void Node::set_physics_interpolation_mode(PhysicsInterpolationMode p_mode) { + if (data.physics_interpolation_mode == p_mode) { + return; + } + + data.physics_interpolation_mode = p_mode; + + bool interpolate = true; // default for root node + + switch (p_mode) { + case PHYSICS_INTERPOLATION_MODE_INHERIT: { + if (is_inside_tree() && data.parent) { + interpolate = data.parent->is_physics_interpolated(); + } + } break; + case PHYSICS_INTERPOLATION_MODE_OFF: { + interpolate = false; + } break; + case PHYSICS_INTERPOLATION_MODE_ON: { + interpolate = true; + } break; + } + // if swapping from interpolated to non-interpolated, use this as // an extra means to cause a reset - if (is_physics_interpolated() && !p_interpolated) { + if (is_physics_interpolated() && !interpolate) { reset_physics_interpolation(); } - _propagate_physics_interpolated(p_interpolated); + _propagate_physics_interpolated(interpolate); } void Node::reset_physics_interpolation() { @@ -2955,7 +3003,8 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("set_physics_process_internal", "enable"), &Node::set_physics_process_internal); ClassDB::bind_method(D_METHOD("is_physics_processing_internal"), &Node::is_physics_processing_internal); - ClassDB::bind_method(D_METHOD("set_physics_interpolated", "enable"), &Node::set_physics_interpolated); + ClassDB::bind_method(D_METHOD("set_physics_interpolation_mode", "mode"), &Node::set_physics_interpolation_mode); + ClassDB::bind_method(D_METHOD("get_physics_interpolation_mode"), &Node::get_physics_interpolation_mode); ClassDB::bind_method(D_METHOD("is_physics_interpolated"), &Node::is_physics_interpolated); ClassDB::bind_method(D_METHOD("is_physics_interpolated_and_enabled"), &Node::is_physics_interpolated_and_enabled); ClassDB::bind_method(D_METHOD("reset_physics_interpolation"), &Node::reset_physics_interpolation); @@ -3063,6 +3112,10 @@ void Node::_bind_methods() { BIND_ENUM_CONSTANT(PAUSE_MODE_STOP); BIND_ENUM_CONSTANT(PAUSE_MODE_PROCESS); + BIND_ENUM_CONSTANT(PHYSICS_INTERPOLATION_MODE_INHERIT); + BIND_ENUM_CONSTANT(PHYSICS_INTERPOLATION_MODE_OFF); + BIND_ENUM_CONSTANT(PHYSICS_INTERPOLATION_MODE_ON); + BIND_ENUM_CONSTANT(DUPLICATE_SIGNALS); BIND_ENUM_CONSTANT(DUPLICATE_GROUPS); BIND_ENUM_CONSTANT(DUPLICATE_SCRIPTS); @@ -3078,6 +3131,8 @@ void Node::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "pause_mode", PROPERTY_HINT_ENUM, "Inherit,Stop,Process"), "set_pause_mode", "get_pause_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_interpolation_mode", PROPERTY_HINT_ENUM, "Inherit,Off,On"), "set_physics_interpolation_mode", "get_physics_interpolation_mode"); + #ifdef ENABLE_DEPRECATED //no longer exists, but remains for compatibility (keep previous scenes folded ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor/display_folded", PROPERTY_HINT_NONE, "", 0), "set_display_folded", "is_displayed_folded"); @@ -3091,9 +3146,6 @@ void Node::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "set_custom_multiplayer", "get_custom_multiplayer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "process_priority"), "set_process_priority", "get_process_priority"); - // Disabled for now - // ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_interpolated"), "set_physics_interpolated", "is_physics_interpolated"); - BIND_VMETHOD(MethodInfo("_process", PropertyInfo(Variant::REAL, "delta"))); BIND_VMETHOD(MethodInfo("_physics_process", PropertyInfo(Variant::REAL, "delta"))); BIND_VMETHOD(MethodInfo("_enter_tree")); @@ -3142,6 +3194,7 @@ Node::Node() { data.unhandled_input = false; data.unhandled_key_input = false; data.pause_mode = PAUSE_MODE_INHERIT; + data.physics_interpolation_mode = PHYSICS_INTERPOLATION_MODE_INHERIT; data.pause_owner = nullptr; data.network_master = 1; //server by default data.path_cache = nullptr; diff --git a/scene/main/node.h b/scene/main/node.h index 98c4d728455..133f6e1ac5e 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -55,6 +55,13 @@ public: PAUSE_MODE_PROCESS }; + enum PhysicsInterpolationMode { + + PHYSICS_INTERPOLATION_MODE_INHERIT, + PHYSICS_INTERPOLATION_MODE_OFF, + PHYSICS_INTERPOLATION_MODE_ON + }; + enum DuplicateFlags { DUPLICATE_SIGNALS = 1, @@ -115,7 +122,6 @@ private: List::Element *OW; // owned element List owned; - PauseMode pause_mode; Node *pause_owner; int network_master; @@ -124,6 +130,10 @@ private: int process_priority; + // Keep bitpacked values together to get better packing + PauseMode pause_mode : 2; + PhysicsInterpolationMode physics_interpolation_mode : 2; + // variables used to properly sort the node when processing, ignored otherwise //should move all the stuff below to bits bool physics_process : 1; @@ -424,7 +434,8 @@ public: bool can_process() const; bool can_process_notification(int p_what) const; - void set_physics_interpolated(bool p_interpolated); + void set_physics_interpolation_mode(PhysicsInterpolationMode p_mode); + PhysicsInterpolationMode get_physics_interpolation_mode() const { return data.physics_interpolation_mode; } _FORCE_INLINE_ bool is_physics_interpolated() const { return data.physics_interpolated; } _FORCE_INLINE_ bool is_physics_interpolated_and_enabled() const { return is_inside_tree() && get_tree()->is_physics_interpolation_enabled() && is_physics_interpolated(); } void reset_physics_interpolation();