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.
This commit is contained in:
lawnjelly 2022-05-07 13:16:38 +01:00
parent 0ddecccd01
commit 0ab077fcef
3 changed files with 88 additions and 19 deletions

View file

@ -391,14 +391,14 @@
<method name="is_physics_interpolated" qualifiers="const">
<return type="bool" />
<description>
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].
</description>
</method>
<method name="is_physics_interpolated_and_enabled" qualifiers="const">
<return type="bool" />
<description>
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].
</description>
@ -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.
</description>
</method>
<method name="set_physics_interpolated">
<return type="void" />
<argument index="0" name="enable" type="bool" />
<description>
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.
</description>
</method>
<method name="set_physics_process">
<return type="void" />
<argument index="0" name="enable" type="bool" />
@ -755,6 +747,10 @@
<member name="pause_mode" type="int" setter="set_pause_mode" getter="get_pause_mode" enum="Node.PauseMode" default="0">
Pause mode. How the node will behave if the [SceneTree] is paused.
</member>
<member name="physics_interpolation_mode" type="int" setter="set_physics_interpolation_mode" getter="get_physics_interpolation_mode" enum="Node.PhysicsInterpolationMode" default="0">
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.
</member>
<member name="process_priority" type="int" setter="set_process_priority" getter="get_process_priority" default="0">
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.
</member>
@ -925,6 +921,15 @@
<constant name="PAUSE_MODE_PROCESS" value="2" enum="PauseMode">
Continue to process regardless of the [SceneTree] pause state.
</constant>
<constant name="PHYSICS_INTERPOLATION_MODE_INHERIT" value="0" enum="PhysicsInterpolationMode">
Inherits physics interpolation mode from the node's parent. For the root node, it is equivalent to [constant PHYSICS_INTERPOLATION_MODE_ON]. Default.
</constant>
<constant name="PHYSICS_INTERPOLATION_MODE_OFF" value="1" enum="PhysicsInterpolationMode">
Turn off physics interpolation in this node and children set to [constant PHYSICS_INTERPOLATION_MODE_INHERIT].
</constant>
<constant name="PHYSICS_INTERPOLATION_MODE_ON" value="2" enum="PhysicsInterpolationMode">
Turn on physics interpolation in this node and children set to [constant PHYSICS_INTERPOLATION_MODE_INHERIT].
</constant>
<constant name="DUPLICATE_SIGNALS" value="1" enum="DuplicateFlags">
Duplicate the node's signals.
</constant>

View file

@ -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;

View file

@ -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<Node *>::Element *OW; // owned element
List<Node *> 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();