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

Global rotation can return opposite sign of expected. #21020

Closed
ghost opened this issue Aug 14, 2018 · 8 comments
Closed

Global rotation can return opposite sign of expected. #21020

ghost opened this issue Aug 14, 2018 · 8 comments

Comments

@ghost
Copy link

ghost commented Aug 14, 2018

When you have a node belonging to a parent using scaling with a negative X (or Y), the global rotation seems to be putting out the wrong sign and flipping the rotation.

When both scaling X and Y are the same sign (positive or negative) it will appear correct, but when only one component of the parent's scaling is negative the global rotation of the children will have the opposite sign of that scaling.

The canvas item will render with no issue, but the global rotation value it returns will give the following:

godot 64_2018-08-15_00-00-45

Red is what happens in the SceneTree, the Green arrow is using the global rotation value given by the Red arrow. The Green Arrow is not parented to the Red and isn't inheriting any rotations, see the sample project for more details.

I don't know if this is something intentional, but looking at the output of the global transform's scaling, I wonder why the Y component has a negative value rather than the X. Maybe the scaling is flipped up somewhere?

godot 64_2018-08-15_00-01-06

Is this behavior intended, expected, or is it actually a bug? It tripped me up quite seriously. I assumed this far that the point of global xform references were that they would be taking into account all the transformations of the parents.

This is from a master branch build (3.1) I compiled yesterday, and I'm running everything in the context of Windows 10 with 64 bit versions.

It also seems to be present in previous versions.

Does it have anything to do with the problems seen here?: #20966

A 3.1 sample project:
Neg X Scale Global Rotation.zip

@Piet-G
Copy link
Contributor

Piet-G commented Aug 14, 2018

I have encountered this before, it has to do with the way the values are stored in the transform matrix.
See #17405

@ghost
Copy link
Author

ghost commented Aug 14, 2018

@dualmatrix Thanks for sharing that. I agree, that it would be nice if the global_rotation (scale as well?) would handle the extra step. It isn't so intuitive when you run into this thinking you'll save some coding time with managing rotating parts belonging to a character that relies on flipping its scaling. The testing starts out fine when going in positive X direction, but when you turn around all hell breaks loose. XD

@poke1024
Copy link
Contributor

Might have to do with orientation, see this comment from Transform2's source code:

	// Warning #2: 2D be aware that unlike 3D code, 2D code uses a left-handed coordinate system: Y-axis points down,
	// and angle is measure from +X to +Y in a clockwise-fashion.

This definitely should appear prominently somewhere in the docs I guess.

@Piet-G
Copy link
Contributor

Piet-G commented Aug 15, 2018

@poke1024

No , it has to do with the way the rotation, scale and position are being stored in a Transform matrix, and since a negative scale + rotation is mathematically identical to a positive scale + another rotation so the code can't distinguish the two.

@ghost
Copy link
Author

ghost commented Aug 15, 2018

@poke1024 The orientation in the example project I believe is correct. It's more of an issue with the rotation being flipped and not taking into account the scaling of the parent when it's negative. Was wondering if it may have been related to your issue, since you were having problems with inverted transforms.

I'm not very well versed in the matrix math, but for now I'm using a work around that goes something like this (though it may be naive):

func global_rotation():
	
	var s = get_global_transform().get_scale()
	return global_rotation * sign(s.x) * sign(s.y)

@poke1024
Copy link
Contributor

@avencherus Ok, this is a different issue from mine then, and not one of orientation, as @dualmatrix notes. As composition, both scale-rotations are identical and correct, it's a matter of convention which to choose, and Godot's convention doesn't match with the convention you need in your use case.

This code might be related:

real_t Transform2D::get_rotation() const {
	real_t det = basis_determinant();
	Transform2D m = orthonormalized();
	if (det < 0) {
		m.scale_basis(Size2(1, -1)); // convention to separate rotation and reflection for 2D is to absorb a flip along y into scaling.
	}
	return Math::atan2(m[0].y, m[0].x);
}

You could try to skip the flip in the implementation above, extract the rotation yourself, i.e. do a atan2(yourtransform.x.y, yourtransform.x.x) in GDScript (not tested).

@Anutrix
Copy link
Contributor

Anutrix commented Aug 10, 2019

Any updates?

@aaronfranke
Copy link
Member

This is a duplicate of #17405. The symptoms are different, but the cause is the same: Negative X scales can't be decomposed from a transformation matrix, and negative X scales get encoded in the transformation matrix as a rotation, therefore negative X scales have problems like these and should be discouraged or disallowed.

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

No branches or pull requests

5 participants