1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-14 13:41:12 +00:00

Physics interpolation - Move out of Scenario

Move VisualServer interpolation data out of Scenario and into VisualServerScene, so the interpolation data and enabled status is now common to all Scenarios.

Fix physics interpolation in multithreaded mode by ensuring tick and pre-draw are called.
This commit is contained in:
lawnjelly
2022-04-04 15:18:44 +01:00
parent 33500a1529
commit d2b1d29634
9 changed files with 155 additions and 229 deletions

View File

@@ -39,8 +39,8 @@
/* CAMERA API */
Transform VisualServerScene::Camera::get_transform() const {
if (!is_currently_interpolated()) {
Transform VisualServerScene::Camera::get_transform_interpolated() const {
if (!interpolated) {
return transform;
}
@@ -54,25 +54,6 @@ RID VisualServerScene::camera_create() {
return camera_owner.make_rid(camera);
}
void VisualServerScene::camera_set_scenario(RID p_camera, RID p_scenario) {
Camera *camera = camera_owner.get(p_camera);
ERR_FAIL_COND(!camera);
Scenario *old_scenario = camera->scenario;
if (p_scenario.is_valid()) {
camera->scenario = scenario_owner.get(p_scenario);
ERR_FAIL_COND(!camera->scenario);
} else {
camera->scenario = nullptr;
}
if (old_scenario && (old_scenario != camera->scenario)) {
// remove any interpolation data associated with the camera in this scenario
old_scenario->_interpolation_data.notify_free_camera(p_camera, *camera);
}
}
void VisualServerScene::camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) {
Camera *camera = camera_owner.get(p_camera);
ERR_FAIL_COND(!camera);
@@ -105,8 +86,8 @@ void VisualServerScene::camera_reset_physics_interpolation(RID p_camera) {
Camera *camera = camera_owner.get(p_camera);
ERR_FAIL_COND(!camera);
if (camera->is_currently_interpolated()) {
camera->scenario->_interpolation_data.camera_teleport_list.push_back(p_camera);
if (_interpolation_data.interpolation_enabled && camera->interpolated) {
_interpolation_data.camera_teleport_list.push_back(p_camera);
}
}
@@ -122,9 +103,9 @@ void VisualServerScene::camera_set_transform(RID p_camera, const Transform &p_tr
camera->transform = p_transform.orthonormalized();
if (camera->is_currently_interpolated()) {
if (_interpolation_data.interpolation_enabled && camera->interpolated) {
if (!camera->on_interpolate_transform_list) {
camera->scenario->_interpolation_data.camera_transform_update_list_curr->push_back(p_camera);
_interpolation_data.camera_transform_update_list_curr->push_back(p_camera);
camera->on_interpolate_transform_list = true;
}
@@ -302,7 +283,6 @@ void VisualServerScene::SpatialPartitioningScene_Octree::set_balance(float p_bal
VisualServerScene::Scenario::Scenario() {
debug = VS::SCENARIO_DEBUG_DISABLED;
_interpolation_data.interpolation_enabled = false;
bool use_bvh_or_octree = GLOBAL_GET("rendering/quality/spatial_partitioning/use_bvh");
@@ -470,30 +450,22 @@ RID VisualServerScene::scenario_create() {
return scenario_rid;
}
void VisualServerScene::scenario_set_physics_interpolation_enabled(RID p_scenario, bool p_enabled) {
Scenario *scenario = scenario_owner.get(p_scenario);
ERR_FAIL_COND(!scenario);
scenario->_interpolation_data.interpolation_enabled = p_enabled;
void VisualServerScene::set_physics_interpolation_enabled(bool p_enabled) {
_interpolation_data.interpolation_enabled = p_enabled;
}
void VisualServerScene::_scenario_tick(RID p_scenario) {
Scenario *scenario = scenario_owner.get(p_scenario);
ERR_FAIL_COND(!scenario);
if (scenario->is_physics_interpolation_enabled()) {
update_interpolation_tick(scenario->_interpolation_data, true);
void VisualServerScene::tick() {
if (_interpolation_data.interpolation_enabled) {
update_interpolation_tick(true);
}
}
void VisualServerScene::_scenario_pre_draw(RID p_scenario, bool p_will_draw) {
Scenario *scenario = scenario_owner.get(p_scenario);
ERR_FAIL_COND(!scenario);
void VisualServerScene::pre_draw(bool p_will_draw) {
// even when running and not drawing scenes, we still need to clear intermediate per frame
// interpolation data .. hence the p_will_draw flag (so we can reduce the processing if the frame
// will not be drawn)
if (scenario->is_physics_interpolation_enabled()) {
update_interpolation_frame(scenario->_interpolation_data, p_will_draw);
if (_interpolation_data.interpolation_enabled) {
update_interpolation_frame(p_will_draw);
}
}
@@ -730,7 +702,7 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario) {
}
// remove any interpolation data associated with the instance in this scenario
instance->scenario->_interpolation_data.notify_free_instance(p_instance, *instance);
_interpolation_data.notify_free_instance(p_instance, *instance);
switch (instance->base_type) {
case VS::INSTANCE_LIGHT: {
@@ -801,8 +773,8 @@ void VisualServerScene::instance_reset_physics_interpolation(RID p_instance) {
Instance *instance = instance_owner.get(p_instance);
ERR_FAIL_COND(!instance);
if (instance->is_currently_interpolated()) {
instance->scenario->_interpolation_data.instance_teleport_list.push_back(p_instance);
if (_interpolation_data.interpolation_enabled && instance->interpolated) {
_interpolation_data.instance_teleport_list.push_back(p_instance);
}
}
@@ -816,19 +788,11 @@ void VisualServerScene::instance_set_transform(RID p_instance, const Transform &
Instance *instance = instance_owner.get(p_instance);
ERR_FAIL_COND(!instance);
if (!instance->is_currently_interpolated() || !instance->scenario) {
if (!(_interpolation_data.interpolation_enabled && instance->interpolated) || !instance->scenario) {
if (instance->transform == p_transform) {
return; //must be checked to avoid worst evil
}
#ifdef DEV_ENABLED
// If we are interpolated but without a scenario, unsure whether
// this should be supported...
if (instance->is_currently_interpolated()) {
WARN_PRINT_ONCE("Instance interpolated without a scenario.");
}
#endif
#ifdef DEBUG_ENABLED
for (int i = 0; i < 4; i++) {
@@ -883,23 +847,23 @@ void VisualServerScene::instance_set_transform(RID p_instance, const Transform &
instance->transform_checksum_curr = new_checksum;
if (!instance->on_interpolate_transform_list) {
instance->scenario->_interpolation_data.instance_transform_update_list_curr->push_back(p_instance);
_interpolation_data.instance_transform_update_list_curr->push_back(p_instance);
instance->on_interpolate_transform_list = true;
} else {
DEV_ASSERT(instance->scenario->_interpolation_data.instance_transform_update_list_curr->size());
DEV_ASSERT(_interpolation_data.instance_transform_update_list_curr->size());
}
if (!instance->on_interpolate_list) {
instance->scenario->_interpolation_data.instance_interpolate_update_list.push_back(p_instance);
_interpolation_data.instance_interpolate_update_list.push_back(p_instance);
instance->on_interpolate_list = true;
} else {
DEV_ASSERT(instance->scenario->_interpolation_data.instance_interpolate_update_list.size());
DEV_ASSERT(_interpolation_data.instance_interpolate_update_list.size());
}
_instance_queue_update(instance, true);
}
void VisualServerScene::Scenario::InterpolationData::notify_free_camera(RID p_rid, Camera &r_camera) {
void VisualServerScene::InterpolationData::notify_free_camera(RID p_rid, Camera &r_camera) {
r_camera.on_interpolate_transform_list = false;
if (!interpolation_enabled) {
@@ -912,7 +876,7 @@ void VisualServerScene::Scenario::InterpolationData::notify_free_camera(RID p_ri
camera_teleport_list.erase_multiple_unordered(p_rid);
}
void VisualServerScene::Scenario::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_transform_list = false;
@@ -927,15 +891,15 @@ void VisualServerScene::Scenario::InterpolationData::notify_free_instance(RID p_
instance_teleport_list.erase_multiple_unordered(p_rid);
}
void VisualServerScene::update_interpolation_tick(Scenario::InterpolationData &r_interpolation_data, bool p_process) {
void VisualServerScene::update_interpolation_tick(bool p_process) {
// update interpolation in storage
VSG::storage->update_interpolation_tick(p_process);
// detect any that were on the previous transform list that are no longer active,
// we should remove them from the interpolate list
for (unsigned int n = 0; n < r_interpolation_data.instance_transform_update_list_prev->size(); n++) {
const RID &rid = (*r_interpolation_data.instance_transform_update_list_prev)[n];
for (unsigned int n = 0; n < _interpolation_data.instance_transform_update_list_prev->size(); n++) {
const RID &rid = (*_interpolation_data.instance_transform_update_list_prev)[n];
Instance *instance = instance_owner.getornull(rid);
bool active = true;
@@ -960,15 +924,15 @@ void VisualServerScene::update_interpolation_tick(Scenario::InterpolationData &r
}
if (!active) {
r_interpolation_data.instance_interpolate_update_list.erase(rid);
_interpolation_data.instance_interpolate_update_list.erase(rid);
}
}
// and now for any in the transform list (being actively interpolated), keep the previous transform
// value up to date ready for the next tick
if (p_process) {
for (unsigned int n = 0; n < r_interpolation_data.instance_transform_update_list_curr->size(); n++) {
const RID &rid = (*r_interpolation_data.instance_transform_update_list_curr)[n];
for (unsigned int n = 0; n < _interpolation_data.instance_transform_update_list_curr->size(); n++) {
const RID &rid = (*_interpolation_data.instance_transform_update_list_curr)[n];
Instance *instance = instance_owner.getornull(rid);
if (instance) {
instance->transform_prev = instance->transform_curr;
@@ -980,15 +944,15 @@ void VisualServerScene::update_interpolation_tick(Scenario::InterpolationData &r
// 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(r_interpolation_data.instance_transform_update_list_curr, r_interpolation_data.instance_transform_update_list_prev);
SWAP(_interpolation_data.instance_transform_update_list_curr, _interpolation_data.instance_transform_update_list_prev);
// prepare for the next iteration
r_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 < r_interpolation_data.camera_transform_update_list_prev->size(); n++) {
const RID &rid = (*r_interpolation_data.camera_transform_update_list_prev)[n];
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)
@@ -998,8 +962,8 @@ void VisualServerScene::update_interpolation_tick(Scenario::InterpolationData &r
}
// cameras , swap any current with previous
for (unsigned int n = 0; n < r_interpolation_data.camera_transform_update_list_curr->size(); n++) {
const RID &rid = (*r_interpolation_data.camera_transform_update_list_curr)[n];
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;
@@ -1009,19 +973,19 @@ void VisualServerScene::update_interpolation_tick(Scenario::InterpolationData &r
// 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(r_interpolation_data.camera_transform_update_list_curr, r_interpolation_data.camera_transform_update_list_prev);
SWAP(_interpolation_data.camera_transform_update_list_curr, _interpolation_data.camera_transform_update_list_prev);
// prepare for the next iteration
r_interpolation_data.camera_transform_update_list_curr->clear();
_interpolation_data.camera_transform_update_list_curr->clear();
}
void VisualServerScene::update_interpolation_frame(Scenario::InterpolationData &r_interpolation_data, bool p_process) {
void VisualServerScene::update_interpolation_frame(bool p_process) {
// update interpolation in storage
VSG::storage->update_interpolation_frame(p_process);
// teleported instances
for (unsigned int n = 0; n < r_interpolation_data.instance_teleport_list.size(); n++) {
const RID &rid = r_interpolation_data.instance_teleport_list[n];
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;
@@ -1029,24 +993,24 @@ void VisualServerScene::update_interpolation_frame(Scenario::InterpolationData &
}
}
r_interpolation_data.instance_teleport_list.clear();
_interpolation_data.instance_teleport_list.clear();
// camera teleports
for (unsigned int n = 0; n < r_interpolation_data.camera_teleport_list.size(); n++) {
const RID &rid = r_interpolation_data.camera_teleport_list[n];
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;
}
}
r_interpolation_data.camera_teleport_list.clear();
_interpolation_data.camera_teleport_list.clear();
if (p_process) {
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
for (unsigned int i = 0; i < r_interpolation_data.instance_interpolate_update_list.size(); i++) {
const RID &rid = r_interpolation_data.instance_interpolate_update_list[i];
for (unsigned int i = 0; i < _interpolation_data.instance_interpolate_update_list.size(); i++) {
const RID &rid = _interpolation_data.instance_interpolate_update_list[i];
Instance *instance = instance_owner.getornull(rid);
if (instance) {
TransformInterpolator::interpolate_transform_via_method(instance->transform_prev, instance->transform_curr, instance->transform, f, instance->interpolation_method);
@@ -2803,8 +2767,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario, Size2 p_view
} break;
}
// This getter allows optional fixed timestep interpolation for the camera.
Transform camera_transform = camera->get_transform();
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);
@@ -4466,10 +4429,7 @@ void VisualServerScene::update_dirty_instances() {
bool VisualServerScene::free(RID p_rid) {
if (camera_owner.owns(p_rid)) {
Camera *camera = camera_owner.get(p_rid);
if (camera->scenario) {
camera->scenario->_interpolation_data.notify_free_camera(p_rid, *camera);
}
_interpolation_data.notify_free_camera(p_rid, *camera);
camera_owner.free(p_rid);
memdelete(camera);
@@ -4490,15 +4450,7 @@ bool VisualServerScene::free(RID p_rid) {
update_dirty_instances();
Instance *instance = instance_owner.get(p_rid);
if (instance->scenario) {
instance->scenario->_interpolation_data.notify_free_instance(p_rid, *instance);
} else {
if (instance->on_interpolate_list || instance->on_interpolate_transform_list) {
// These flags should be set to false when removing the scenario.
WARN_PRINT_ONCE("Instance delete without scenario and on interpolate lists.");
}
}
_interpolation_data.notify_free_instance(p_rid, *instance);
instance_set_use_lightmap(p_rid, RID(), RID(), -1, Rect2(0, 0, 1, 1));
instance_set_scenario(p_rid, RID());