Skip to content

Commit

Permalink
Merge pull request godotengine#33 from lawnjelly/plus_interpolated_bo…
Browse files Browse the repository at this point in the history
…unds

Hierarchical 2D culling - use interpolated bound
  • Loading branch information
lawnjelly authored Apr 25, 2023
2 parents 5c9a4f1 + 27389b5 commit 881ac09
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 4 deletions.
8 changes: 8 additions & 0 deletions doc/classes/VisualServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,14 @@
Modulates all colors in the given canvas.
</description>
</method>
<method name="debug_canvas_item_get_local_bound">
<return type="Rect2" />
<argument index="0" name="item" type="RID" />
<description>
Returns the bounding rectangle for a canvas item and its descendants in local space, as calculated by the renderer. This bound is used internally for culling.
[b]Warning:[/b] This function is intended for debugging in the editor, and will pass through and return a zero [Rect2] in exported projects.
</description>
</method>
<method name="debug_canvas_item_get_rect">
<return type="Rect2" />
<argument index="0" name="item" type="RID" />
Expand Down
8 changes: 8 additions & 0 deletions servers/visual/rasterizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,13 @@ class RasterizerCanvas {
// in local space.
Rect2 local_bound;

// When using interpolation, the local bound for culling
// should be a combined bound of the previous and current.
// To keep this up to date, we need to keep track of the previous
// bound separately rather than just the combined bound.
Rect2 local_bound_prev;
uint32_t local_bound_last_update_tick;

private:
Rect2 calculate_polygon_bounds(const Item::CommandPolygon &p_polygon) const;
void precalculate_polygon_bone_bounds(const Item::CommandPolygon &p_polygon) const;
Expand Down Expand Up @@ -1229,6 +1236,7 @@ class RasterizerCanvas {
update_when_visible = false;
on_interpolate_transform_list = false;
interpolated = true;
local_bound_last_update_tick = 0;
}
virtual ~Item() {
clear();
Expand Down
44 changes: 44 additions & 0 deletions servers/visual/visual_server_canvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,37 @@ void VisualServerCanvas::_calculate_canvas_item_bound(Item *p_canvas_item, Rect2
}

_finalize_and_merge_local_bound_to_branch(ci, r_branch_bound);

// If we are interpolating, we want to modify the local_bound (combined)
// to include both the previous AND current bounds.
if (local_bound && _interpolation_data.interpolation_enabled && ci->interpolated) {
Rect2 bound_prev = ci->local_bound_prev;

// Keep track of the previously assigned exact bound for the next tick.
ci->local_bound_prev = ci->local_bound;

// The combined bound is the exact current bound merged with the previous exact bound.
ci->local_bound = ci->local_bound.merge(bound_prev);

// This can overflow, it's no problem, it is just rough to detect when items stop
// having local bounds updated, so we can set prev to curr.
ci->local_bound_last_update_tick = Engine::get_singleton()->get_physics_frames();

// Detect special case of overflow.
// This is omitted but included for reference.
// It is such a rare possibility, and even if it did occur
// so it should just result in slightly larger culling bounds
// probably for one tick (and no visual errors).
// Would occur once every 828.5 days at 60 ticks per second
// with uint32_t counter.
#if 0
if (!ci->local_bound_last_update_tick) {
// Prevents it being treated as non-dirty.
// Just has an increased delay of one tick in this very rare occurrence.
ci->local_bound_last_update_tick = 1;
}
#endif
}
}

void VisualServerCanvas::_finalize_and_merge_local_bound_to_branch(Item *p_canvas_item, Rect2 *r_branch_bound) {
Expand Down Expand Up @@ -426,6 +457,13 @@ void VisualServerCanvas::_render_canvas_item_cull_by_node(Item *p_canvas_item, c
// This should have been calculated as a pre-process.
DEV_ASSERT(!ci->bound_dirty);

// If we are interpolating, and the updates have stopped, we can reduce the local bound.
if (ci->local_bound_last_update_tick && (ci->local_bound_last_update_tick != Engine::get_singleton()->get_physics_frames())) {
// The combined bound is reduced to the last calculated exact bound.
ci->local_bound = ci->local_bound_prev;
ci->local_bound_last_update_tick = 0;
}

Rect2 rect = ci->get_rect();

Transform2D final_xform;
Expand Down Expand Up @@ -1432,6 +1470,12 @@ Rect2 VisualServerCanvas::_debug_canvas_item_get_rect(RID p_item) {
return canvas_item->get_rect();
}

Rect2 VisualServerCanvas::_debug_canvas_item_get_local_bound(RID p_item) {
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND_V(!canvas_item, Rect2());
return canvas_item->local_bound;
}

void VisualServerCanvas::canvas_item_set_skeleton_relative_xform(RID p_item, Transform2D p_relative_xform) {
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
Expand Down
1 change: 1 addition & 0 deletions servers/visual/visual_server_canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ class VisualServerCanvas {
void _canvas_item_skeleton_moved(RID p_item);
void canvas_item_set_skeleton_relative_xform(RID p_item, Transform2D p_relative_xform);
Rect2 _debug_canvas_item_get_rect(RID p_item);
Rect2 _debug_canvas_item_get_local_bound(RID p_item);

void canvas_item_set_interpolated(RID p_item, bool p_interpolated);
void canvas_item_reset_physics_interpolation(RID p_item);
Expand Down
1 change: 1 addition & 0 deletions servers/visual/visual_server_raster.h
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@ class VisualServerRaster : public VisualServer {
BIND2(canvas_item_attach_skeleton, RID, RID)
BIND2(canvas_item_set_skeleton_relative_xform, RID, Transform2D)
BIND1R(Rect2, _debug_canvas_item_get_rect, RID)
BIND1R(Rect2, _debug_canvas_item_get_local_bound, RID)

BIND2(canvas_item_set_interpolated, RID, bool)
BIND1(canvas_item_reset_physics_interpolation, RID)
Expand Down
1 change: 1 addition & 0 deletions servers/visual/visual_server_wrap_mt.h
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ class VisualServerWrapMT : public VisualServer {
FUNC2(canvas_item_attach_skeleton, RID, RID)
FUNC2(canvas_item_set_skeleton_relative_xform, RID, Transform2D)
FUNC1R(Rect2, _debug_canvas_item_get_rect, RID)
FUNC1R(Rect2, _debug_canvas_item_get_local_bound, RID)

FUNC2(canvas_item_set_interpolated, RID, bool)
FUNC1(canvas_item_reset_physics_interpolation, RID)
Expand Down
1 change: 1 addition & 0 deletions servers/visual_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2223,6 +2223,7 @@ void VisualServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("canvas_item_set_material", "item", "material"), &VisualServer::canvas_item_set_material);
ClassDB::bind_method(D_METHOD("canvas_item_set_use_parent_material", "item", "enabled"), &VisualServer::canvas_item_set_use_parent_material);
ClassDB::bind_method(D_METHOD("debug_canvas_item_get_rect", "item"), &VisualServer::debug_canvas_item_get_rect);
ClassDB::bind_method(D_METHOD("debug_canvas_item_get_local_bound", "item"), &VisualServer::debug_canvas_item_get_local_bound);
ClassDB::bind_method(D_METHOD("canvas_light_create"), &VisualServer::canvas_light_create);
ClassDB::bind_method(D_METHOD("canvas_light_attach_to_canvas", "light", "canvas"), &VisualServer::canvas_light_attach_to_canvas);
ClassDB::bind_method(D_METHOD("canvas_light_set_enabled", "light", "enabled"), &VisualServer::canvas_light_set_enabled);
Expand Down
9 changes: 5 additions & 4 deletions servers/visual_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -1062,15 +1062,16 @@ class VisualServer : public Object {

virtual void canvas_item_attach_skeleton(RID p_item, RID p_skeleton) = 0;
virtual void canvas_item_set_skeleton_relative_xform(RID p_item, Transform2D p_relative_xform) = 0;
Rect2 debug_canvas_item_get_rect(RID p_item) {
#ifdef TOOLS_ENABLED
return _debug_canvas_item_get_rect(p_item);
Rect2 debug_canvas_item_get_rect(RID p_item) { return _debug_canvas_item_get_rect(p_item); }
Rect2 debug_canvas_item_get_local_bound(RID p_item) { return _debug_canvas_item_get_local_bound(p_item); }
#else
return Rect2();
Rect2 debug_canvas_item_get_rect(RID p_item) { return Rect2; }
Rect2 debug_canvas_item_get_local_bound(RID p_item) { return Rect2; }
#endif
}

virtual Rect2 _debug_canvas_item_get_rect(RID p_item) = 0;
virtual Rect2 _debug_canvas_item_get_local_bound(RID p_item) = 0;
virtual void canvas_item_set_interpolated(RID p_item, bool p_interpolated) = 0;
virtual void canvas_item_reset_physics_interpolation(RID p_item) = 0;
virtual void canvas_item_transform_physics_interpolation(RID p_item, Transform2D p_transform) = 0;
Expand Down

0 comments on commit 881ac09

Please sign in to comment.