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
Jittery camera movement when physics tick rate doesn't match FPS #241
Comments
Actually, just tried out the Screen.Recording.2024-03-27.at.12.57.01.AM.movFollowing the Feel free to close this issue if it doesn't provide any value; I'd say that the upcoming release fixes the bug. |
Will keep this issue open until the release is out. Every test for this makes a difference, so thanks for sharing the MRP :) |
I experienced some jitter when I tested out 0.6 with 2D camera. Given this comment I wanted to test 0.7 as well, turns out it was much worse. Video of jitterjitter2d.webmSorry for the bad recording, the jitter did not show up with my screen recorder software, so I had to use my phone. |
The way the system works in 0.7 requires a bit of extra setup. So if you're only assigning the Would stay tuned for the release notes of 0.7, which covers what to do in more detail. |
I used the same setup as stated in the docs for 0.6, with the target being a CharacterBody2D. Looking forward to the release! |
In case it helps, I turned the pixel perfect setting on the camera off and changed the _process in the camera and host gd scripts to _physics_process and it works well with both the characterbody2D and rigidbody2D. |
Don't recommend moving the logic to the Would suggest following the steps mentioned in the FAQ |
That was the first thing I tried but 1. It didn't work for pixel perfect cameras and 2. the solution is not the ideal one if the user needs to use the same smoothing paradigm for networking rollback etc which will make the plugin more awkward to use. The fundamental issue IS the tick rate in which the camera is moving if the target is a physics object. Cinemachine solves this by allowing the brain to execute its processes in FixedUpdate as well as LateUpdate (This is important as right now it seems the camera interferes with velocity/position as it locks the rigidbody/transform in place if set up incorrectly) or it has a SmartUpdate feature which will dynamically pick between the two depending on situation. |
After reading your release note I understand the problem you are facing. It can be solved by having an enum that lets the code run in either physicsprocess or process then you can extend that with a smart update by detecting the phantom camera target’s node type and auto switch between the two. |
I won't pretend like I know what, how and most importantly why Cinemachine does all the things it does, so correct me if I'm wrong. Conceptually, cameras (and, by extension, phantom cameras) shouldn't ever be physics objects. Every game object (i.e. ones that interact with the world) you want to render to your game's window should have a) a physics representation and b) a visual representation. There is then a clear separation of concern with a) handling where the physics representation should be after interacting with other physics objects at physics tick intervals (i.e. in In this case, correctly handling networking rollback, or even the object teleporting instantly, is up to b) (albeit obviously with some help from your networking code, etc.). Having a separate node handling solely where the object should be rendered is beneficial for many reasons. As an example, imagine you have a 2D game, and you want a true pixel-perfect camera (i.e. no pixel misalignments - even for moving objects). However, you have a moving object, intentionally with no friction, with a vector of As another example, you can have the physics engine running at 20 ticks per second (wink), and still have smooth motion of objects on the screen at 1000+ fps if b) uses techniques such as interpolation using frame times. So then cameras - objects that should concern themselves with only the visual representations of objects - should update at frame rate intervals (i.e. in Sorry for the wall of text 🤓. |
To back up what @audeck says, jittery in this context isn't an issue with the physics node being jittery as it moves around, but rather the thing that visually represents it, i.e. the Sprite / Model inside of it. I could not for the life of me record actual examples of how Each project includes 2 example scenes, one for 2D and one for 3D, which can be found in the root directory. More concretely, the The 2D and 3D scenes both contain a node, Both projects use an identical project setup of:
The observation from the above projects with those settings should show the one using the If you modify the So I am not confident that a dynamic system that sets the camera to move in |
I understand. I think the issue stems from Godot not having any underlying interpolation for physics. 3.5 had this but is yet to be implemented from what I have read. The engine itself should be responsible for this interpolation under the hood in process_physics but as of 4.2 I still don’t think that has happened. Essentially doing what you guys are doing with smoothing, this should be happening between the rigidbody node and the sprite node with the user having no idea. When it does eventually happen, mimicking the way cinemachine handles this would work. |
Just found out that 2D physics interpolation has been implemented for godot 4.3 godotengine/godot#88424 |
100%, it ideally shouldn't be on the user to figure out how to set it up correctly — as most will be confused until looking it up otherwise. Should hopefully just be a case of waiting for the engine to add that in to improve that usability.
Good idea, will try to run some tests with that and Jolt out at some point. |
I am on the 4.3 Dev 6 snapshot and the issue is still happening when using https://godotengine.org/article/dev-snapshot-godot-4-3-dev-6/ |
@blai30 Did you enable the settings mentioned in the PR?
|
@Nohac Yes, that did not seem to help |
@blai30 Fixed the repository's 2D dev scene for
What's important is not mixing the previous manual interpolation (using either the project's From the upstream discussions it seems that the Godot team wants to prioritize making things as easy as possible for people just getting into Godot/game dev in general. @ramokz To support your previous comment, I think this addon should mirror that and support using |
I tested this now, and it does not work out of the box as @blai30 says, applying @audeck solution fixes it. So I'm not completely sure what the interpolation actually does. With @audeck changes and interpolation disabled, it is a bit more jittery, but it's not terrible. It would be nice to get the godot devs to give an "official" recommendation of what to do in this case. |
Tried out the 4.3 dev6 build as well. @Nohac if you comment out the following code in func _process(delta) -> void:
_player_visuals.global_position = _physics_body_trans_last.interpolate_with(
_physics_body_trans_current,
Engine.get_physics_interpolation_fraction()
).origin This code exists as a manual solution to the lawnjelly's |
Have attached a short demo of having the physics_interpolation_demo.mp4To go back to what @ipinzi proposed, do agree that with this change in Godot 4.3, and assuming it works consistently for others, the |
Yes. The built-in physics interpolation's inherent limitation is that it makes the game's physics run 1 tick behind (in reality it now runs 2 ticks behind, but that's irrelevant for this), since instead of just calculating the physical position and setting the object's That means that during So say we have three physics ticks - #0, #1 and #2 - with the game just after finishing #2. Inbetween #2 and the next tick, the physics node is interpolating between positions at #1 and #2, while the visual node is interpolating between positions at #0 and #1. It is then very easy to introduce jitter with any sort of discrepancy in these positions (mainly due to differing tick rates and FPS), since the camera is following the "invisible" physical node, while the sprite is lagging behind at different distances each frame.
So yes, I'm pretty sure it does, as long as the visual representation isn't trying to do the same thing as well, but with different data. On another note, with the dev scene using physics interpolation, the camera position seems to lag behind the player position by 1 tick (noticeable on very low physics tick rates), but that's material for a separate issue after 4.3. |
That's great news! I'm glad this came together so quickly. It should also help the camera not fight against the interpolation of other physics systems. |
Now we just need the same interpolation to come to 3D 😉 |
Have made a draft PR with the changes to support the Godot 4.3 It technically all works and supports both 4.2 and 4.3, but due to an issue (described in the PR) I won't be merging this in until that gets resolved. From the test included in the PR description, it points to it being a bug in the current Godot implementation of the physics interpolation. |
The PR should now be updated to resolve the aforementioned issue(s). Testing in Godot 4.2 would also be beneficial, mainly just to confirm that there's no regression. |
Please read follow-up comment; this may be able to just be closed!
Issue description
phantom-camera
version:0.6.4
Godot v4.2.1.stable - macOS 14.1.1 - Vulkan (Forward+) - integrated Apple M1 - Apple M1 (8 Threads)
This is a bit of a duplicate of #173 but I think that there may need to be some updated docs around it for some best practices. I spent the whole day debugging physics jitters and found out that it was the camera that was the source of it 😅
I think this comment is very relevant: #179 (comment)
(hi, it's me, people thinking something is fundamentally broken 😄 )
The setup I have is like...
CharacterBody3D
(RigidBody3D
)CollisionShape3D
Smoothing
(fromsmoothing-addon
)MeshInstance3D
PhantomCamera3D
(follow mode "Simple", follow targetMeshInstance3D
above)For testing purposes, I've set
Physics Ticks per Second
to10
in the project settings.Using a static camera, you can see that the
smoothing-addon
is working as intended. The mesh follows the collision shape smoothly, even though the physics update is slow:Screen.Recording.2024-03-27.at.12.16.40.AM.mov
However, if you set this to follow mode "Simple", the camera movement is jittery even if you follow the mesh instance that's a child of the
Smoothing
node.Note that this behavior exists even with
damping
turned on! It also happens no matter what child of the rigid body you follow. It's surprising to me that this behavior happens when following theMeshInstance3D
since it should be smoothed (but maybe this is happening in_physics_process
so the smoothing is done before the camera updates?)Screen.Recording.2024-03-27.at.12.15.43.AM.mov
There even appear to be issues when using
smoothing-addon
with the physics tick rate much higher than the FPS. Here's an example of a physics tick rate of 144, zoomed in so that you can see the "vibration" of the camera following the object:Screen.Recording.2024-03-27.at.12.22.11.AM.mov
That same vibration is not present with the static camera, so it's something in the way that the camera is following the object:
Screen.Recording.2024-03-27.at.12.23.44.AM.mov
I wonder if there should be a setting to switch whether you want a specific camera to update inside of
_process
or inside of_physics_process
?Minimal reproduction project
Reproduction project: https://github.com/TranquilMarmot/phantom-camera-jitter-repro
See README for details.
The text was updated successfully, but these errors were encountered: