Closed DragonAxe closed 1 year ago
With the following project settings: Window Width/Height = (800, 600), Stretch Mode = viewport, Stretch Aspect = keep. I observed the following approximate results from get_camera_screen_center()
when the camera is rotated at the following angles at camera position or offset (0, 0):
Note: Screen center values are approximate and are rounded to remove floating point math artifacts, e.g. (50.000061, -0.000061).
For anyone else who has run into this issue, I found a workaround:
var inv_canv_tfm: Transform2D = self.get_canvas_transform().affine_inverse()
var half_screen: Transform2D = Transform2D().translated(get_viewport_rect().size / 2)
var actual_screen_center_pos: Vector2 = inv_canv_tfm * half_screen * Vector2(0, 0)
actual_screen_center_pos
will be accurate even with camera smoothing enabled, zoom, and rotation. (Note: Did not test with camera offset)
@DragonAxe I tried to adapt your code to my game. But I can currently not multiply a vector with a transform (at least in my C# project). I don't actually understand the third line. Could you explain it so I can adapt?
Let me see if I can explain, it's been a while since I've looked at this.
Basically what I'm doing here is matrix-vector multiplication.
One thing to note is that GDscript has some special handling when using *
with vectors and matrices.
I haven't done much with C#, but perhaps the Transform2D class has a .Multiply(<vector>)
method you could use, or maybe .xform()
and .xform_inv()
methods are what you need.
(https://docs.godotengine.org/en/3.2/tutorials/math/matrices_and_transforms.html#converting-positions-between-transforms)
Here is a breakdown of my code above:
self.get_canvas_transform()
I start by getting a transformation matrix that can convert a vector from world space into screen space.
self.get_canvas_transform().affine_inverse()
Then I make it go in the opposite direction by inverting the matrix. (screen space to world space)
Transform2D().translated(get_viewport_rect().size / 2)
To make the next operation a simple matrix multiplication, I create another transformation matrix which, when multiplied with a vector, will move that vector to the center of the screen.
half_screen * Vector2(0, 0)
Then, I take a position at (0,0) then I move it (translate it) into the center of the screen. This gives us a vector that exists in screen space.
inv_canv_tfm *
Then I can use my handy screen space to world space transformation matrix to move the center screen position to the position of the camera.
Hope this helps!
Thank you for the explaination. I think I now understand it. I adapted the code to C#:
Transform2D inverseCanvasTransform = this.GetCanvasTransform().AffineInverse();
Transform2D halfScreenTransform = (new Transform2D()).Translated(this.GetViewportRect().Size * 0.5f);
Vector2 actualScreenCenterPosition = inverseCanvasTransform.Xform(halfScreenTransform.Xform(Vector2.Zero));
I tested if this works with my implemented camera shake. But I guess there is a problem left with the offset (as you mentioned already), because the position seems to be off when my camera shakes.
But maybe I can find a way to fix this. :)
I had accidentally made a duplicate of this. Reposting as a comment here in case my repro might be useful.
v4.2.beta.custom_build [b1371806a], v4.1.2.stable
Godot v4.2.beta (b1371806a) - Windows 10.0.19045 - GLES3 (Compatibility) - NVIDIA GeForce GTX 1080 Ti (NVIDIA; 31.0.15.3623) - AMD Ryzen Threadripper 1950X 16-Core Processor (32 Threads)
The Vector2 returned by Camera2D::get_screen_center_position()
is (incorrectly) affected by the camera's rotation. Rotating the camera will cause get_screen_center_position
to return different values, despite the actual center being in the same place.
get_screen_center_position
returns incorrect values.In this example project there are two scenes with similar setups.
One Sprite, colored red, follows the Camera2D's get_screen_center_position()
The other Sprite follows the Camera2D's get_target_position()
for comparison
The Camera2D being followed is rotated by delta in _process
one_cam.tscn is from the perspective of the rotating camera. two_cams..tscn is from the perspective of a second, zoomed out camera.
I've looked at https://github.com/godotengine/godot/pull/63773 and it will unfortunately NOT close this issue, though I don't believe it was intended to. I agree that if that gets merged, it will at least make it easier to fix this issue.
I adapted the code to C#:
Transform2D inverseCanvasTransform = this.GetCanvasTransform().AffineInverse(); Transform2D halfScreenTransform = (new Transform2D()).Translated(this.GetViewportRect().Size * 0.5f); Vector2 actualScreenCenterPosition = inverseCanvasTransform.Xform(halfScreenTransform.Xform(Vector2.Zero));
In C# default constructor zeroes the structs. In GDScript Transform2D() == Transform2D.IDENTITY
but in C# new Transform2D() != Transform2D.Identity
. So replacing new Transform2D()
with Transform2D.Identity
should fix that snippet.
Anyway, pure translation transform can be omitted by straight up adding the translation to the vector, same effect:
Transform2D inverseCanvasTransform = this.GetCanvasTransform().AffineInverse();
Vector2 actualScreenCenterPosition = inverseCanvasTransform.Xform(this.GetViewportRect().Size * 0.5f);
Godot version: Godot Engine v3.2.3.stable.official
OS/device including version: Arch Linux 5.9.11-arch2-1 #1 SMP PREEMPT Sat, 28 Nov 2020 02:07:22 +0000 x86_64 GNU/Linux OpenGL ES 3.0 Renderer: Mesa Intel(R) UHD Graphics 620 (KBL GT2)
Issue description: What happened: Camera2D method
get_camera_screen_center()
does not return(0, 0)
when the camera is being rotated withself.rotate(0.1*delta)
,Offset=(0, 0)
,Current=On
,Rotating=On
, andAnchor Mode = Drag Center
. Note: WithAnchor Mode = Fixed TopLeft
I also see unexpected behavior where the position reported byget_camera_screen_center()
remains unchanged even though the camera view is rotating about the top left corner.What I expected:
get_camera_screen_center()
should continue to return(0, 0)
at any rotation angle as long as Offset=(0, 0) and the Anchor Mode = Drag Center. Note: WithAnchor Mode = Fixed TopLeft
the position reported byget_camera_screen_center()
should follow a circular path with center at the top left corner of the camera and radius equal to half the diagonal length of the camera window size.https://docs.godotengine.org/en/stable/classes/class_camera2d.html#class-camera2d-method-get-camera-screen-center
Steps to reproduce:
get_camera_screen_center()
.)func _ready(): set_process(true)
func _process(delta): self.rotate(0.1*delta) $"../Label".text = str(self.get_camera_screen_center())