Physics Interpolation - refactor Camera
and fix get_camera_transform()
* Moves 3D Camera interpolation scene side. * Automatically switches `get_camera_transform()` to report interpolated transform during `_process()`. * Fixes `ClippedCamera` to work with physics interpolation.
This commit is contained in:
parent
b203829361
commit
0b30d77384
20 changed files with 359 additions and 274 deletions
|
@ -34,6 +34,10 @@
|
||||||
#include "core/ustring.h"
|
#include "core/ustring.h"
|
||||||
#include "os/os.h"
|
#include "os/os.h"
|
||||||
|
|
||||||
|
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
||||||
|
#include "scene/main/node.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
static ErrorHandlerList *error_handler_list = nullptr;
|
static ErrorHandlerList *error_handler_list = nullptr;
|
||||||
|
|
||||||
void add_error_handler(ErrorHandlerList *p_handler) {
|
void add_error_handler(ErrorHandlerList *p_handler) {
|
||||||
|
@ -117,3 +121,50 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
|
||||||
void _err_flush_stdout() {
|
void _err_flush_stdout() {
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prevent error spam by limiting the warnings to a certain frequency.
|
||||||
|
void _physics_interpolation_warning(const char *p_function, const char *p_file, int p_line, ObjectID p_id, const char *p_warn_string) {
|
||||||
|
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
||||||
|
const uint32_t warn_max = 2048;
|
||||||
|
const uint32_t warn_timeout_seconds = 15;
|
||||||
|
|
||||||
|
static uint32_t warn_count = warn_max;
|
||||||
|
static uint32_t warn_timeout = warn_timeout_seconds;
|
||||||
|
|
||||||
|
uint32_t time_now = UINT32_MAX;
|
||||||
|
|
||||||
|
if (warn_count) {
|
||||||
|
warn_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!warn_count) {
|
||||||
|
time_now = OS::get_singleton()->get_ticks_msec() / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((warn_count == 0) && (time_now >= warn_timeout)) {
|
||||||
|
warn_count = warn_max;
|
||||||
|
warn_timeout = time_now + warn_timeout_seconds;
|
||||||
|
|
||||||
|
if (GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
|
||||||
|
// UINT64_MAX means unused.
|
||||||
|
if (p_id == UINT64_MAX) {
|
||||||
|
_err_print_error(p_function, p_file, p_line, "[Physics interpolation] " + String(p_warn_string) + " (possibly benign).", ERR_HANDLER_WARNING);
|
||||||
|
} else {
|
||||||
|
String node_name;
|
||||||
|
if (p_id != 0) {
|
||||||
|
if (ObjectDB::get_instance(p_id)) {
|
||||||
|
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(p_id));
|
||||||
|
if (node && node->is_inside_tree()) {
|
||||||
|
node_name = "\"" + String(node->get_path()) + "\"";
|
||||||
|
} else {
|
||||||
|
node_name = "\"unknown\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_err_print_error(p_function, p_file, p_line, "[Physics interpolation] " + String(p_warn_string) + ": " + node_name + " (possibly benign).", ERR_HANDLER_WARNING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#ifndef ERROR_MACROS_H
|
#ifndef ERROR_MACROS_H
|
||||||
#define ERROR_MACROS_H
|
#define ERROR_MACROS_H
|
||||||
|
|
||||||
|
#include "core/object_id.h"
|
||||||
#include "core/safe_refcount.h"
|
#include "core/safe_refcount.h"
|
||||||
#include "core/typedefs.h"
|
#include "core/typedefs.h"
|
||||||
|
|
||||||
|
@ -86,6 +87,8 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
|
||||||
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool fatal = false);
|
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool fatal = false);
|
||||||
void _err_flush_stdout();
|
void _err_flush_stdout();
|
||||||
|
|
||||||
|
void _physics_interpolation_warning(const char *p_function, const char *p_file, int p_line, ObjectID p_id, const char *p_warn_string);
|
||||||
|
|
||||||
#ifndef _STR
|
#ifndef _STR
|
||||||
#define _STR(m_x) #m_x
|
#define _STR(m_x) #m_x
|
||||||
#define _MKSTR(m_x) _STR(m_x)
|
#define _MKSTR(m_x) _STR(m_x)
|
||||||
|
@ -558,4 +561,14 @@ void _err_flush_stdout();
|
||||||
#define DEV_CHECK_ONCE(m_cond)
|
#define DEV_CHECK_ONCE(m_cond)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Physics Interpolation warnings.
|
||||||
|
* These are spam protection warnings.
|
||||||
|
*/
|
||||||
|
#define PHYSICS_INTERPOLATION_NODE_WARNING(m_object_id, m_string) \
|
||||||
|
_physics_interpolation_warning(FUNCTION_STR, __FILE__, __LINE__, m_object_id, m_string)
|
||||||
|
|
||||||
|
#define PHYSICS_INTERPOLATION_WARNING(m_string) \
|
||||||
|
_physics_interpolation_warning(FUNCTION_STR, __FILE__, __LINE__, UINT64_MAX, m_string)
|
||||||
|
|
||||||
#endif // ERROR_MACROS_H
|
#endif // ERROR_MACROS_H
|
||||||
|
|
|
@ -45,14 +45,6 @@
|
||||||
Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
|
Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="camera_reset_physics_interpolation">
|
|
||||||
<return type="void" />
|
|
||||||
<argument index="0" name="camera" type="RID" />
|
|
||||||
<description>
|
|
||||||
Prevents physics interpolation for the current physics tick.
|
|
||||||
This is useful when moving a [Camera] to a new location, to give an instantaneous change rather than interpolation from the previous location.
|
|
||||||
</description>
|
|
||||||
</method>
|
|
||||||
<method name="camera_set_cull_mask">
|
<method name="camera_set_cull_mask">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<argument index="0" name="camera" type="RID" />
|
<argument index="0" name="camera" type="RID" />
|
||||||
|
@ -80,14 +72,6 @@
|
||||||
Sets camera to use frustum projection. This mode allows adjusting the [code]offset[/code] argument to create "tilted frustum" effects.
|
Sets camera to use frustum projection. This mode allows adjusting the [code]offset[/code] argument to create "tilted frustum" effects.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="camera_set_interpolated">
|
|
||||||
<return type="void" />
|
|
||||||
<argument index="0" name="camera" type="RID" />
|
|
||||||
<argument index="1" name="interpolated" type="bool" />
|
|
||||||
<description>
|
|
||||||
Turns on and off physics interpolation for the [Camera].
|
|
||||||
</description>
|
|
||||||
</method>
|
|
||||||
<method name="camera_set_orthogonal">
|
<method name="camera_set_orthogonal">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<argument index="0" name="camera" type="RID" />
|
<argument index="0" name="camera" type="RID" />
|
||||||
|
|
|
@ -1267,7 +1267,7 @@ void CPUParticles2D::_notification(int p_what) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p_what == NOTIFICATION_RESET_PHYSICS_INTERPOLATION) {
|
if (p_what == NOTIFICATION_RESET_PHYSICS_INTERPOLATION && is_inside_tree()) {
|
||||||
// Make sure current is up to date with any pending global transform changes.
|
// 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_curr = get_global_transform_const();
|
||||||
_interpolation_data.global_xform_prev = _interpolation_data.global_xform_curr;
|
_interpolation_data.global_xform_prev = _interpolation_data.global_xform_curr;
|
||||||
|
|
|
@ -33,8 +33,11 @@
|
||||||
#include "collision_object.h"
|
#include "collision_object.h"
|
||||||
#include "core/engine.h"
|
#include "core/engine.h"
|
||||||
#include "core/math/camera_matrix.h"
|
#include "core/math/camera_matrix.h"
|
||||||
|
#include "core/math/transform_interpolator.h"
|
||||||
#include "scene/resources/material.h"
|
#include "scene/resources/material.h"
|
||||||
#include "scene/resources/surface_tool.h"
|
#include "scene/resources/surface_tool.h"
|
||||||
|
#include "servers/visual/visual_server_constants.h"
|
||||||
|
|
||||||
void Camera::_update_audio_listener_state() {
|
void Camera::_update_audio_listener_state() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +82,16 @@ void Camera::_update_camera() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!is_physics_interpolated_and_enabled()) {
|
||||||
VisualServer::get_singleton()->camera_set_transform(camera, get_camera_transform());
|
VisualServer::get_singleton()->camera_set_transform(camera, get_camera_transform());
|
||||||
|
} else {
|
||||||
|
// Ideally we shouldn't be moving a physics interpolated camera within a frame,
|
||||||
|
// because it will break smooth interpolation, but it may occur on e.g. level load.
|
||||||
|
if (!Engine::get_singleton()->is_in_physics_frame() && camera.is_valid()) {
|
||||||
|
_physics_interpolation_ensure_transform_calculated(true);
|
||||||
|
VisualServer::get_singleton()->camera_set_transform(camera, _interpolation_data.camera_xform_interpolated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// here goes listener stuff
|
// here goes listener stuff
|
||||||
/*
|
/*
|
||||||
|
@ -99,7 +111,61 @@ void Camera::_update_camera() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::_physics_interpolated_changed() {
|
void Camera::_physics_interpolated_changed() {
|
||||||
VisualServer::get_singleton()->camera_set_interpolated(camera, is_physics_interpolated());
|
_update_process_mode();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::_physics_interpolation_ensure_data_flipped() {
|
||||||
|
// The curr -> previous update can either occur
|
||||||
|
// on the INTERNAL_PHYSICS_PROCESS OR
|
||||||
|
// on NOTIFICATION_TRANSFORM_CHANGED,
|
||||||
|
// if NOTIFICATION_TRANSFORM_CHANGED takes place
|
||||||
|
// earlier than INTERNAL_PHYSICS_PROCESS on a tick.
|
||||||
|
// This is to ensure that the data keeps flowing, but the new data
|
||||||
|
// doesn't overwrite before prev has been set.
|
||||||
|
|
||||||
|
// Keep the data flowing.
|
||||||
|
uint64_t tick = Engine::get_singleton()->get_physics_frames();
|
||||||
|
if (_interpolation_data.last_update_physics_tick != tick) {
|
||||||
|
_interpolation_data.xform_prev = _interpolation_data.xform_curr;
|
||||||
|
_interpolation_data.last_update_physics_tick = tick;
|
||||||
|
physics_interpolation_flip_data();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::_physics_interpolation_ensure_transform_calculated(bool p_force) const {
|
||||||
|
DEV_CHECK_ONCE(!Engine::get_singleton()->is_in_physics_frame());
|
||||||
|
|
||||||
|
InterpolationData &id = _interpolation_data;
|
||||||
|
uint64_t frame = Engine::get_singleton()->get_frames_drawn();
|
||||||
|
|
||||||
|
if (id.last_update_frame != frame || p_force) {
|
||||||
|
id.last_update_frame = frame;
|
||||||
|
|
||||||
|
TransformInterpolator::interpolate_transform(id.xform_prev, id.xform_curr, id.xform_interpolated, Engine::get_singleton()->get_physics_interpolation_fraction());
|
||||||
|
|
||||||
|
Transform &tr = id.camera_xform_interpolated;
|
||||||
|
tr = _get_adjusted_camera_transform(id.xform_interpolated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::set_desired_process_modes(bool p_process_internal, bool p_physics_process_internal) {
|
||||||
|
_desired_process_internal = p_process_internal;
|
||||||
|
_desired_physics_process_internal = p_physics_process_internal;
|
||||||
|
_update_process_mode();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::_update_process_mode() {
|
||||||
|
bool process = _desired_process_internal;
|
||||||
|
bool physics_process = _desired_physics_process_internal;
|
||||||
|
|
||||||
|
if (is_physics_interpolated_and_enabled()) {
|
||||||
|
if (is_current()) {
|
||||||
|
process = true;
|
||||||
|
physics_process = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set_process_internal(process);
|
||||||
|
set_physics_process_internal(physics_process);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::_notification(int p_what) {
|
void Camera::_notification(int p_what) {
|
||||||
|
@ -116,15 +182,48 @@ void Camera::_notification(int p_what) {
|
||||||
viewport->_camera_set(this);
|
viewport->_camera_set(this);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case NOTIFICATION_INTERNAL_PROCESS: {
|
||||||
|
if (is_physics_interpolated_and_enabled() && camera.is_valid()) {
|
||||||
|
_physics_interpolation_ensure_transform_calculated();
|
||||||
|
|
||||||
|
#ifdef VISUAL_SERVER_DEBUG_PHYSICS_INTERPOLATION
|
||||||
|
print_line("\t\tinterpolated Camera: " + rtos(_interpolation_data.xform_interpolated.origin.x) + "\t( prev " + rtos(_interpolation_data.xform_prev.origin.x) + ", curr " + rtos(_interpolation_data.xform_curr.origin.x) + " ) on tick " + itos(Engine::get_singleton()->get_physics_frames()));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
VisualServer::get_singleton()->camera_set_transform(camera, _interpolation_data.camera_xform_interpolated);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
|
||||||
|
if (is_physics_interpolated_and_enabled()) {
|
||||||
|
_physics_interpolation_ensure_data_flipped();
|
||||||
|
_interpolation_data.xform_curr = get_global_transform();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
case NOTIFICATION_TRANSFORM_CHANGED: {
|
case NOTIFICATION_TRANSFORM_CHANGED: {
|
||||||
|
if (is_physics_interpolated_and_enabled()) {
|
||||||
|
_physics_interpolation_ensure_data_flipped();
|
||||||
|
_interpolation_data.xform_curr = get_global_transform();
|
||||||
|
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
||||||
|
if (!Engine::get_singleton()->is_in_physics_frame()) {
|
||||||
|
PHYSICS_INTERPOLATION_NODE_WARNING(get_instance_id(), "Interpolated Camera triggered from outside physics process");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
_request_camera_update();
|
_request_camera_update();
|
||||||
if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
|
if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
|
||||||
velocity_tracker->update_position(get_global_transform().origin);
|
velocity_tracker->update_position(get_global_transform().origin);
|
||||||
}
|
}
|
||||||
|
// Allow auto-reset when first adding to the tree, as a convenience.
|
||||||
|
if (_is_physics_interpolation_reset_requested() && is_inside_tree()) {
|
||||||
|
_notification(NOTIFICATION_RESET_PHYSICS_INTERPOLATION);
|
||||||
|
_set_physics_interpolation_reset_requested(false);
|
||||||
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: {
|
case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: {
|
||||||
if (is_physics_interpolated()) {
|
if (is_inside_tree()) {
|
||||||
VisualServer::get_singleton()->camera_reset_physics_interpolation(camera);
|
_interpolation_data.xform_curr = get_global_transform();
|
||||||
|
_interpolation_data.xform_prev = _interpolation_data.xform_curr;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_EXIT_WORLD: {
|
case NOTIFICATION_EXIT_WORLD: {
|
||||||
|
@ -148,22 +247,33 @@ void Camera::_notification(int p_what) {
|
||||||
if (viewport) {
|
if (viewport) {
|
||||||
viewport->find_world()->_register_camera(this);
|
viewport->find_world()->_register_camera(this);
|
||||||
}
|
}
|
||||||
|
_update_process_mode();
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_LOST_CURRENT: {
|
case NOTIFICATION_LOST_CURRENT: {
|
||||||
if (viewport) {
|
if (viewport) {
|
||||||
viewport->find_world()->_remove_camera(this);
|
viewport->find_world()->_remove_camera(this);
|
||||||
}
|
}
|
||||||
|
_update_process_mode();
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform Camera::get_camera_transform() const {
|
Transform Camera::_get_adjusted_camera_transform(const Transform &p_xform) const {
|
||||||
Transform tr = get_global_transform().orthonormalized();
|
Transform tr = p_xform.orthonormalized();
|
||||||
tr.origin += tr.basis.get_axis(1) * v_offset;
|
tr.origin += tr.basis.get_axis(1) * v_offset;
|
||||||
tr.origin += tr.basis.get_axis(0) * h_offset;
|
tr.origin += tr.basis.get_axis(0) * h_offset;
|
||||||
return tr;
|
return tr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform Camera::get_camera_transform() const {
|
||||||
|
if (is_physics_interpolated_and_enabled() && !Engine::get_singleton()->is_in_physics_frame()) {
|
||||||
|
_physics_interpolation_ensure_transform_calculated();
|
||||||
|
return _interpolation_data.camera_xform_interpolated;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _get_adjusted_camera_transform(get_global_transform());
|
||||||
|
}
|
||||||
|
|
||||||
void Camera::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) {
|
void Camera::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) {
|
||||||
if (!force_change && fov == p_fovy_degrees && p_z_near == near && p_z_far == far && mode == PROJECTION_PERSPECTIVE) {
|
if (!force_change && fov == p_fovy_degrees && p_z_near == near && p_z_far == far && mode == PROJECTION_PERSPECTIVE) {
|
||||||
return;
|
return;
|
||||||
|
@ -365,6 +475,10 @@ Point2 Camera::unproject_position(const Vector3 &p_pos) const {
|
||||||
Plane p(get_camera_transform().xform_inv(p_pos), 1.0);
|
Plane p(get_camera_transform().xform_inv(p_pos), 1.0);
|
||||||
|
|
||||||
p = cm.xform4(p);
|
p = cm.xform4(p);
|
||||||
|
|
||||||
|
// Prevent divide by zero.
|
||||||
|
// TODO : Investigate, this was causing Nans.
|
||||||
|
ERR_FAIL_COND_V(p.d == 0, Point2());
|
||||||
p.normal /= p.d;
|
p.normal /= p.d;
|
||||||
|
|
||||||
Point2 res;
|
Point2 res;
|
||||||
|
@ -692,25 +806,48 @@ float ClippedCamera::get_margin() const {
|
||||||
return margin;
|
return margin;
|
||||||
}
|
}
|
||||||
void ClippedCamera::set_process_mode(ProcessMode p_mode) {
|
void ClippedCamera::set_process_mode(ProcessMode p_mode) {
|
||||||
|
if (is_physics_interpolated_and_enabled() && p_mode == CLIP_PROCESS_IDLE) {
|
||||||
|
p_mode = CLIP_PROCESS_PHYSICS;
|
||||||
|
WARN_PRINT_ONCE("[Physics interpolation] Forcing ClippedCamera to PROCESS_PHYSICS mode.");
|
||||||
|
}
|
||||||
|
|
||||||
if (process_mode == p_mode) {
|
if (process_mode == p_mode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
process_mode = p_mode;
|
process_mode = p_mode;
|
||||||
set_process_internal(process_mode == CLIP_PROCESS_IDLE);
|
|
||||||
set_physics_process_internal(process_mode == CLIP_PROCESS_PHYSICS);
|
set_desired_process_modes(process_mode == CLIP_PROCESS_IDLE, process_mode == CLIP_PROCESS_PHYSICS);
|
||||||
}
|
}
|
||||||
ClippedCamera::ProcessMode ClippedCamera::get_process_mode() const {
|
ClippedCamera::ProcessMode ClippedCamera::get_process_mode() const {
|
||||||
return process_mode;
|
return process_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform ClippedCamera::get_camera_transform() const {
|
void ClippedCamera::physics_interpolation_flip_data() {
|
||||||
Transform t = Camera::get_camera_transform();
|
_interpolation_data.clip_offset_prev = _interpolation_data.clip_offset_curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClippedCamera::_physics_interpolated_changed() {
|
||||||
|
// Switch process mode to physics if we are turning on interpolation.
|
||||||
|
// Idle process mode doesn't work well with physics interpolation.
|
||||||
|
set_process_mode(get_process_mode());
|
||||||
|
|
||||||
|
Camera::_physics_interpolated_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform ClippedCamera::_get_adjusted_camera_transform(const Transform &p_xform) const {
|
||||||
|
Transform t = Camera::_get_adjusted_camera_transform(p_xform);
|
||||||
t.origin += -t.basis.get_axis(Vector3::AXIS_Z).normalized() * clip_offset;
|
t.origin += -t.basis.get_axis(Vector3::AXIS_Z).normalized() * clip_offset;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClippedCamera::_notification(int p_what) {
|
void ClippedCamera::_notification(int p_what) {
|
||||||
if (p_what == NOTIFICATION_INTERNAL_PROCESS || p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
|
if (p_what == NOTIFICATION_ENTER_TREE) {
|
||||||
|
// Switch process mode to physics if we are turning on interpolation.
|
||||||
|
// Idle process mode doesn't work well with physics interpolation.
|
||||||
|
set_process_mode(get_process_mode());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((p_what == NOTIFICATION_INTERNAL_PROCESS) && process_mode == CLIP_PROCESS_IDLE) || ((p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) && process_mode == CLIP_PROCESS_PHYSICS)) {
|
||||||
Spatial *parent = Object::cast_to<Spatial>(get_parent());
|
Spatial *parent = Object::cast_to<Spatial>(get_parent());
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
return;
|
return;
|
||||||
|
@ -732,7 +869,7 @@ void ClippedCamera::_notification(int p_what) {
|
||||||
|
|
||||||
Vector3 ray_from = parent_plane.project(cam_pos);
|
Vector3 ray_from = parent_plane.project(cam_pos);
|
||||||
|
|
||||||
clip_offset = 0; //reset by defau;t
|
_interpolation_data.clip_offset_curr = 0; // Reset by default.
|
||||||
|
|
||||||
{ //check if points changed
|
{ //check if points changed
|
||||||
Vector<Vector3> local_points = get_near_plane_points();
|
Vector<Vector3> local_points = get_near_plane_points();
|
||||||
|
@ -758,15 +895,29 @@ void ClippedCamera::_notification(int p_what) {
|
||||||
|
|
||||||
float closest_safe = 1.0f, closest_unsafe = 1.0f;
|
float closest_safe = 1.0f, closest_unsafe = 1.0f;
|
||||||
if (dspace->cast_motion(pyramid_shape, xf, cam_pos - ray_from, margin, closest_safe, closest_unsafe, exclude, collision_mask, clip_to_bodies, clip_to_areas)) {
|
if (dspace->cast_motion(pyramid_shape, xf, cam_pos - ray_from, margin, closest_safe, closest_unsafe, exclude, collision_mask, clip_to_bodies, clip_to_areas)) {
|
||||||
clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from) * closest_safe);
|
_interpolation_data.clip_offset_curr = cam_pos.distance_to(ray_from + (cam_pos - ray_from) * closest_safe);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to use the current value
|
||||||
|
// (in the case of non-interpolated).
|
||||||
|
if (!is_physics_interpolated_and_enabled()) {
|
||||||
|
clip_offset = _interpolation_data.clip_offset_curr;
|
||||||
}
|
}
|
||||||
|
|
||||||
_update_camera();
|
_update_camera();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_physics_interpolated_and_enabled() && (p_what == NOTIFICATION_INTERNAL_PROCESS)) {
|
||||||
|
clip_offset = ((_interpolation_data.clip_offset_curr - _interpolation_data.clip_offset_prev) * Engine::get_singleton()->get_physics_interpolation_fraction()) + _interpolation_data.clip_offset_prev;
|
||||||
|
}
|
||||||
|
|
||||||
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
|
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
|
||||||
update_gizmo();
|
update_gizmo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_what == NOTIFICATION_RESET_PHYSICS_INTERPOLATION) {
|
||||||
|
_interpolation_data.clip_offset_prev = _interpolation_data.clip_offset_curr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClippedCamera::set_collision_mask(uint32_t p_mask) {
|
void ClippedCamera::set_collision_mask(uint32_t p_mask) {
|
||||||
|
@ -881,9 +1032,11 @@ void ClippedCamera::_bind_methods() {
|
||||||
}
|
}
|
||||||
ClippedCamera::ClippedCamera() {
|
ClippedCamera::ClippedCamera() {
|
||||||
margin = 0;
|
margin = 0;
|
||||||
clip_offset = 0;
|
|
||||||
process_mode = CLIP_PROCESS_PHYSICS;
|
// Force initializing to physics (prevent noop check).
|
||||||
set_physics_process_internal(true);
|
process_mode = CLIP_PROCESS_IDLE;
|
||||||
|
set_process_mode(CLIP_PROCESS_PHYSICS);
|
||||||
|
|
||||||
collision_mask = 1;
|
collision_mask = 1;
|
||||||
set_notify_local_transform(Engine::get_singleton()->is_editor_hint());
|
set_notify_local_transform(Engine::get_singleton()->is_editor_hint());
|
||||||
points.resize(5);
|
points.resize(5);
|
||||||
|
|
|
@ -61,6 +61,7 @@ public:
|
||||||
private:
|
private:
|
||||||
bool force_change;
|
bool force_change;
|
||||||
bool current;
|
bool current;
|
||||||
|
|
||||||
Viewport *viewport;
|
Viewport *viewport;
|
||||||
|
|
||||||
Projection mode;
|
Projection mode;
|
||||||
|
@ -90,13 +91,44 @@ private:
|
||||||
Ref<SpatialVelocityTracker> velocity_tracker;
|
Ref<SpatialVelocityTracker> velocity_tracker;
|
||||||
bool affect_lod = true;
|
bool affect_lod = true;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
|
// INTERPOLATION FUNCTIONS
|
||||||
|
void _physics_interpolation_ensure_transform_calculated(bool p_force = false) const;
|
||||||
|
void _physics_interpolation_ensure_data_flipped();
|
||||||
|
|
||||||
|
// These can be set by derived Cameras,
|
||||||
|
// if they wish to do processing (while still
|
||||||
|
// allowing physics interpolation to function).
|
||||||
|
bool _desired_process_internal = false;
|
||||||
|
bool _desired_physics_process_internal = false;
|
||||||
|
|
||||||
|
mutable struct InterpolationData {
|
||||||
|
Transform xform_curr;
|
||||||
|
Transform xform_prev;
|
||||||
|
Transform xform_interpolated;
|
||||||
|
Transform camera_xform_interpolated; // After modification according to camera type.
|
||||||
|
uint32_t last_update_physics_tick = 0;
|
||||||
|
uint32_t last_update_frame = UINT32_MAX;
|
||||||
|
} _interpolation_data;
|
||||||
|
|
||||||
|
void _update_process_mode();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// Use from derived classes to set process modes instead of setting directly.
|
||||||
|
// This is because physics interpolation may need to request process modes additionally.
|
||||||
|
void set_desired_process_modes(bool p_process_internal, bool p_physics_process_internal);
|
||||||
|
|
||||||
|
// Opportunity for derived classes to interpolate extra attributes.
|
||||||
|
virtual void physics_interpolation_flip_data() {}
|
||||||
|
|
||||||
|
virtual void _physics_interpolated_changed();
|
||||||
|
virtual Transform _get_adjusted_camera_transform(const Transform &p_xform) const;
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
|
|
||||||
void _update_camera();
|
void _update_camera();
|
||||||
virtual void _request_camera_update();
|
virtual void _request_camera_update();
|
||||||
void _update_camera_mode();
|
void _update_camera_mode();
|
||||||
|
|
||||||
virtual void _physics_interpolated_changed();
|
|
||||||
|
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
virtual void _validate_property(PropertyInfo &p_property) const;
|
virtual void _validate_property(PropertyInfo &p_property) const;
|
||||||
|
|
||||||
|
@ -135,7 +167,7 @@ public:
|
||||||
void set_znear(float p_znear);
|
void set_znear(float p_znear);
|
||||||
void set_frustum_offset(Vector2 p_offset);
|
void set_frustum_offset(Vector2 p_offset);
|
||||||
|
|
||||||
virtual Transform get_camera_transform() const;
|
Transform get_camera_transform() const;
|
||||||
|
|
||||||
virtual Vector3 project_ray_normal(const Point2 &p_pos) const;
|
virtual Vector3 project_ray_normal(const Point2 &p_pos) const;
|
||||||
virtual Vector3 project_ray_origin(const Point2 &p_pos) const;
|
virtual Vector3 project_ray_origin(const Point2 &p_pos) const;
|
||||||
|
@ -195,7 +227,9 @@ private:
|
||||||
ProcessMode process_mode;
|
ProcessMode process_mode;
|
||||||
RID pyramid_shape;
|
RID pyramid_shape;
|
||||||
float margin;
|
float margin;
|
||||||
float clip_offset;
|
|
||||||
|
float clip_offset = 0;
|
||||||
|
|
||||||
uint32_t collision_mask;
|
uint32_t collision_mask;
|
||||||
bool clip_to_areas;
|
bool clip_to_areas;
|
||||||
bool clip_to_bodies;
|
bool clip_to_bodies;
|
||||||
|
@ -204,10 +238,21 @@ private:
|
||||||
|
|
||||||
Vector<Vector3> points;
|
Vector<Vector3> points;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
|
// INTERPOLATION FUNCTIONS
|
||||||
|
struct InterpolatedData {
|
||||||
|
float clip_offset_curr = 0;
|
||||||
|
float clip_offset_prev = 0;
|
||||||
|
} _interpolation_data;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual Transform _get_adjusted_camera_transform(const Transform &p_xform) const;
|
||||||
|
virtual void physics_interpolation_flip_data();
|
||||||
|
virtual void _physics_interpolated_changed();
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
|
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
virtual Transform get_camera_transform() const;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void set_clip_to_areas(bool p_clip);
|
void set_clip_to_areas(bool p_clip);
|
||||||
|
|
|
@ -900,14 +900,6 @@ void CPUParticles::_particles_process(float p_delta) {
|
||||||
p.velocity.z = 0.0;
|
p.velocity.z = 0.0;
|
||||||
p.transform.origin.z = 0.0;
|
p.transform.origin.z = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Teleport if starting a new particle, so
|
|
||||||
// we don't get a streak from the old position
|
|
||||||
// to this new start.
|
|
||||||
if (_interpolated) {
|
|
||||||
p.copy_to(particles_prev[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (!p.active) {
|
} else if (!p.active) {
|
||||||
continue;
|
continue;
|
||||||
} else if (p.time > p.lifetime) {
|
} else if (p.time > p.lifetime) {
|
||||||
|
@ -1012,6 +1004,13 @@ void CPUParticles::_particles_process(float p_delta) {
|
||||||
}
|
}
|
||||||
|
|
||||||
p.transform.origin += p.velocity * local_delta;
|
p.transform.origin += p.velocity * local_delta;
|
||||||
|
|
||||||
|
// Teleport if starting a new particle, so
|
||||||
|
// we don't get a streak from the old position
|
||||||
|
// to this new start.
|
||||||
|
if (restart && _interpolated) {
|
||||||
|
p.copy_to(particles_prev[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -359,7 +359,7 @@ void Spatial::_disable_client_physics_interpolation() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform Spatial::_get_global_transform_interpolated(real_t p_interpolation_fraction) {
|
Transform Spatial::_get_global_transform_interpolated(real_t p_interpolation_fraction) {
|
||||||
ERR_FAIL_NULL_V(is_inside_tree(), Transform());
|
ERR_FAIL_COND_V(!is_inside_tree(), Transform());
|
||||||
|
|
||||||
// set in motion the mechanisms for client side interpolation if not already active
|
// set in motion the mechanisms for client side interpolation if not already active
|
||||||
if (!_is_physics_interpolated_client_side()) {
|
if (!_is_physics_interpolated_client_side()) {
|
||||||
|
|
|
@ -99,12 +99,11 @@ void VisualInstance::_notification(int p_what) {
|
||||||
case NOTIFICATION_TRANSFORM_CHANGED: {
|
case NOTIFICATION_TRANSFORM_CHANGED: {
|
||||||
if (_is_vi_visible() || is_physics_interpolated_and_enabled()) {
|
if (_is_vi_visible() || is_physics_interpolated_and_enabled()) {
|
||||||
if (!_is_using_identity_transform()) {
|
if (!_is_using_identity_transform()) {
|
||||||
Transform gt = get_global_transform();
|
VisualServer::get_singleton()->instance_set_transform(instance, get_global_transform());
|
||||||
VisualServer::get_singleton()->instance_set_transform(instance, gt);
|
|
||||||
|
|
||||||
// For instance when first adding to the tree, when the previous transform is
|
// For instance when first adding to the tree, when the previous transform is
|
||||||
// unset, to prevent streaking from the origin.
|
// unset, to prevent streaking from the origin.
|
||||||
if (_is_physics_interpolation_reset_requested()) {
|
if (_is_physics_interpolation_reset_requested() && is_physics_interpolated_and_enabled() && is_inside_tree()) {
|
||||||
if (_is_vi_visible()) {
|
if (_is_vi_visible()) {
|
||||||
_notification(NOTIFICATION_RESET_PHYSICS_INTERPOLATION);
|
_notification(NOTIFICATION_RESET_PHYSICS_INTERPOLATION);
|
||||||
}
|
}
|
||||||
|
@ -114,7 +113,14 @@ void VisualInstance::_notification(int p_what) {
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: {
|
case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: {
|
||||||
if (_is_vi_visible() && is_physics_interpolated()) {
|
if (_is_vi_visible() && is_physics_interpolated() && is_inside_tree()) {
|
||||||
|
// We must ensure the VisualServer transform is up to date before resetting.
|
||||||
|
// This is because NOTIFICATION_TRANSFORM_CHANGED is deferred,
|
||||||
|
// and cannot be relied to be called in order before NOTIFICATION_RESET_PHYSICS_INTERPOLATION.
|
||||||
|
if (!_is_using_identity_transform()) {
|
||||||
|
VisualServer::get_singleton()->instance_set_transform(instance, get_global_transform());
|
||||||
|
}
|
||||||
|
|
||||||
VisualServer::get_singleton()->instance_reset_physics_interpolation(instance);
|
VisualServer::get_singleton()->instance_reset_physics_interpolation(instance);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -101,6 +101,12 @@ void Node::_notification(int p_notification) {
|
||||||
get_tree()->node_count++;
|
get_tree()->node_count++;
|
||||||
orphan_node_count--;
|
orphan_node_count--;
|
||||||
|
|
||||||
|
// Allow physics interpolated nodes to automatically reset when added to the tree
|
||||||
|
// (this is to save the user doing this manually each time).
|
||||||
|
if (get_tree()->is_physics_interpolation_enabled()) {
|
||||||
|
_set_physics_interpolation_reset_requested(true);
|
||||||
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_EXIT_TREE: {
|
case NOTIFICATION_EXIT_TREE: {
|
||||||
ERR_FAIL_COND(!get_viewport());
|
ERR_FAIL_COND(!get_viewport());
|
||||||
|
@ -221,14 +227,14 @@ void Node::_propagate_physics_interpolated(bool p_interpolated) {
|
||||||
data.blocked--;
|
data.blocked--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::_propagate_physics_interpolation_reset_requested() {
|
void Node::_propagate_physics_interpolation_reset_requested(bool p_requested) {
|
||||||
if (is_physics_interpolated()) {
|
if (is_physics_interpolated()) {
|
||||||
data.physics_interpolation_reset_requested = true;
|
data.physics_interpolation_reset_requested = p_requested;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.blocked++;
|
data.blocked++;
|
||||||
for (int i = 0; i < data.children.size(); i++) {
|
for (int i = 0; i < data.children.size(); i++) {
|
||||||
data.children[i]->_propagate_physics_interpolation_reset_requested();
|
data.children[i]->_propagate_physics_interpolation_reset_requested(p_requested);
|
||||||
}
|
}
|
||||||
data.blocked--;
|
data.blocked--;
|
||||||
}
|
}
|
||||||
|
@ -885,15 +891,23 @@ void Node::set_physics_interpolation_mode(PhysicsInterpolationMode p_mode) {
|
||||||
|
|
||||||
// if swapping from interpolated to non-interpolated, use this as
|
// if swapping from interpolated to non-interpolated, use this as
|
||||||
// an extra means to cause a reset
|
// an extra means to cause a reset
|
||||||
if (is_physics_interpolated() && !interpolate) {
|
if (is_physics_interpolated() && !interpolate && is_inside_tree()) {
|
||||||
reset_physics_interpolation();
|
propagate_notification(NOTIFICATION_RESET_PHYSICS_INTERPOLATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
_propagate_physics_interpolated(interpolate);
|
_propagate_physics_interpolated(interpolate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::reset_physics_interpolation() {
|
void Node::reset_physics_interpolation() {
|
||||||
|
if (is_inside_tree()) {
|
||||||
propagate_notification(NOTIFICATION_RESET_PHYSICS_INTERPOLATION);
|
propagate_notification(NOTIFICATION_RESET_PHYSICS_INTERPOLATION);
|
||||||
|
|
||||||
|
// If `reset_physics_interpolation()` is called explicitly by the user
|
||||||
|
// (e.g. from scripts) then we prevent deferred auto-resets taking place.
|
||||||
|
// The user is trusted to call reset in the right order, and auto-reset
|
||||||
|
// will interfere with their control of prev / curr, so should be turned off.
|
||||||
|
_propagate_physics_interpolation_reset_requested(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float Node::get_physics_process_delta_time() const {
|
float Node::get_physics_process_delta_time() const {
|
||||||
|
@ -1297,12 +1311,6 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
|
||||||
//recognize children created in this node constructor
|
//recognize children created in this node constructor
|
||||||
p_child->data.parent_owned = data.in_constructor;
|
p_child->data.parent_owned = data.in_constructor;
|
||||||
add_child_notify(p_child);
|
add_child_notify(p_child);
|
||||||
|
|
||||||
// Allow physics interpolated nodes to automatically reset when added to the tree
|
|
||||||
// (this is to save the user doing this manually each time)
|
|
||||||
if (is_inside_tree() && get_tree()->is_physics_interpolation_enabled()) {
|
|
||||||
p_child->_propagate_physics_interpolation_reset_requested();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::add_child(Node *p_child, bool p_force_readable_name) {
|
void Node::add_child(Node *p_child, bool p_force_readable_name) {
|
||||||
|
|
|
@ -209,7 +209,7 @@ private:
|
||||||
void _propagate_exit_tree();
|
void _propagate_exit_tree();
|
||||||
void _propagate_after_exit_branch(bool p_exiting_tree);
|
void _propagate_after_exit_branch(bool p_exiting_tree);
|
||||||
void _propagate_physics_interpolated(bool p_interpolated);
|
void _propagate_physics_interpolated(bool p_interpolated);
|
||||||
void _propagate_physics_interpolation_reset_requested();
|
void _propagate_physics_interpolation_reset_requested(bool p_requested);
|
||||||
void _print_stray_nodes();
|
void _print_stray_nodes();
|
||||||
void _propagate_pause_owner(Node *p_owner);
|
void _propagate_pause_owner(Node *p_owner);
|
||||||
void _propagate_groups_dirty();
|
void _propagate_groups_dirty();
|
||||||
|
|
|
@ -555,6 +555,9 @@ void SceneTree::client_physics_interpolation_remove_spatial(SelfList<Spatial> *p
|
||||||
|
|
||||||
void SceneTree::iteration_prepare() {
|
void SceneTree::iteration_prepare() {
|
||||||
if (_physics_interpolation_enabled) {
|
if (_physics_interpolation_enabled) {
|
||||||
|
// Make sure any pending transforms from the last tick / frame
|
||||||
|
// are flushed before pumping the interpolation prev and currents.
|
||||||
|
flush_transform_notifications();
|
||||||
VisualServer::get_singleton()->tick();
|
VisualServer::get_singleton()->tick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -361,11 +361,7 @@ void RasterizerStorage::multimesh_instance_set_transform(RID p_multimesh, int p_
|
||||||
|
|
||||||
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
||||||
if (!Engine::get_singleton()->is_in_physics_frame()) {
|
if (!Engine::get_singleton()->is_in_physics_frame()) {
|
||||||
static int32_t warn_count = 0;
|
PHYSICS_INTERPOLATION_WARNING("Interpolated MultiMesh triggered from outside physics process");
|
||||||
warn_count++;
|
|
||||||
if (((warn_count % 2048) == 0) && GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
|
|
||||||
WARN_PRINT("[Physics interpolation] MultiMesh interpolation is being triggered from outside physics process, this might lead to issues (possibly benign).");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
|
@ -521,11 +517,7 @@ void RasterizerStorage::multimesh_set_as_bulk_array_interpolated(RID p_multimesh
|
||||||
_multimesh_add_to_interpolation_lists(p_multimesh, *mmi);
|
_multimesh_add_to_interpolation_lists(p_multimesh, *mmi);
|
||||||
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
||||||
if (!Engine::get_singleton()->is_in_physics_frame()) {
|
if (!Engine::get_singleton()->is_in_physics_frame()) {
|
||||||
static int32_t warn_count = 0;
|
PHYSICS_INTERPOLATION_WARNING("Interpolated MultiMesh triggered from outside physics process");
|
||||||
warn_count++;
|
|
||||||
if (((warn_count % 2048) == 0) && GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
|
|
||||||
WARN_PRINT("[Physics interpolation] MultiMesh interpolation is being triggered from outside physics process, this might lead to issues (possibly benign).");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -541,11 +533,7 @@ void RasterizerStorage::multimesh_set_as_bulk_array(RID p_multimesh, const PoolV
|
||||||
_multimesh_add_to_interpolation_lists(p_multimesh, *mmi);
|
_multimesh_add_to_interpolation_lists(p_multimesh, *mmi);
|
||||||
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
||||||
if (!Engine::get_singleton()->is_in_physics_frame()) {
|
if (!Engine::get_singleton()->is_in_physics_frame()) {
|
||||||
static int32_t warn_count = 0;
|
PHYSICS_INTERPOLATION_WARNING("Interpolated MultiMesh triggered from outside physics process");
|
||||||
warn_count++;
|
|
||||||
if (((warn_count % 2048) == 0) && GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
|
|
||||||
WARN_PRINT("[Physics interpolation] MultiMesh interpolation is being triggered from outside physics process, this might lead to issues (possibly benign).");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -53,6 +53,9 @@
|
||||||
// This is expensive.
|
// This is expensive.
|
||||||
// #define VISUAL_SERVER_CANVAS_CHECK_BOUNDS
|
// #define VISUAL_SERVER_CANVAS_CHECK_BOUNDS
|
||||||
|
|
||||||
|
// Uncomment this define to produce debugging output for physics interpolation.
|
||||||
|
// #define VISUAL_SERVER_DEBUG_PHYSICS_INTERPOLATION
|
||||||
|
|
||||||
#endif // DEV_ENABLED
|
#endif // DEV_ENABLED
|
||||||
|
|
||||||
#endif // VISUAL_SERVER_CONSTANTS_H
|
#endif // VISUAL_SERVER_CONSTANTS_H
|
||||||
|
|
|
@ -461,8 +461,6 @@ public:
|
||||||
BIND4(camera_set_orthogonal, RID, float, float, float)
|
BIND4(camera_set_orthogonal, RID, float, float, float)
|
||||||
BIND5(camera_set_frustum, RID, float, Vector2, float, float)
|
BIND5(camera_set_frustum, RID, float, Vector2, float, float)
|
||||||
BIND2(camera_set_transform, RID, const Transform &)
|
BIND2(camera_set_transform, RID, const Transform &)
|
||||||
BIND2(camera_set_interpolated, RID, bool)
|
|
||||||
BIND1(camera_reset_physics_interpolation, RID)
|
|
||||||
BIND2(camera_set_cull_mask, RID, uint32_t)
|
BIND2(camera_set_cull_mask, RID, uint32_t)
|
||||||
BIND2(camera_set_environment, RID, RID)
|
BIND2(camera_set_environment, RID, RID)
|
||||||
BIND2(camera_set_use_vertical_aspect, RID, bool)
|
BIND2(camera_set_use_vertical_aspect, RID, bool)
|
||||||
|
|
|
@ -40,16 +40,6 @@
|
||||||
|
|
||||||
/* CAMERA API */
|
/* CAMERA API */
|
||||||
|
|
||||||
Transform VisualServerScene::Camera::get_transform_interpolated() const {
|
|
||||||
if (!interpolated) {
|
|
||||||
return transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
Transform final;
|
|
||||||
TransformInterpolator::interpolate_transform_via_method(transform_prev, transform, final, Engine::get_singleton()->get_physics_interpolation_fraction(), interpolation_method);
|
|
||||||
return final;
|
|
||||||
}
|
|
||||||
|
|
||||||
RID VisualServerScene::camera_create() {
|
RID VisualServerScene::camera_create() {
|
||||||
Camera *camera = memnew(Camera);
|
Camera *camera = memnew(Camera);
|
||||||
return camera_owner.make_rid(camera);
|
return camera_owner.make_rid(camera);
|
||||||
|
@ -83,59 +73,11 @@ void VisualServerScene::camera_set_frustum(RID p_camera, float p_size, Vector2 p
|
||||||
camera->zfar = p_z_far;
|
camera->zfar = p_z_far;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualServerScene::camera_reset_physics_interpolation(RID p_camera) {
|
|
||||||
Camera *camera = camera_owner.get(p_camera);
|
|
||||||
ERR_FAIL_COND(!camera);
|
|
||||||
|
|
||||||
if (_interpolation_data.interpolation_enabled && camera->interpolated) {
|
|
||||||
_interpolation_data.camera_teleport_list.push_back(p_camera);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualServerScene::camera_set_interpolated(RID p_camera, bool p_interpolated) {
|
|
||||||
Camera *camera = camera_owner.get(p_camera);
|
|
||||||
ERR_FAIL_COND(!camera);
|
|
||||||
camera->interpolated = p_interpolated;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualServerScene::camera_set_transform(RID p_camera, const Transform &p_transform) {
|
void VisualServerScene::camera_set_transform(RID p_camera, const Transform &p_transform) {
|
||||||
Camera *camera = camera_owner.get(p_camera);
|
Camera *camera = camera_owner.get(p_camera);
|
||||||
ERR_FAIL_COND(!camera);
|
ERR_FAIL_COND(!camera);
|
||||||
|
|
||||||
camera->transform = p_transform.orthonormalized();
|
camera->transform = p_transform.orthonormalized();
|
||||||
|
|
||||||
if (_interpolation_data.interpolation_enabled) {
|
|
||||||
if (camera->interpolated) {
|
|
||||||
if (!camera->on_interpolate_transform_list) {
|
|
||||||
_interpolation_data.camera_transform_update_list_curr->push_back(p_camera);
|
|
||||||
camera->on_interpolate_transform_list = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// decide on the interpolation method .. slerp if possible
|
|
||||||
camera->interpolation_method = TransformInterpolator::find_method(camera->transform_prev.basis, camera->transform.basis);
|
|
||||||
|
|
||||||
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
|
||||||
if (!Engine::get_singleton()->is_in_physics_frame()) {
|
|
||||||
// Effectively a WARN_PRINT_ONCE but after a certain number of occurrences.
|
|
||||||
static int32_t warn_count = -256;
|
|
||||||
if ((warn_count == 0) && GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
|
|
||||||
WARN_PRINT("[Physics interpolation] Camera interpolation is being triggered from outside physics process, this might lead to issues (possibly benign).");
|
|
||||||
}
|
|
||||||
warn_count++;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
|
||||||
if (Engine::get_singleton()->is_in_physics_frame()) {
|
|
||||||
static int32_t warn_count = -256;
|
|
||||||
if ((warn_count == 0) && GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
|
|
||||||
WARN_PRINT("[Physics interpolation] Non-interpolated Camera is being triggered from physics process, this might lead to issues (possibly benign).");
|
|
||||||
}
|
|
||||||
warn_count++;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualServerScene::camera_set_cull_mask(RID p_camera, uint32_t p_layers) {
|
void VisualServerScene::camera_set_cull_mask(RID p_camera, uint32_t p_layers) {
|
||||||
|
@ -828,7 +770,13 @@ void VisualServerScene::instance_reset_physics_interpolation(RID p_instance) {
|
||||||
ERR_FAIL_COND(!instance);
|
ERR_FAIL_COND(!instance);
|
||||||
|
|
||||||
if (_interpolation_data.interpolation_enabled && instance->interpolated) {
|
if (_interpolation_data.interpolation_enabled && instance->interpolated) {
|
||||||
_interpolation_data.instance_teleport_list.push_back(p_instance);
|
instance->transform_prev = instance->transform_curr;
|
||||||
|
instance->transform_checksum_prev = instance->transform_checksum_curr;
|
||||||
|
|
||||||
|
#ifdef VISUAL_SERVER_DEBUG_PHYSICS_INTERPOLATION
|
||||||
|
print_line("instance_reset_physics_interpolation .. tick " + itos(Engine::get_singleton()->get_physics_frames()));
|
||||||
|
print_line("\tprev " + rtos(instance->transform_prev.origin.x) + ", curr " + rtos(instance->transform_curr.origin.x));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -842,6 +790,10 @@ void VisualServerScene::instance_set_transform(RID p_instance, const Transform &
|
||||||
Instance *instance = instance_owner.get(p_instance);
|
Instance *instance = instance_owner.get(p_instance);
|
||||||
ERR_FAIL_COND(!instance);
|
ERR_FAIL_COND(!instance);
|
||||||
|
|
||||||
|
#ifdef VISUAL_SERVER_DEBUG_PHYSICS_INTERPOLATION
|
||||||
|
print_line("instance_set_transform " + rtos(p_transform.origin.x) + " .. tick " + itos(Engine::get_singleton()->get_physics_frames()));
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!(_interpolation_data.interpolation_enabled && instance->interpolated) || !instance->scenario) {
|
if (!(_interpolation_data.interpolation_enabled && instance->interpolated) || !instance->scenario) {
|
||||||
if (instance->transform == p_transform) {
|
if (instance->transform == p_transform) {
|
||||||
return; //must be checked to avoid worst evil
|
return; //must be checked to avoid worst evil
|
||||||
|
@ -865,24 +817,7 @@ void VisualServerScene::instance_set_transform(RID p_instance, const Transform &
|
||||||
|
|
||||||
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
||||||
if ((_interpolation_data.interpolation_enabled && !instance->interpolated) && (Engine::get_singleton()->is_in_physics_frame())) {
|
if ((_interpolation_data.interpolation_enabled && !instance->interpolated) && (Engine::get_singleton()->is_in_physics_frame())) {
|
||||||
static int32_t warn_count = 0;
|
PHYSICS_INTERPOLATION_NODE_WARNING(instance->object_id, "Non-interpolated triggered from physics process");
|
||||||
warn_count++;
|
|
||||||
if (((warn_count % 2048) == 0) && GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
|
|
||||||
String node_name;
|
|
||||||
ObjectID id = instance->object_id;
|
|
||||||
if (id != 0) {
|
|
||||||
if (ObjectDB::get_instance(id)) {
|
|
||||||
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(id));
|
|
||||||
if (node && node->is_inside_tree()) {
|
|
||||||
node_name = "\"" + String(node->get_path()) + "\"";
|
|
||||||
} else {
|
|
||||||
node_name = "\"unknown\"";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WARN_PRINT("[Physics interpolation] Non-interpolated Instance is being triggered from physics process, this might lead to issues: " + node_name + " (possibly benign).");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -918,6 +853,10 @@ void VisualServerScene::instance_set_transform(RID p_instance, const Transform &
|
||||||
|
|
||||||
instance->transform_curr = p_transform;
|
instance->transform_curr = p_transform;
|
||||||
|
|
||||||
|
#ifdef VISUAL_SERVER_DEBUG_PHYSICS_INTERPOLATION
|
||||||
|
print_line("\tprev " + rtos(instance->transform_prev.origin.x) + ", curr " + rtos(instance->transform_curr.origin.x));
|
||||||
|
#endif
|
||||||
|
|
||||||
// keep checksums up to date
|
// keep checksums up to date
|
||||||
instance->transform_checksum_curr = new_checksum;
|
instance->transform_checksum_curr = new_checksum;
|
||||||
|
|
||||||
|
@ -950,41 +889,11 @@ void VisualServerScene::instance_set_transform(RID p_instance, const Transform &
|
||||||
|
|
||||||
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
|
||||||
if (!Engine::get_singleton()->is_in_physics_frame()) {
|
if (!Engine::get_singleton()->is_in_physics_frame()) {
|
||||||
static int32_t warn_count = 0;
|
PHYSICS_INTERPOLATION_NODE_WARNING(instance->object_id, "Interpolated triggered from outside physics process");
|
||||||
warn_count++;
|
|
||||||
if (((warn_count % 2048) == 0) && GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
|
|
||||||
String node_name;
|
|
||||||
ObjectID id = instance->object_id;
|
|
||||||
if (id != 0) {
|
|
||||||
if (ObjectDB::get_instance(id)) {
|
|
||||||
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(id));
|
|
||||||
if (node && node->is_inside_tree()) {
|
|
||||||
node_name = "\"" + String(node->get_path()) + "\"";
|
|
||||||
} else {
|
|
||||||
node_name = "\"unknown\"";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WARN_PRINT("[Physics interpolation] Instance interpolation is being triggered from outside physics process, this might lead to issues: " + node_name + " (possibly benign).");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualServerScene::InterpolationData::notify_free_camera(RID p_rid, Camera &r_camera) {
|
|
||||||
r_camera.on_interpolate_transform_list = false;
|
|
||||||
|
|
||||||
if (!interpolation_enabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the camera was on any of the lists, remove
|
|
||||||
camera_transform_update_list_curr->erase_multiple_unordered(p_rid);
|
|
||||||
camera_transform_update_list_prev->erase_multiple_unordered(p_rid);
|
|
||||||
camera_teleport_list.erase_multiple_unordered(p_rid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualServerScene::InterpolationData::notify_free_instance(RID p_rid, Instance &r_instance) {
|
void VisualServerScene::InterpolationData::notify_free_instance(RID p_rid, Instance &r_instance) {
|
||||||
r_instance.on_interpolate_list = false;
|
r_instance.on_interpolate_list = false;
|
||||||
r_instance.on_interpolate_transform_list = false;
|
r_instance.on_interpolate_transform_list = false;
|
||||||
|
@ -997,10 +906,13 @@ void VisualServerScene::InterpolationData::notify_free_instance(RID p_rid, Insta
|
||||||
instance_interpolate_update_list.erase_multiple_unordered(p_rid);
|
instance_interpolate_update_list.erase_multiple_unordered(p_rid);
|
||||||
instance_transform_update_list_curr->erase_multiple_unordered(p_rid);
|
instance_transform_update_list_curr->erase_multiple_unordered(p_rid);
|
||||||
instance_transform_update_list_prev->erase_multiple_unordered(p_rid);
|
instance_transform_update_list_prev->erase_multiple_unordered(p_rid);
|
||||||
instance_teleport_list.erase_multiple_unordered(p_rid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualServerScene::update_interpolation_tick(bool p_process) {
|
void VisualServerScene::update_interpolation_tick(bool p_process) {
|
||||||
|
#ifdef VISUAL_SERVER_DEBUG_PHYSICS_INTERPOLATION
|
||||||
|
print_line("update_interpolation_tick " + itos(Engine::get_singleton()->get_physics_frames()));
|
||||||
|
#endif
|
||||||
|
|
||||||
// update interpolation in storage
|
// update interpolation in storage
|
||||||
VSG::storage->update_interpolation_tick(p_process);
|
VSG::storage->update_interpolation_tick(p_process);
|
||||||
|
|
||||||
|
@ -1057,64 +969,12 @@ void VisualServerScene::update_interpolation_tick(bool p_process) {
|
||||||
|
|
||||||
// prepare for the next iteration
|
// prepare for the next iteration
|
||||||
_interpolation_data.instance_transform_update_list_curr->clear();
|
_interpolation_data.instance_transform_update_list_curr->clear();
|
||||||
|
|
||||||
// CAMERAS
|
|
||||||
// detect any that were on the previous transform list that are no longer active,
|
|
||||||
for (unsigned int n = 0; n < _interpolation_data.camera_transform_update_list_prev->size(); n++) {
|
|
||||||
const RID &rid = (*_interpolation_data.camera_transform_update_list_prev)[n];
|
|
||||||
Camera *camera = camera_owner.getornull(rid);
|
|
||||||
|
|
||||||
// no longer active? (either the instance deleted or no longer being transformed)
|
|
||||||
if (camera && !camera->on_interpolate_transform_list) {
|
|
||||||
camera->transform = camera->transform_prev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// cameras , swap any current with previous
|
|
||||||
for (unsigned int n = 0; n < _interpolation_data.camera_transform_update_list_curr->size(); n++) {
|
|
||||||
const RID &rid = (*_interpolation_data.camera_transform_update_list_curr)[n];
|
|
||||||
Camera *camera = camera_owner.getornull(rid);
|
|
||||||
if (camera) {
|
|
||||||
camera->transform_prev = camera->transform;
|
|
||||||
camera->on_interpolate_transform_list = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we maintain a mirror list for the transform updates, so we can detect when an instance
|
|
||||||
// is no longer being transformed, and remove it from the interpolate list
|
|
||||||
SWAP(_interpolation_data.camera_transform_update_list_curr, _interpolation_data.camera_transform_update_list_prev);
|
|
||||||
|
|
||||||
// prepare for the next iteration
|
|
||||||
_interpolation_data.camera_transform_update_list_curr->clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualServerScene::update_interpolation_frame(bool p_process) {
|
void VisualServerScene::update_interpolation_frame(bool p_process) {
|
||||||
// update interpolation in storage
|
// update interpolation in storage
|
||||||
VSG::storage->update_interpolation_frame(p_process);
|
VSG::storage->update_interpolation_frame(p_process);
|
||||||
|
|
||||||
// teleported instances
|
|
||||||
for (unsigned int n = 0; n < _interpolation_data.instance_teleport_list.size(); n++) {
|
|
||||||
const RID &rid = _interpolation_data.instance_teleport_list[n];
|
|
||||||
Instance *instance = instance_owner.getornull(rid);
|
|
||||||
if (instance) {
|
|
||||||
instance->transform_prev = instance->transform_curr;
|
|
||||||
instance->transform_checksum_prev = instance->transform_checksum_curr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_interpolation_data.instance_teleport_list.clear();
|
|
||||||
|
|
||||||
// camera teleports
|
|
||||||
for (unsigned int n = 0; n < _interpolation_data.camera_teleport_list.size(); n++) {
|
|
||||||
const RID &rid = _interpolation_data.camera_teleport_list[n];
|
|
||||||
Camera *camera = camera_owner.getornull(rid);
|
|
||||||
if (camera) {
|
|
||||||
camera->transform_prev = camera->transform;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_interpolation_data.camera_teleport_list.clear();
|
|
||||||
|
|
||||||
if (p_process) {
|
if (p_process) {
|
||||||
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
|
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
|
||||||
|
|
||||||
|
@ -1124,6 +984,10 @@ void VisualServerScene::update_interpolation_frame(bool p_process) {
|
||||||
if (instance) {
|
if (instance) {
|
||||||
TransformInterpolator::interpolate_transform_via_method(instance->transform_prev, instance->transform_curr, instance->transform, f, instance->interpolation_method);
|
TransformInterpolator::interpolate_transform_via_method(instance->transform_prev, instance->transform_curr, instance->transform, f, instance->interpolation_method);
|
||||||
|
|
||||||
|
#ifdef VISUAL_SERVER_DEBUG_PHYSICS_INTERPOLATION
|
||||||
|
print_line("\t\tinterpolated: " + rtos(instance->transform.origin.x) + "\t( prev " + rtos(instance->transform_prev.origin.x) + ", curr " + rtos(instance->transform_curr.origin.x) + " ) on tick " + itos(Engine::get_singleton()->get_physics_frames()));
|
||||||
|
#endif
|
||||||
|
|
||||||
// make sure AABBs are constantly up to date through the interpolation
|
// make sure AABBs are constantly up to date through the interpolation
|
||||||
_instance_queue_update(instance, true);
|
_instance_queue_update(instance, true);
|
||||||
}
|
}
|
||||||
|
@ -2930,10 +2794,8 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario, Size2 p_view
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform camera_transform = _interpolation_data.interpolation_enabled ? camera->get_transform_interpolated() : camera->transform;
|
_prepare_scene(camera->transform, camera_matrix, ortho, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), camera->previous_room_id_hint);
|
||||||
|
_render_scene(camera->transform, camera_matrix, 0, ortho, camera->env, p_scenario, p_shadow_atlas, RID(), -1);
|
||||||
_prepare_scene(camera_transform, camera_matrix, ortho, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), camera->previous_room_id_hint);
|
|
||||||
_render_scene(camera_transform, camera_matrix, 0, ortho, camera->env, p_scenario, p_shadow_atlas, RID(), -1);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4615,8 +4477,6 @@ void VisualServerScene::update_dirty_instances() {
|
||||||
bool VisualServerScene::free(RID p_rid) {
|
bool VisualServerScene::free(RID p_rid) {
|
||||||
if (camera_owner.owns(p_rid)) {
|
if (camera_owner.owns(p_rid)) {
|
||||||
Camera *camera = camera_owner.get(p_rid);
|
Camera *camera = camera_owner.get(p_rid);
|
||||||
_interpolation_data.notify_free_camera(p_rid, *camera);
|
|
||||||
|
|
||||||
camera_owner.free(p_rid);
|
camera_owner.free(p_rid);
|
||||||
memdelete(camera);
|
memdelete(camera);
|
||||||
} else if (scenario_owner.owns(p_rid)) {
|
} else if (scenario_owner.owns(p_rid)) {
|
||||||
|
|
|
@ -81,20 +81,12 @@ public:
|
||||||
uint32_t visible_layers;
|
uint32_t visible_layers;
|
||||||
RID env;
|
RID env;
|
||||||
|
|
||||||
// transform_prev is only used when using fixed timestep interpolation
|
|
||||||
Transform transform;
|
Transform transform;
|
||||||
Transform transform_prev;
|
|
||||||
|
|
||||||
bool interpolated : 1;
|
|
||||||
bool on_interpolate_transform_list : 1;
|
|
||||||
|
|
||||||
bool vaspect : 1;
|
bool vaspect : 1;
|
||||||
TransformInterpolator::Method interpolation_method : 3;
|
|
||||||
|
|
||||||
int32_t previous_room_id_hint;
|
int32_t previous_room_id_hint;
|
||||||
|
|
||||||
Transform get_transform_interpolated() const;
|
|
||||||
|
|
||||||
Camera() {
|
Camera() {
|
||||||
visible_layers = 0xFFFFFFFF;
|
visible_layers = 0xFFFFFFFF;
|
||||||
fov = 70;
|
fov = 70;
|
||||||
|
@ -105,9 +97,6 @@ public:
|
||||||
offset = Vector2();
|
offset = Vector2();
|
||||||
vaspect = false;
|
vaspect = false;
|
||||||
previous_room_id_hint = -1;
|
previous_room_id_hint = -1;
|
||||||
interpolated = true;
|
|
||||||
on_interpolate_transform_list = false;
|
|
||||||
interpolation_method = TransformInterpolator::INTERP_LERP;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -118,8 +107,6 @@ public:
|
||||||
virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far);
|
virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far);
|
||||||
virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far);
|
virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far);
|
||||||
virtual void camera_set_transform(RID p_camera, const Transform &p_transform);
|
virtual void camera_set_transform(RID p_camera, const Transform &p_transform);
|
||||||
virtual void camera_set_interpolated(RID p_camera, bool p_interpolated);
|
|
||||||
virtual void camera_reset_physics_interpolation(RID p_camera);
|
|
||||||
virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers);
|
virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers);
|
||||||
virtual void camera_set_environment(RID p_camera, RID p_env);
|
virtual void camera_set_environment(RID p_camera, RID p_env);
|
||||||
virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable);
|
virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable);
|
||||||
|
@ -410,18 +397,11 @@ public:
|
||||||
virtual void set_physics_interpolation_enabled(bool p_enabled);
|
virtual void set_physics_interpolation_enabled(bool p_enabled);
|
||||||
|
|
||||||
struct InterpolationData {
|
struct InterpolationData {
|
||||||
void notify_free_camera(RID p_rid, Camera &r_camera);
|
|
||||||
void notify_free_instance(RID p_rid, Instance &r_instance);
|
void notify_free_instance(RID p_rid, Instance &r_instance);
|
||||||
LocalVector<RID> instance_interpolate_update_list;
|
LocalVector<RID> instance_interpolate_update_list;
|
||||||
LocalVector<RID> instance_transform_update_lists[2];
|
LocalVector<RID> instance_transform_update_lists[2];
|
||||||
LocalVector<RID> *instance_transform_update_list_curr = &instance_transform_update_lists[0];
|
LocalVector<RID> *instance_transform_update_list_curr = &instance_transform_update_lists[0];
|
||||||
LocalVector<RID> *instance_transform_update_list_prev = &instance_transform_update_lists[1];
|
LocalVector<RID> *instance_transform_update_list_prev = &instance_transform_update_lists[1];
|
||||||
LocalVector<RID> instance_teleport_list;
|
|
||||||
|
|
||||||
LocalVector<RID> camera_transform_update_lists[2];
|
|
||||||
LocalVector<RID> *camera_transform_update_list_curr = &camera_transform_update_lists[0];
|
|
||||||
LocalVector<RID> *camera_transform_update_list_prev = &camera_transform_update_lists[1];
|
|
||||||
LocalVector<RID> camera_teleport_list;
|
|
||||||
|
|
||||||
bool interpolation_enabled = false;
|
bool interpolation_enabled = false;
|
||||||
} _interpolation_data;
|
} _interpolation_data;
|
||||||
|
|
|
@ -375,8 +375,6 @@ public:
|
||||||
FUNC4(camera_set_orthogonal, RID, float, float, float)
|
FUNC4(camera_set_orthogonal, RID, float, float, float)
|
||||||
FUNC5(camera_set_frustum, RID, float, Vector2, float, float)
|
FUNC5(camera_set_frustum, RID, float, Vector2, float, float)
|
||||||
FUNC2(camera_set_transform, RID, const Transform &)
|
FUNC2(camera_set_transform, RID, const Transform &)
|
||||||
FUNC2(camera_set_interpolated, RID, bool)
|
|
||||||
FUNC1(camera_reset_physics_interpolation, RID)
|
|
||||||
FUNC2(camera_set_cull_mask, RID, uint32_t)
|
FUNC2(camera_set_cull_mask, RID, uint32_t)
|
||||||
FUNC2(camera_set_environment, RID, RID)
|
FUNC2(camera_set_environment, RID, RID)
|
||||||
FUNC2(camera_set_use_vertical_aspect, RID, bool)
|
FUNC2(camera_set_use_vertical_aspect, RID, bool)
|
||||||
|
|
|
@ -2095,8 +2095,6 @@ void VisualServer::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("camera_set_orthogonal", "camera", "size", "z_near", "z_far"), &VisualServer::camera_set_orthogonal);
|
ClassDB::bind_method(D_METHOD("camera_set_orthogonal", "camera", "size", "z_near", "z_far"), &VisualServer::camera_set_orthogonal);
|
||||||
ClassDB::bind_method(D_METHOD("camera_set_frustum", "camera", "size", "offset", "z_near", "z_far"), &VisualServer::camera_set_frustum);
|
ClassDB::bind_method(D_METHOD("camera_set_frustum", "camera", "size", "offset", "z_near", "z_far"), &VisualServer::camera_set_frustum);
|
||||||
ClassDB::bind_method(D_METHOD("camera_set_transform", "camera", "transform"), &VisualServer::camera_set_transform);
|
ClassDB::bind_method(D_METHOD("camera_set_transform", "camera", "transform"), &VisualServer::camera_set_transform);
|
||||||
ClassDB::bind_method(D_METHOD("camera_set_interpolated", "camera", "interpolated"), &VisualServer::camera_set_interpolated);
|
|
||||||
ClassDB::bind_method(D_METHOD("camera_reset_physics_interpolation", "camera"), &VisualServer::camera_reset_physics_interpolation);
|
|
||||||
ClassDB::bind_method(D_METHOD("camera_set_cull_mask", "camera", "layers"), &VisualServer::camera_set_cull_mask);
|
ClassDB::bind_method(D_METHOD("camera_set_cull_mask", "camera", "layers"), &VisualServer::camera_set_cull_mask);
|
||||||
ClassDB::bind_method(D_METHOD("camera_set_environment", "camera", "env"), &VisualServer::camera_set_environment);
|
ClassDB::bind_method(D_METHOD("camera_set_environment", "camera", "env"), &VisualServer::camera_set_environment);
|
||||||
ClassDB::bind_method(D_METHOD("camera_set_use_vertical_aspect", "camera", "enable"), &VisualServer::camera_set_use_vertical_aspect);
|
ClassDB::bind_method(D_METHOD("camera_set_use_vertical_aspect", "camera", "enable"), &VisualServer::camera_set_use_vertical_aspect);
|
||||||
|
|
|
@ -634,8 +634,6 @@ public:
|
||||||
virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) = 0;
|
virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) = 0;
|
||||||
virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) = 0;
|
virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) = 0;
|
||||||
virtual void camera_set_transform(RID p_camera, const Transform &p_transform) = 0;
|
virtual void camera_set_transform(RID p_camera, const Transform &p_transform) = 0;
|
||||||
virtual void camera_set_interpolated(RID p_camera, bool p_interpolated) = 0;
|
|
||||||
virtual void camera_reset_physics_interpolation(RID p_camera) = 0;
|
|
||||||
virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers) = 0;
|
virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers) = 0;
|
||||||
virtual void camera_set_environment(RID p_camera, RID p_env) = 0;
|
virtual void camera_set_environment(RID p_camera, RID p_env) = 0;
|
||||||
virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable) = 0;
|
virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable) = 0;
|
||||||
|
|
Loading…
Reference in a new issue