Fixed Timestep Interpolation (2D)
Adds fixed timestep interpolation to the rendering server (2D only). Switchable on and off with a project setting (default is off). Co-authored-by: lawnjelly <lawnjelly@gmail.com>
This commit is contained in:
parent
fe01776f05
commit
2ed2ccc2d8
39 changed files with 1040 additions and 75 deletions
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/math/geometry_2d.h"
|
||||
#include "core/math/transform_interpolator.h"
|
||||
#include "renderer_viewport.h"
|
||||
#include "rendering_server_default.h"
|
||||
#include "rendering_server_globals.h"
|
||||
|
|
@ -81,7 +82,7 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2
|
|||
if (r_items) {
|
||||
r_items[r_index] = child_items[i];
|
||||
child_items[i]->ysort_xform = p_transform;
|
||||
child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform.columns[2]);
|
||||
child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform_curr.columns[2]);
|
||||
child_items[i]->material_owner = child_items[i]->use_parent_material ? p_material_owner : nullptr;
|
||||
child_items[i]->ysort_modulate = p_modulate;
|
||||
child_items[i]->ysort_index = r_index;
|
||||
|
|
@ -98,7 +99,7 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2
|
|||
r_index++;
|
||||
|
||||
if (child_items[i]->sort_y) {
|
||||
_collect_ysort_children(child_items[i], p_transform * child_items[i]->xform, child_items[i]->use_parent_material ? p_material_owner : child_items[i], p_modulate * child_items[i]->modulate, r_items, r_index, abs_z);
|
||||
_collect_ysort_children(child_items[i], p_transform * child_items[i]->xform_curr, child_items[i]->use_parent_material ? p_material_owner : child_items[i], p_modulate * child_items[i]->modulate, r_items, r_index, abs_z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -244,7 +245,14 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
|
|||
}
|
||||
}
|
||||
|
||||
Transform2D xform = ci->xform;
|
||||
Transform2D final_xform;
|
||||
if (!_interpolation_data.interpolation_enabled || !ci->interpolated) {
|
||||
final_xform = ci->xform_curr;
|
||||
} else {
|
||||
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
|
||||
TransformInterpolator::interpolate_transform_2d(ci->xform_prev, ci->xform_curr, final_xform, f);
|
||||
}
|
||||
|
||||
Transform2D parent_xform = p_parent_xform;
|
||||
|
||||
Point2 repeat_size = p_repeat_size;
|
||||
|
|
@ -258,19 +266,19 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
|
|||
ci->repeat_times = repeat_times;
|
||||
|
||||
if (repeat_size.x || repeat_size.y) {
|
||||
rect.size += repeat_size * repeat_times / ci->xform.get_scale();
|
||||
rect.size += repeat_size * repeat_times / final_xform.get_scale();
|
||||
rect.position -= repeat_size * (repeat_times / 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (snapping_2d_transforms_to_pixel) {
|
||||
xform.columns[2] = xform.columns[2].round();
|
||||
final_xform.columns[2] = final_xform.columns[2].round();
|
||||
parent_xform.columns[2] = parent_xform.columns[2].round();
|
||||
}
|
||||
|
||||
xform = parent_xform * xform;
|
||||
final_xform = parent_xform * final_xform;
|
||||
|
||||
Rect2 global_rect = xform.xform(rect);
|
||||
Rect2 global_rect = final_xform.xform(rect);
|
||||
global_rect.position += p_clip_rect.position;
|
||||
|
||||
if (ci->use_parent_material && p_material_owner) {
|
||||
|
|
@ -324,7 +332,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
|
|||
child_item_count = ci->ysort_children_count + 1;
|
||||
child_items = (Item **)alloca(child_item_count * sizeof(Item *));
|
||||
|
||||
ci->ysort_xform = ci->xform.affine_inverse();
|
||||
ci->ysort_xform = final_xform.affine_inverse();
|
||||
ci->ysort_pos = Vector2();
|
||||
ci->ysort_modulate = Color(1, 1, 1, 1);
|
||||
ci->ysort_index = 0;
|
||||
|
|
@ -337,7 +345,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
|
|||
sorter.sort(child_items, child_item_count);
|
||||
|
||||
for (i = 0; i < child_item_count; i++) {
|
||||
_cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, p_canvas_cull_mask, repeat_size, repeat_times);
|
||||
_cull_canvas_item(child_items[i], final_xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, p_canvas_cull_mask, repeat_size, repeat_times);
|
||||
}
|
||||
} else {
|
||||
RendererCanvasRender::Item *canvas_group_from = nullptr;
|
||||
|
|
@ -347,7 +355,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
|
|||
canvas_group_from = r_z_last_list[zidx];
|
||||
}
|
||||
|
||||
_attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
|
||||
_attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, final_xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
|
||||
}
|
||||
} else {
|
||||
RendererCanvasRender::Item *canvas_group_from = nullptr;
|
||||
|
|
@ -361,14 +369,14 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
|
|||
if (!child_items[i]->behind && !use_canvas_group) {
|
||||
continue;
|
||||
}
|
||||
_cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times);
|
||||
_cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times);
|
||||
}
|
||||
_attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
|
||||
_attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, final_xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
|
||||
for (int i = 0; i < child_item_count; i++) {
|
||||
if (child_items[i]->behind || use_canvas_group) {
|
||||
continue;
|
||||
}
|
||||
_cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times);
|
||||
_cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -512,7 +520,16 @@ void RendererCanvasCull::canvas_item_set_transform(RID p_item, const Transform2D
|
|||
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
|
||||
ERR_FAIL_NULL(canvas_item);
|
||||
|
||||
canvas_item->xform = p_transform;
|
||||
if (_interpolation_data.interpolation_enabled && canvas_item->interpolated) {
|
||||
if (!canvas_item->on_interpolate_transform_list) {
|
||||
_interpolation_data.canvas_item_transform_update_list_curr->push_back(p_item);
|
||||
canvas_item->on_interpolate_transform_list = true;
|
||||
} else {
|
||||
DEV_ASSERT(_interpolation_data.canvas_item_transform_update_list_curr->size() > 0);
|
||||
}
|
||||
}
|
||||
|
||||
canvas_item->xform_curr = p_transform;
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_item_set_visibility_layer(RID p_item, uint32_t p_visibility_layer) {
|
||||
|
|
@ -1622,6 +1639,26 @@ bool RendererCanvasCull::canvas_item_get_debug_redraw() const {
|
|||
return debug_redraw;
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_item_set_interpolated(RID p_item, bool p_interpolated) {
|
||||
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
|
||||
ERR_FAIL_NULL(canvas_item);
|
||||
canvas_item->interpolated = p_interpolated;
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_item_reset_physics_interpolation(RID p_item) {
|
||||
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
|
||||
ERR_FAIL_NULL(canvas_item);
|
||||
canvas_item->xform_prev = canvas_item->xform_curr;
|
||||
}
|
||||
|
||||
// Useful especially for origin shifting.
|
||||
void RendererCanvasCull::canvas_item_transform_physics_interpolation(RID p_item, const Transform2D &p_transform) {
|
||||
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
|
||||
ERR_FAIL_NULL(canvas_item);
|
||||
canvas_item->xform_prev = p_transform * canvas_item->xform_prev;
|
||||
canvas_item->xform_curr = p_transform * canvas_item->xform_curr;
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) {
|
||||
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
|
||||
ERR_FAIL_NULL(canvas_item);
|
||||
|
|
@ -1720,7 +1757,16 @@ void RendererCanvasCull::canvas_light_set_transform(RID p_light, const Transform
|
|||
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
|
||||
ERR_FAIL_NULL(clight);
|
||||
|
||||
clight->xform = p_transform;
|
||||
if (_interpolation_data.interpolation_enabled && clight->interpolated) {
|
||||
if (!clight->on_interpolate_transform_list) {
|
||||
_interpolation_data.canvas_light_transform_update_list_curr->push_back(p_light);
|
||||
clight->on_interpolate_transform_list = true;
|
||||
} else {
|
||||
DEV_ASSERT(_interpolation_data.canvas_light_transform_update_list_curr->size() > 0);
|
||||
}
|
||||
}
|
||||
|
||||
clight->xform_curr = p_transform;
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_light_set_texture(RID p_light, RID p_texture) {
|
||||
|
|
@ -1839,6 +1885,25 @@ void RendererCanvasCull::canvas_light_set_shadow_smooth(RID p_light, float p_smo
|
|||
clight->shadow_smooth = p_smooth;
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_light_set_interpolated(RID p_light, bool p_interpolated) {
|
||||
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
|
||||
ERR_FAIL_NULL(clight);
|
||||
clight->interpolated = p_interpolated;
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_light_reset_physics_interpolation(RID p_light) {
|
||||
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
|
||||
ERR_FAIL_NULL(clight);
|
||||
clight->xform_prev = clight->xform_curr;
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_light_transform_physics_interpolation(RID p_light, const Transform2D &p_transform) {
|
||||
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
|
||||
ERR_FAIL_NULL(clight);
|
||||
clight->xform_prev = p_transform * clight->xform_prev;
|
||||
clight->xform_curr = p_transform * clight->xform_curr;
|
||||
}
|
||||
|
||||
RID RendererCanvasCull::canvas_light_occluder_allocate() {
|
||||
return canvas_light_occluder_owner.allocate_rid();
|
||||
}
|
||||
|
|
@ -1911,7 +1976,16 @@ void RendererCanvasCull::canvas_light_occluder_set_transform(RID p_occluder, con
|
|||
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
|
||||
ERR_FAIL_NULL(occluder);
|
||||
|
||||
occluder->xform = p_xform;
|
||||
if (_interpolation_data.interpolation_enabled && occluder->interpolated) {
|
||||
if (!occluder->on_interpolate_transform_list) {
|
||||
_interpolation_data.canvas_light_occluder_transform_update_list_curr->push_back(p_occluder);
|
||||
occluder->on_interpolate_transform_list = true;
|
||||
} else {
|
||||
DEV_ASSERT(_interpolation_data.canvas_light_occluder_transform_update_list_curr->size() > 0);
|
||||
}
|
||||
}
|
||||
|
||||
occluder->xform_curr = p_xform;
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) {
|
||||
|
|
@ -1921,6 +1995,25 @@ void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, in
|
|||
occluder->light_mask = p_mask;
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated) {
|
||||
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
|
||||
ERR_FAIL_NULL(occluder);
|
||||
occluder->interpolated = p_interpolated;
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_light_occluder_reset_physics_interpolation(RID p_occluder) {
|
||||
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
|
||||
ERR_FAIL_NULL(occluder);
|
||||
occluder->xform_prev = occluder->xform_curr;
|
||||
}
|
||||
|
||||
void RendererCanvasCull::canvas_light_occluder_transform_physics_interpolation(RID p_occluder, const Transform2D &p_transform) {
|
||||
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
|
||||
ERR_FAIL_NULL(occluder);
|
||||
occluder->xform_prev = p_transform * occluder->xform_prev;
|
||||
occluder->xform_curr = p_transform * occluder->xform_curr;
|
||||
}
|
||||
|
||||
RID RendererCanvasCull::canvas_occluder_polygon_allocate() {
|
||||
return canvas_light_occluder_polygon_owner.allocate_rid();
|
||||
}
|
||||
|
|
@ -2075,6 +2168,7 @@ bool RendererCanvasCull::free(RID p_rid) {
|
|||
} else if (canvas_item_owner.owns(p_rid)) {
|
||||
Item *canvas_item = canvas_item_owner.get_or_null(p_rid);
|
||||
ERR_FAIL_NULL_V(canvas_item, true);
|
||||
_interpolation_data.notify_free_canvas_item(p_rid, *canvas_item);
|
||||
|
||||
if (canvas_item->parent.is_valid()) {
|
||||
if (canvas_owner.owns(canvas_item->parent)) {
|
||||
|
|
@ -2114,6 +2208,7 @@ bool RendererCanvasCull::free(RID p_rid) {
|
|||
} else if (canvas_light_owner.owns(p_rid)) {
|
||||
RendererCanvasRender::Light *canvas_light = canvas_light_owner.get_or_null(p_rid);
|
||||
ERR_FAIL_NULL_V(canvas_light, true);
|
||||
_interpolation_data.notify_free_canvas_light(p_rid, *canvas_light);
|
||||
|
||||
if (canvas_light->canvas.is_valid()) {
|
||||
Canvas *canvas = canvas_owner.get_or_null(canvas_light->canvas);
|
||||
|
|
@ -2129,6 +2224,7 @@ bool RendererCanvasCull::free(RID p_rid) {
|
|||
} else if (canvas_light_occluder_owner.owns(p_rid)) {
|
||||
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_rid);
|
||||
ERR_FAIL_NULL_V(occluder, true);
|
||||
_interpolation_data.notify_free_canvas_light_occluder(p_rid, *occluder);
|
||||
|
||||
if (occluder->polygon.is_valid()) {
|
||||
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(occluder->polygon);
|
||||
|
|
@ -2186,6 +2282,81 @@ void RendererCanvasCull::finalize() {
|
|||
_free_rids(canvas_light_occluder_polygon_owner, "CanvasLightOccluderPolygon");
|
||||
}
|
||||
|
||||
void RendererCanvasCull::tick() {
|
||||
if (_interpolation_data.interpolation_enabled) {
|
||||
update_interpolation_tick(true);
|
||||
}
|
||||
}
|
||||
|
||||
void RendererCanvasCull::update_interpolation_tick(bool p_process) {
|
||||
#define GODOT_UPDATE_INTERPOLATION_TICK(m_list_prev, m_list_curr, m_type, m_owner_list) \
|
||||
/* Detect any that were on the previous transform list that are no longer active. */ \
|
||||
for (unsigned int n = 0; n < _interpolation_data.m_list_prev->size(); n++) { \
|
||||
const RID &rid = (*_interpolation_data.m_list_prev)[n]; \
|
||||
m_type *item = m_owner_list.get_or_null(rid); \
|
||||
/* no longer active? (either the instance deleted or no longer being transformed) */ \
|
||||
if (item && !item->on_interpolate_transform_list) { \
|
||||
item->xform_prev = item->xform_curr; \
|
||||
} \
|
||||
} \
|
||||
/* and now for any in the transform list (being actively interpolated), */ \
|
||||
/* keep the previous transform value up to date and ready for next tick */ \
|
||||
if (p_process) { \
|
||||
for (unsigned int n = 0; n < _interpolation_data.m_list_curr->size(); n++) { \
|
||||
const RID &rid = (*_interpolation_data.m_list_curr)[n]; \
|
||||
m_type *item = m_owner_list.get_or_null(rid); \
|
||||
if (item) { \
|
||||
item->xform_prev = item->xform_curr; \
|
||||
item->on_interpolate_transform_list = false; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
SWAP(_interpolation_data.m_list_curr, _interpolation_data.m_list_prev); \
|
||||
_interpolation_data.m_list_curr->clear();
|
||||
|
||||
GODOT_UPDATE_INTERPOLATION_TICK(canvas_item_transform_update_list_prev, canvas_item_transform_update_list_curr, Item, canvas_item_owner);
|
||||
GODOT_UPDATE_INTERPOLATION_TICK(canvas_light_transform_update_list_prev, canvas_light_transform_update_list_curr, RendererCanvasRender::Light, canvas_light_owner);
|
||||
GODOT_UPDATE_INTERPOLATION_TICK(canvas_light_occluder_transform_update_list_prev, canvas_light_occluder_transform_update_list_curr, RendererCanvasRender::LightOccluderInstance, canvas_light_occluder_owner);
|
||||
|
||||
#undef GODOT_UPDATE_INTERPOLATION_TICK
|
||||
}
|
||||
|
||||
void RendererCanvasCull::InterpolationData::notify_free_canvas_item(RID p_rid, RendererCanvasCull::Item &r_canvas_item) {
|
||||
r_canvas_item.on_interpolate_transform_list = false;
|
||||
|
||||
if (!interpolation_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the instance was on any of the lists, remove.
|
||||
canvas_item_transform_update_list_curr->erase_multiple_unordered(p_rid);
|
||||
canvas_item_transform_update_list_prev->erase_multiple_unordered(p_rid);
|
||||
}
|
||||
|
||||
void RendererCanvasCull::InterpolationData::notify_free_canvas_light(RID p_rid, RendererCanvasRender::Light &r_canvas_light) {
|
||||
r_canvas_light.on_interpolate_transform_list = false;
|
||||
|
||||
if (!interpolation_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the instance was on any of the lists, remove.
|
||||
canvas_light_transform_update_list_curr->erase_multiple_unordered(p_rid);
|
||||
canvas_light_transform_update_list_prev->erase_multiple_unordered(p_rid);
|
||||
}
|
||||
|
||||
void RendererCanvasCull::InterpolationData::notify_free_canvas_light_occluder(RID p_rid, RendererCanvasRender::LightOccluderInstance &r_canvas_light_occluder) {
|
||||
r_canvas_light_occluder.on_interpolate_transform_list = false;
|
||||
|
||||
if (!interpolation_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the instance was on any of the lists, remove.
|
||||
canvas_light_occluder_transform_update_list_curr->erase_multiple_unordered(p_rid);
|
||||
canvas_light_occluder_transform_update_list_prev->erase_multiple_unordered(p_rid);
|
||||
}
|
||||
|
||||
RendererCanvasCull::RendererCanvasCull() {
|
||||
z_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));
|
||||
z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));
|
||||
|
|
|
|||
|
|
@ -271,6 +271,10 @@ public:
|
|||
void canvas_item_set_debug_redraw(bool p_enabled);
|
||||
bool canvas_item_get_debug_redraw() const;
|
||||
|
||||
void canvas_item_set_interpolated(RID p_item, bool p_interpolated);
|
||||
void canvas_item_reset_physics_interpolation(RID p_item);
|
||||
void canvas_item_transform_physics_interpolation(RID p_item, const Transform2D &p_transform);
|
||||
|
||||
RID canvas_light_allocate();
|
||||
void canvas_light_initialize(RID p_rid);
|
||||
|
||||
|
|
@ -297,6 +301,10 @@ public:
|
|||
void canvas_light_set_shadow_color(RID p_light, const Color &p_color);
|
||||
void canvas_light_set_shadow_smooth(RID p_light, float p_smooth);
|
||||
|
||||
void canvas_light_set_interpolated(RID p_light, bool p_interpolated);
|
||||
void canvas_light_reset_physics_interpolation(RID p_light);
|
||||
void canvas_light_transform_physics_interpolation(RID p_light, const Transform2D &p_transform);
|
||||
|
||||
RID canvas_light_occluder_allocate();
|
||||
void canvas_light_occluder_initialize(RID p_rid);
|
||||
|
||||
|
|
@ -307,6 +315,10 @@ public:
|
|||
void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform);
|
||||
void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask);
|
||||
|
||||
void canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated);
|
||||
void canvas_light_occluder_reset_physics_interpolation(RID p_occluder);
|
||||
void canvas_light_occluder_transform_physics_interpolation(RID p_occluder, const Transform2D &p_transform);
|
||||
|
||||
RID canvas_occluder_polygon_allocate();
|
||||
void canvas_occluder_polygon_initialize(RID p_rid);
|
||||
|
||||
|
|
@ -336,6 +348,32 @@ public:
|
|||
|
||||
void finalize();
|
||||
|
||||
/* INTERPOLATION */
|
||||
|
||||
void tick();
|
||||
void update_interpolation_tick(bool p_process = true);
|
||||
void set_physics_interpolation_enabled(bool p_enabled) { _interpolation_data.interpolation_enabled = p_enabled; }
|
||||
|
||||
struct InterpolationData {
|
||||
void notify_free_canvas_item(RID p_rid, RendererCanvasCull::Item &r_canvas_item);
|
||||
void notify_free_canvas_light(RID p_rid, RendererCanvasRender::Light &r_canvas_light);
|
||||
void notify_free_canvas_light_occluder(RID p_rid, RendererCanvasRender::LightOccluderInstance &r_canvas_light_occluder);
|
||||
|
||||
LocalVector<RID> canvas_item_transform_update_lists[2];
|
||||
LocalVector<RID> *canvas_item_transform_update_list_curr = &canvas_item_transform_update_lists[0];
|
||||
LocalVector<RID> *canvas_item_transform_update_list_prev = &canvas_item_transform_update_lists[1];
|
||||
|
||||
LocalVector<RID> canvas_light_transform_update_lists[2];
|
||||
LocalVector<RID> *canvas_light_transform_update_list_curr = &canvas_light_transform_update_lists[0];
|
||||
LocalVector<RID> *canvas_light_transform_update_list_prev = &canvas_light_transform_update_lists[1];
|
||||
|
||||
LocalVector<RID> canvas_light_occluder_transform_update_lists[2];
|
||||
LocalVector<RID> *canvas_light_occluder_transform_update_list_curr = &canvas_light_occluder_transform_update_lists[0];
|
||||
LocalVector<RID> *canvas_light_occluder_transform_update_list_prev = &canvas_light_occluder_transform_update_lists[1];
|
||||
|
||||
bool interpolation_enabled = false;
|
||||
} _interpolation_data;
|
||||
|
||||
RendererCanvasCull();
|
||||
~RendererCanvasCull();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -51,9 +51,12 @@ public:
|
|||
};
|
||||
|
||||
struct Light {
|
||||
bool enabled;
|
||||
bool enabled : 1;
|
||||
bool on_interpolate_transform_list : 1;
|
||||
bool interpolated : 1;
|
||||
Color color;
|
||||
Transform2D xform;
|
||||
Transform2D xform_curr;
|
||||
Transform2D xform_prev;
|
||||
float height;
|
||||
float energy;
|
||||
float scale;
|
||||
|
|
@ -97,6 +100,8 @@ public:
|
|||
Light() {
|
||||
version = 0;
|
||||
enabled = true;
|
||||
on_interpolate_transform_list = false;
|
||||
interpolated = true;
|
||||
color = Color(1, 1, 1);
|
||||
shadow_color = Color(0, 0, 0, 0);
|
||||
height = 0;
|
||||
|
|
@ -307,11 +312,17 @@ public:
|
|||
Rect2 rect;
|
||||
};
|
||||
|
||||
Transform2D xform;
|
||||
bool clip;
|
||||
bool visible;
|
||||
bool behind;
|
||||
bool update_when_visible;
|
||||
// For interpolation we store the current local xform,
|
||||
// and the previous xform from the previous tick.
|
||||
Transform2D xform_curr;
|
||||
Transform2D xform_prev;
|
||||
|
||||
bool clip : 1;
|
||||
bool visible : 1;
|
||||
bool behind : 1;
|
||||
bool update_when_visible : 1;
|
||||
bool on_interpolate_transform_list : 1;
|
||||
bool interpolated : 1;
|
||||
|
||||
struct CanvasGroup {
|
||||
RS::CanvasGroupMode mode;
|
||||
|
|
@ -472,6 +483,8 @@ public:
|
|||
texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
|
||||
texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
|
||||
repeat_source = false;
|
||||
on_interpolate_transform_list = false;
|
||||
interpolated = true;
|
||||
}
|
||||
virtual ~Item() {
|
||||
clear();
|
||||
|
|
@ -487,12 +500,15 @@ public:
|
|||
virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used, RenderingMethod::RenderInfo *r_render_info = nullptr) = 0;
|
||||
|
||||
struct LightOccluderInstance {
|
||||
bool enabled;
|
||||
bool enabled : 1;
|
||||
bool on_interpolate_transform_list : 1;
|
||||
bool interpolated : 1;
|
||||
RID canvas;
|
||||
RID polygon;
|
||||
RID occluder;
|
||||
Rect2 aabb_cache;
|
||||
Transform2D xform;
|
||||
Transform2D xform_curr;
|
||||
Transform2D xform_prev;
|
||||
Transform2D xform_cache;
|
||||
int light_mask;
|
||||
bool sdf_collision;
|
||||
|
|
@ -502,6 +518,8 @@ public:
|
|||
|
||||
LightOccluderInstance() {
|
||||
enabled = true;
|
||||
on_interpolate_transform_list = false;
|
||||
interpolated = false;
|
||||
sdf_collision = false;
|
||||
next = nullptr;
|
||||
light_mask = 1;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "core/math/geometry_2d.h"
|
||||
#include "core/math/math_defs.h"
|
||||
#include "core/math/math_funcs.h"
|
||||
#include "core/math/transform_interpolator.h"
|
||||
#include "renderer_compositor_rd.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
|
||||
#include "servers/rendering/renderer_rd/storage_rd/particles_storage.h"
|
||||
|
|
@ -427,7 +428,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
|
|||
Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform;
|
||||
|
||||
if (p_offset.x || p_offset.y) {
|
||||
base_transform *= Transform2D(0, p_offset / p_item->xform.get_scale());
|
||||
base_transform *= Transform2D(0, p_offset / p_item->xform_curr.get_scale()); // TODO: Interpolate or explain why not needed.
|
||||
}
|
||||
|
||||
Transform2D draw_transform;
|
||||
|
|
@ -1366,7 +1367,15 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
|
|||
ERR_CONTINUE(!clight);
|
||||
}
|
||||
|
||||
Vector2 canvas_light_pos = p_canvas_transform.xform(l->xform.get_origin()); //convert light position to canvas coordinates, as all computation is done in canvas coords to avoid precision loss
|
||||
Transform2D final_xform;
|
||||
if (!RSG::canvas->_interpolation_data.interpolation_enabled || !l->interpolated) {
|
||||
final_xform = l->xform_curr;
|
||||
} else {
|
||||
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
|
||||
TransformInterpolator::interpolate_transform_2d(l->xform_prev, l->xform_curr, final_xform, f);
|
||||
}
|
||||
// Convert light position to canvas coordinates, as all computation is done in canvas coordinates to avoid precision loss.
|
||||
Vector2 canvas_light_pos = p_canvas_transform.xform(final_xform.get_origin());
|
||||
state.light_uniforms[index].position[0] = canvas_light_pos.x;
|
||||
state.light_uniforms[index].position[1] = canvas_light_pos.y;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "renderer_viewport.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/math/transform_interpolator.h"
|
||||
#include "core/object/worker_thread_pool.h"
|
||||
#include "renderer_canvas_cull.h"
|
||||
#include "renderer_scene_cull.h"
|
||||
|
|
@ -339,7 +340,14 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
|
|||
if (!F->enabled) {
|
||||
continue;
|
||||
}
|
||||
F->xform_cache = xf * F->xform;
|
||||
|
||||
if (!RSG::canvas->_interpolation_data.interpolation_enabled || !F->interpolated) {
|
||||
F->xform_cache = xf * F->xform_curr;
|
||||
} else {
|
||||
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
|
||||
TransformInterpolator::interpolate_transform_2d(F->xform_prev, F->xform_curr, F->xform_cache, f);
|
||||
F->xform_cache = xf * F->xform_cache;
|
||||
}
|
||||
|
||||
if (sdf_rect.intersects_transformed(F->xform_cache, F->aabb_cache)) {
|
||||
F->next = occluders;
|
||||
|
|
@ -378,7 +386,14 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
|
|||
|
||||
Vector2 offset = tsize / 2.0;
|
||||
cl->rect_cache = Rect2(-offset + cl->texture_offset, tsize);
|
||||
cl->xform_cache = xf * cl->xform;
|
||||
|
||||
if (!RSG::canvas->_interpolation_data.interpolation_enabled || !cl->interpolated) {
|
||||
cl->xform_cache = xf * cl->xform_curr;
|
||||
} else {
|
||||
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
|
||||
TransformInterpolator::interpolate_transform_2d(cl->xform_prev, cl->xform_curr, cl->xform_cache, f);
|
||||
cl->xform_cache = xf * cl->xform_cache;
|
||||
}
|
||||
|
||||
if (clip_rect.intersects_transformed(cl->xform_cache, cl->rect_cache)) {
|
||||
cl->filter_next_ptr = lights;
|
||||
|
|
@ -386,7 +401,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
|
|||
Transform2D scale;
|
||||
scale.scale(cl->rect_cache.size);
|
||||
scale.columns[2] = cl->rect_cache.position;
|
||||
cl->light_shader_xform = xf * cl->xform * scale;
|
||||
cl->light_shader_xform = cl->xform_cache * scale;
|
||||
if (cl->use_shadow) {
|
||||
cl->shadows_next_ptr = lights_with_shadow;
|
||||
if (lights_with_shadow == nullptr) {
|
||||
|
|
@ -406,7 +421,13 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
|
|||
if (cl->enabled) {
|
||||
cl->filter_next_ptr = directional_lights;
|
||||
directional_lights = cl;
|
||||
cl->xform_cache = xf * cl->xform;
|
||||
if (!RSG::canvas->_interpolation_data.interpolation_enabled || !cl->interpolated) {
|
||||
cl->xform_cache = xf * cl->xform_curr;
|
||||
} else {
|
||||
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
|
||||
TransformInterpolator::interpolate_transform_2d(cl->xform_prev, cl->xform_curr, cl->xform_cache, f);
|
||||
cl->xform_cache = xf * cl->xform_cache;
|
||||
}
|
||||
cl->xform_cache.columns[2] = Vector2(); //translation is pointless
|
||||
if (cl->use_shadow) {
|
||||
cl->shadows_next_ptr = directional_lights_with_shadow;
|
||||
|
|
@ -441,7 +462,13 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
|
|||
if (!F->enabled) {
|
||||
continue;
|
||||
}
|
||||
F->xform_cache = xf * F->xform;
|
||||
if (!RSG::canvas->_interpolation_data.interpolation_enabled || !F->interpolated) {
|
||||
F->xform_cache = xf * F->xform_curr;
|
||||
} else {
|
||||
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
|
||||
TransformInterpolator::interpolate_transform_2d(F->xform_prev, F->xform_curr, F->xform_cache, f);
|
||||
F->xform_cache = xf * F->xform_cache;
|
||||
}
|
||||
if (shadow_rect.intersects_transformed(F->xform_cache, F->aabb_cache)) {
|
||||
F->next = occluders;
|
||||
occluders = F;
|
||||
|
|
@ -521,7 +548,13 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
|
|||
if (!F->enabled) {
|
||||
continue;
|
||||
}
|
||||
F->xform_cache = xf * F->xform;
|
||||
if (!RSG::canvas->_interpolation_data.interpolation_enabled || !F->interpolated) {
|
||||
F->xform_cache = xf * F->xform_curr;
|
||||
} else {
|
||||
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
|
||||
TransformInterpolator::interpolate_transform_2d(F->xform_prev, F->xform_curr, F->xform_cache, f);
|
||||
F->xform_cache = xf * F->xform_cache;
|
||||
}
|
||||
Transform2D localizer = F->xform_cache.affine_inverse();
|
||||
|
||||
for (int j = 0; j < point_count; j++) {
|
||||
|
|
|
|||
|
|
@ -370,6 +370,16 @@ void RenderingServerDefault::_thread_loop() {
|
|||
_finish();
|
||||
}
|
||||
|
||||
/* INTERPOLATION */
|
||||
|
||||
void RenderingServerDefault::tick() {
|
||||
RSG::canvas->tick();
|
||||
}
|
||||
|
||||
void RenderingServerDefault::set_physics_interpolation_enabled(bool p_enabled) {
|
||||
RSG::canvas->set_physics_interpolation_enabled(p_enabled);
|
||||
}
|
||||
|
||||
/* EVENT QUEUING */
|
||||
|
||||
void RenderingServerDefault::sync() {
|
||||
|
|
|
|||
|
|
@ -926,6 +926,10 @@ public:
|
|||
FUNC1(canvas_item_set_debug_redraw, bool)
|
||||
FUNC0RC(bool, canvas_item_get_debug_redraw)
|
||||
|
||||
FUNC2(canvas_item_set_interpolated, RID, bool)
|
||||
FUNC1(canvas_item_reset_physics_interpolation, RID)
|
||||
FUNC2(canvas_item_transform_physics_interpolation, RID, const Transform2D &)
|
||||
|
||||
FUNCRIDSPLIT(canvas_light)
|
||||
|
||||
FUNC2(canvas_light_set_mode, RID, CanvasLightMode)
|
||||
|
|
@ -952,6 +956,10 @@ public:
|
|||
FUNC2(canvas_light_set_shadow_color, RID, const Color &)
|
||||
FUNC2(canvas_light_set_shadow_smooth, RID, float)
|
||||
|
||||
FUNC2(canvas_light_set_interpolated, RID, bool)
|
||||
FUNC1(canvas_light_reset_physics_interpolation, RID)
|
||||
FUNC2(canvas_light_transform_physics_interpolation, RID, const Transform2D &)
|
||||
|
||||
FUNCRIDSPLIT(canvas_light_occluder)
|
||||
FUNC2(canvas_light_occluder_attach_to_canvas, RID, RID)
|
||||
FUNC2(canvas_light_occluder_set_enabled, RID, bool)
|
||||
|
|
@ -960,6 +968,10 @@ public:
|
|||
FUNC2(canvas_light_occluder_set_transform, RID, const Transform2D &)
|
||||
FUNC2(canvas_light_occluder_set_light_mask, RID, int)
|
||||
|
||||
FUNC2(canvas_light_occluder_set_interpolated, RID, bool)
|
||||
FUNC1(canvas_light_occluder_reset_physics_interpolation, RID)
|
||||
FUNC2(canvas_light_occluder_transform_physics_interpolation, RID, const Transform2D &)
|
||||
|
||||
FUNCRIDSPLIT(canvas_occluder_polygon)
|
||||
FUNC3(canvas_occluder_polygon_set_shape, RID, const Vector<Vector2> &, bool)
|
||||
|
||||
|
|
@ -1021,6 +1033,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/* INTERPOLATION */
|
||||
|
||||
virtual void tick() override;
|
||||
virtual void set_physics_interpolation_enabled(bool p_enabled) override;
|
||||
|
||||
/* EVENT QUEUING */
|
||||
|
||||
virtual void request_frame_drawn_callback(const Callable &p_callable) override;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue