Skip to content

Commit

Permalink
CPUParticles2D - fix interpolated transforms and culling
Browse files Browse the repository at this point in the history
1) Physics interpolated particles in global mode are specified in global space. In VisualServer they should therefore ignore local transform.

2) Additionally, the expected final_transform should be passed on to children, rather than the identity transform used on the local item.

3) Local bounds in hierarchical culling are fixed for items using identity transform, by calculating their local bound in local space from the global space particles.
  • Loading branch information
lawnjelly committed Aug 22, 2023
1 parent 17b403a commit 723632a
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 19 deletions.
2 changes: 1 addition & 1 deletion scene/2d/canvas_item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ void CanvasItem::set_canvas_item_use_identity_transform(bool p_enable) {
_set_use_identity_transform(p_enable);

// Let VisualServer know not to concatenate the parent transform during the render.
VisualServer::get_singleton()->canvas_item_set_ignore_parent_transform(get_canvas_item(), p_enable);
VisualServer::get_singleton()->canvas_item_set_use_identity_transform(get_canvas_item(), p_enable);

if (is_inside_tree()) {
if (p_enable) {
Expand Down
4 changes: 2 additions & 2 deletions servers/visual/rasterizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -1006,7 +1006,7 @@ class RasterizerCanvas {
bool light_masked : 1;
bool on_interpolate_transform_list : 1;
bool interpolated : 1;
bool ignore_parent_xform : 1;
bool use_identity_xform : 1;
mutable bool custom_rect : 1;
mutable bool rect_dirty : 1;
mutable bool bound_dirty : 1;
Expand Down Expand Up @@ -1262,7 +1262,7 @@ class RasterizerCanvas {
update_when_visible = false;
on_interpolate_transform_list = false;
interpolated = true;
ignore_parent_xform = false;
use_identity_xform = false;
local_bound_last_update_tick = 0;
}
virtual ~Item() {
Expand Down
84 changes: 72 additions & 12 deletions servers/visual/visual_server_canvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
/**************************************************************************/

#include "visual_server_canvas.h"
#include "core/fixed_array.h"
#include "core/math/transform_interpolator.h"
#include "visual_server_globals.h"
#include "visual_server_raster.h"
Expand Down Expand Up @@ -277,10 +278,57 @@ void VisualServerCanvas::_calculate_canvas_item_bound(Item *p_canvas_item, Rect2
}
}

Transform2D VisualServerCanvas::_calculate_item_global_xform(const Item *p_canvas_item) {
// If we use more than the maximum scene tree depth, we are out of luck.
// But that would be super inefficient anyway.
FixedArray<const Transform2D *, 64> transforms;

while (p_canvas_item) {
// Should only happen if scene tree depth too high.
if (transforms.is_full()) {
WARN_PRINT_ONCE("SceneTree depth too high for hierarchical culling.");
break;
}

// Note this is only using the CURRENT transform.
// This may have implications for interpolated bounds - investigate.
transforms.push_back(&p_canvas_item->xform_curr);

if (canvas_item_owner.owns(p_canvas_item->parent)) {
p_canvas_item = canvas_item_owner.get(p_canvas_item->parent);
} else {
p_canvas_item = nullptr;
}
}

Transform2D tr;
for (int n = (int)transforms.size() - 1; n >= 0; n--) {
tr *= *transforms[n];
}
return tr;
}

void VisualServerCanvas::_finalize_and_merge_local_bound_to_branch(Item *p_canvas_item, Rect2 *r_branch_bound) {
if (r_branch_bound) {
Rect2 this_rect = p_canvas_item->get_rect();

// Special case .. if the canvas_item has use_identity_xform,
// we need to transform the rect from global space to local space,
// because the hierarchical culling expects local space.
if (p_canvas_item->use_identity_xform) {
// This is incredibly inefficient, but should only occur for e.g. CPUParticles2D,
// and is difficult to avoid because global transform is not usually kept track of
// in VisualServer (only final transform which is combinated with camera, and that
// is only calculated on render, so is no use for culling purposes).
Transform2D global_xform = _calculate_item_global_xform(p_canvas_item);
this_rect = global_xform.affine_inverse().xform(this_rect);

// Note that the efficiency will depend linearly on the scene tree depth of the
// identity transform item.
// So e.g. interpolated global CPUParticles2D may run faster at lower depths
// in extreme circumstances.
}

// If this item has a bound...
if (!p_canvas_item->local_bound.has_no_area()) {
// If the rect has an area...
Expand Down Expand Up @@ -340,13 +388,19 @@ void VisualServerCanvas::_render_canvas_item_cull_by_item(Item *p_canvas_item, c
TransformInterpolator::interpolate_transform_2d(ci->xform_prev, ci->xform_curr, final_xform, f);
}

if (!p_canvas_item->ignore_parent_xform) {
final_xform = p_transform * final_xform;
// Always calculate final transform as if not using identity xform.
// This is so the expected transform is passed to children.
// However, if use_identity_xform is set,
// we can override the transform for rendering purposes for this item only.
final_xform = p_transform * final_xform;

Rect2 global_rect;
if (!p_canvas_item->use_identity_xform) {
global_rect = final_xform.xform(rect);
} else {
final_xform = _current_camera_transform * final_xform;
global_rect = _current_camera_transform.xform(rect);
}

Rect2 global_rect = final_xform.xform(rect);
global_rect.position += p_clip_rect.position;

if (ci->use_parent_material && p_material_owner) {
Expand Down Expand Up @@ -422,7 +476,7 @@ void VisualServerCanvas::_render_canvas_item_cull_by_item(Item *p_canvas_item, c

if ((!ci->commands.empty() && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
//something to draw?
ci->final_transform = final_xform;
ci->final_transform = !p_canvas_item->use_identity_xform ? final_xform : _current_camera_transform;
ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a);
ci->global_rect_cache = global_rect;
ci->global_rect_cache.position -= p_clip_rect.position;
Expand Down Expand Up @@ -481,15 +535,21 @@ void VisualServerCanvas::_render_canvas_item_cull_by_node(Item *p_canvas_item, c
TransformInterpolator::interpolate_transform_2d(ci->xform_prev, ci->xform_curr, final_xform, f);
}

if (!p_canvas_item->ignore_parent_xform) {
final_xform = p_transform * final_xform;
// Always calculate final transform as if not using identity xform.
// This is so the expected transform is passed to children.
// However, if use_identity_xform is set,
// we can override the transform for rendering purposes for this item only.
final_xform = p_transform * final_xform;

Rect2 global_rect;
if (!p_canvas_item->use_identity_xform) {
global_rect = final_xform.xform(rect);
} else {
final_xform = _current_camera_transform * final_xform;
global_rect = _current_camera_transform.xform(rect);
}

Rect2 global_rect = final_xform.xform(rect);
ci->global_rect_cache = global_rect;
ci->final_transform = final_xform;
ci->final_transform = !p_canvas_item->use_identity_xform ? final_xform : _current_camera_transform;

global_rect.position += p_clip_rect.position;

Expand Down Expand Up @@ -955,11 +1015,11 @@ void VisualServerCanvas::canvas_item_set_draw_behind_parent(RID p_item, bool p_e
_check_bound_integrity(canvas_item);
}

void VisualServerCanvas::canvas_item_set_ignore_parent_transform(RID p_item, bool p_enable) {
void VisualServerCanvas::canvas_item_set_use_identity_transform(RID p_item, bool p_enable) {
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);

canvas_item->ignore_parent_xform = p_enable;
canvas_item->use_identity_xform = p_enable;
_make_bound_dirty(canvas_item);
}

Expand Down
3 changes: 2 additions & 1 deletion servers/visual/visual_server_canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ class VisualServerCanvas {
void _prepare_tree_bounds(Item *p_root);
void _calculate_canvas_item_bound(Item *p_canvas_item, Rect2 *r_branch_bound);

Transform2D _calculate_item_global_xform(const Item *p_canvas_item);
void _finalize_and_merge_local_bound_to_branch(Item *p_canvas_item, Rect2 *r_branch_bound);
void _merge_local_bound_to_branch(Item *p_canvas_item, Rect2 *r_branch_bound);

Expand Down Expand Up @@ -227,7 +228,7 @@ class VisualServerCanvas {
void canvas_item_set_self_modulate(RID p_item, const Color &p_color);

void canvas_item_set_draw_behind_parent(RID p_item, bool p_enable);
void canvas_item_set_ignore_parent_transform(RID p_item, bool p_enable);
void canvas_item_set_use_identity_transform(RID p_item, bool p_enable);

void canvas_item_set_update_when_visible(RID p_item, bool p_update);

Expand Down
2 changes: 1 addition & 1 deletion servers/visual/visual_server_raster.h
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ class VisualServerRaster : public VisualServer {
BIND2(canvas_item_set_self_modulate, RID, const Color &)

BIND2(canvas_item_set_draw_behind_parent, RID, bool)
BIND2(canvas_item_set_ignore_parent_transform, RID, bool)
BIND2(canvas_item_set_use_identity_transform, RID, bool)

BIND6(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float, bool)
BIND5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool)
Expand Down
2 changes: 1 addition & 1 deletion servers/visual/visual_server_wrap_mt.h
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ class VisualServerWrapMT : public VisualServer {
FUNC2(canvas_item_set_self_modulate, RID, const Color &)

FUNC2(canvas_item_set_draw_behind_parent, RID, bool)
FUNC2(canvas_item_set_ignore_parent_transform, RID, bool)
FUNC2(canvas_item_set_use_identity_transform, RID, bool)

FUNC6(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float, bool)
FUNC5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool)
Expand Down
2 changes: 1 addition & 1 deletion servers/visual_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -1024,7 +1024,7 @@ class VisualServer : public Object {
virtual void canvas_item_set_self_modulate(RID p_item, const Color &p_color) = 0;

virtual void canvas_item_set_draw_behind_parent(RID p_item, bool p_enable) = 0;
virtual void canvas_item_set_ignore_parent_transform(RID p_item, bool p_enable) = 0;
virtual void canvas_item_set_use_identity_transform(RID p_item, bool p_enable) = 0;

enum NinePatchAxisMode {
NINE_PATCH_STRETCH,
Expand Down

0 comments on commit 723632a

Please sign in to comment.