Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix global transform validity for Node2D and Control #80105

Merged
merged 1 commit into from
Aug 28, 2023

Conversation

Sauermann
Copy link
Contributor

@Sauermann Sauermann commented Aug 1, 2023

Set global transform to invalid when changing transform

resolve #79453

Add unit-tests for the bug

kleonc
kleonc previously requested changes Aug 1, 2023
Copy link
Member

@kleonc kleonc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a correct fix.

The global_invalid flag being initialized to false is correct. A newly created CanvasItem has no parent and its own transform is an identity, hence global_transform being an identity by default is valid.

Marking global transform as invalid by default would result in some unnecessary one-time updates for actually unchanged global transforms. But it doesn't solve the issue which is: some out of tree modifications (like Node2D.set_global_position) result in not marking the global transform as dirty.

E.g. with this PR:

@tool
extends EditorScript

func _run() -> void:
	var a = Node2D.new()
	a.global_position = Vector2(1, 1)
	assert(a.global_position == Vector2(1, 1)) # Passes because of invalid by default.
	a.global_position = Vector2(2, 2)
	assert(a.global_position == Vector2(2, 2)) # Still fails.

Also I'm not sure if the global_invalid to global_valid name change is needed/wanted at all.

@Sauermann Sauermann requested a review from a team as a code owner August 1, 2023 10:13
@Sauermann Sauermann changed the title Fix gobal transform validity initialization Fix global transform validity for Node2D Aug 1, 2023
@Sauermann
Copy link
Contributor Author

@kleonc Thank you for pointing me in the right direction. I have included your improvements in the PR.

@kleonc
Copy link
Member

kleonc commented Aug 1, 2023

@Sauermann There's also Control.global_position having the same issue.

@Sauermann Sauermann requested a review from a team as a code owner August 1, 2023 11:19
@Sauermann Sauermann changed the title Fix global transform validity for Node2D Fix global transform validity for Node2D and Control Aug 1, 2023
@Sauermann
Copy link
Contributor Author

I have included the invalidation for transform-changing operations in Control.

@Sauermann
Copy link
Contributor Author

@kleonc may I ask if your requested changes have been resolved by my updates?

@kleonc
Copy link
Member

kleonc commented Aug 5, 2023

@kleonc may I ask if your requested changes have been resolved by my updates?

Hmm, seems like it should now be properly invalidating the global transforms. 👍

However, I'm not sure if these added invalidations don't affect transform notifications in some unwanted manner. Specifically, after brief look at the code, when in the tree CanvasItem::_notify_transform calls _notify_transform(this):

_FORCE_INLINE_ void _notify_transform() {
if (!is_inside_tree()) {
return;
}
_notify_transform(this);
if (!block_transform_notify && notify_local_transform) {
notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
}
}

which early returns in case global transform is invalid:
void CanvasItem::_notify_transform(CanvasItem *p_node) {
/* This check exists to avoid re-propagating the transform
* notification down the tree on dirty nodes. It provides
* optimization by avoiding redundancy (nodes are dirty, will get the
* notification anyway).
*/
if (/*p_node->xform_change.in_list() &&*/ p_node->_is_global_invalid()) {
return; //nothing to do
}

Hence I wonder if adding _invalidate_global_transform(); before _notify_transform(); (like it's done in many of the changed methods) could have broken some notification propagation or something like that. 🤔 We'll need to ensure nothing is broken I guess (or maybe you've already ensured that?).

@Sauermann
Copy link
Contributor Author

Thank you for taking the time to guide me through the maze of Transform-caching.
The case, that you have identified was indeed problematic.

With the latest updated I made sure that

  • the behavior while is_inside_tree() == true is not changed
  • while not inside tree, caching status traverses down the scene-tree

scene/main/canvas_item.cpp Outdated Show resolved Hide resolved
Set global transform to invalid when changing transform
Copy link
Member

@Calinou Calinou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested locally (rebased on top of master 6758a7f), it works as expected.

I've also tested a few demo projects (3D Platformer, Control Gallery) and they behave correctly.

@YuriSizov YuriSizov requested a review from kleonc August 25, 2023 10:04
Copy link
Member

@kleonc kleonc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT it should work fine now. 👍

@akien-mga akien-mga added the cherrypick:4.1 Considered for cherry-picking into a future 4.1.x release label Aug 28, 2023
@akien-mga akien-mga merged commit 2c0a74a into godotengine:master Aug 28, 2023
@akien-mga
Copy link
Member

Thanks!

@Sauermann Sauermann deleted the fix-global-transform branch August 28, 2023 21:55
@YuriSizov YuriSizov removed the cherrypick:4.1 Considered for cherry-picking into a future 4.1.x release label Sep 20, 2023
@YuriSizov
Copy link
Contributor

Cherry-picked for 4.1.2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Node2D global_position does not update when set before it's added to the scene tree
5 participants