Closed ghost closed 7 years ago
For example, if I ship my game out at a fixed_fps variable of 144. Only players who have a 144hz monitor will get NO JITTER. Anyone with a 60hz monitor wll experience massive jitter.
I don't remember fixed_fps
values above the monitor's refresh rates causing any issues. That said, it would be helpful to have a function to retreive the monitor's refresh rate, but the implementation is quite OS-specific and would have to be done for every desktop platform.
@Calinou Yeah, I just got done plugging in my older 60hz monitor to test on my 144 fixed_fps game. Jitter is still very apparent. I did test it on my 144hz monitor by just switching it to 60hz in settings, but just wanted to make sure with an actual physically different monitor
Basically i'm curious shouldn't the fixed_fps adjust automatically based on the user's refresh rate already? For the smoothness performance? I mean, if the fixed_fps is defaulted to a delta time of 0.0167 (60fps) I finally get where all the jitter reports are coming from...
Because once I set the fixed_fps to the same as my monitor's refresh rate, it all disappeared and Godot's renderer feels as smooth as butter... (never thought I'd say that lol)
e: This is with vsync on btw
this is the physics iteration per second step right? If so this defeats the purpose which is to let you have a fixed stepped iteration, interpolate/extrapolate the node's physics state to obtain a visual position in frame update or move your stuff there manually.
I am pretty impressed anyone can see jitter beyond 60fps, would love to have a 144hz monitor to test :P
On Sat, Jul 8, 2017 at 12:32 PM, tamkcr notifications@github.com wrote:
this is the physics iteration per second step right? If so this defeats the purpose which is to let you have a fixed stepped iteration, interpolate/extrapolate the node's physics state to obtain a visual position in frame update or move your stuff there manually.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/godotengine/godot/issues/9561#issuecomment-313863096, or mute the thread https://github.com/notifications/unsubscribe-auth/AF-Z2x0D7bqJonb2q94qz-myoo--AZsSks5sL6EBgaJpZM4ORui1 .
Is this the fixed timestep jitter when more/less fixed steps happen compared to the previous frame? If so, the issue is that Godot doesn't interpolate between the previous<->new states when there is a fixed/idle time deficit -- how's that going by the way? :P
Changing fixed FPS per user/machine is probably not a good idea. Different deltas will make physics and your code behave differently, causing an inconsistent experience and limiting your test coverage. Fixed timesteps are and should be completely independent of the monitor refresh rate.
Okay, thank you guys.
So here's the deal after I did some testing. I am now using a KinematicBody2D that utilizes _process instead of _fixed_process to move the character. This works flawlessly on both 60hz and 144hz with no jitter whatsoever.
The only problem now is when your character on a 144hz monitor pushes against a collision shape. The KinematicBody2D goes back n forth and creates a jitter.
To fix that, you need to set fixed_fps to 144
Also, another way to fix that, set the force_fps to 60
But if you set the force_fps to 60, then there is jitter when you move. (if you're on a 144hz monitor)
And if you set the fixed_fps to 144, the godot user who doesn't have a 144hz monitor will experience jitter.
We need a way to programmatically get the user's monitor refresh rate and use it to set settings in godot. Or games cannot be shipped and work with 144hz and 60hz monitors. That's a big problem!!
One suggested solution was using fixed frame interpolation, but honestly without trying or seeing the problem myself you can imagine it's a little difficult..
Np reduz, thanks for the info.
I found a temporary solution.
The only problem now is when your character on a 144hz monitor pushes against a collision shape. The KinematicBody2D goes back n forth and creates a jitter.
Go to physics 2d -> motion_fix_enabled and set this to true. This fixes that issue.
And, looking at the camera class, line 141, it uses fixed updated (physics).
Sadly that means using a native camera node it will create jitter if updating your kinematic body with _process.
The best solution I found is to roll some custom camera code. Use this inside your _process function right after your character is moving.
Create 2 variables
var cameraPos = Vector2()
var smoothed_camera_pos = Vector2()
Then stick this underneath your move()
var canvas_transform = get_viewport().get_canvas_transform()
var width = OS.get_window_size().width
var height = OS.get_window_size().height
cameraPos.x = -get_global_pos().x + (width/2)
cameraPos.y = -get_global_pos().y + (height/2)
var c = 4 * delta
smoothed_camera_pos = ((cameraPos - smoothed_camera_pos) * c) + smoothed_camera_pos
canvas_transform[2] = smoothed_camera_pos
get_viewport().set_canvas_transform(canvas_transform)
No jitter on 144hz, or 60hz.
This is a big deal juan because a lot of users are transitioning over to 144hz monitors, and when someone with a 144hz monitor starts playing a godot game that was developed using the native camera node, and moving charcters with _fixed_update, they'll notice a lot of jitter. So it's essential!
Maybe there should be engine support for interpolating visuals?
It's a possibility, but it's really difficult without being able to see the problem. My intuition tells me jitter should not be visible, and that it might be something else that is at fault
On Sun, Jul 9, 2017 at 2:12 PM, raymoo notifications@github.com wrote:
Maybe there should be engine support for interpolating visuals?
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/godotengine/godot/issues/9561#issuecomment-313932610, or mute the thread https://github.com/notifications/unsubscribe-auth/AF-Z26FvOZrIFnzhZhOmOwZ6uFSGky2Uks5sMQn6gaJpZM4ORui1 .
I get very little / no jitter when running at 144 fixed FPS on my 60Hz monitor. I can't test the other way around since I don't have a high refresh rate monitor.
Okay. I need someone to test this for me please. Sorry for the big download:
https://drive.google.com/file/d/0B0bKTHkpn7NZZGRQdWt4dDVoNGs/view?usp=sharing
It's shipped at 144 fixed_fps with vSync on. I tried it on my 60hz monitor, and there is jitter, but it's only because of the human eye phenomena (from going to 144 to 60).
On my 144hz monitor though, there is no jitter so that's good.
I need someone who is using a 60hz monitor, to test this and move around with WASD and see if there is any jitter.
If there is jitter = something bad
If there is no jitter for 60hz monitor users. Then that means you must ship godot with fixed_fps to be a value of whatever your gamedev machine's monitor is running at AND a value you think is the highest used for your playerbase?
@Dillybob92 Could you export a Linux build? I don't have a Windows machine.
@raymoo yep np, done:
https://drive.google.com/file/d/0B0bKTHkpn7NZUE5GWVVWRFhLNlU/view?usp=sharing
@Dillybob92 It is a bit jittery for me. Could you export a 60FPS version too so I can make sure it's because of the FPS difference?
Yep. Here is fixed_fps set to 60:
https://drive.google.com/file/d/0B0bKTHkpn7NZaGxDV2lnYmt2OUU/view?usp=sharing
I get lag spikes in both but the 60 fixed_fps one is definitely smoother when there are no lag spikes.
Thank you raymoo for testing them.. I am unfortunately stumped lol. I don't know how ship a godot game that works with all monitor refresh rates..
It seems like if I change it to 144 fixed_fps, it's smooth for 144hz monitor users, but jittery for 60hz users.
If I change it to a fixed_fps to 60, it's smooth for 60hz users, but jittery for 144hz users
There has to be something going on internally?
Well I'm guessing at least that 60FPS on 144Hz will be smoother than 144FPS on 60Hz since with 60->144 at least you won't be skipping any fixed frames when displaying.
@reduz, this would be a good solution, right?
Use Globals.set("physics/fixed_fps", MONITOR_REFRESH_RATE)
. -- Then, we won't have to worry for each individual user's refresh rate?
And if using delta
for movement in _fixed_process
, it will be the same experience for all.
Win Win?
And if using delta for movement in _fixed_process, it will be the same experience for all.
Not really true, especially for second-order movement effects like acceleration, if implemented with ordinary Euler integration. Euler's method becomes more accurate (closer to how an object experiencing that acceleration would actually move) with smaller timesteps, so you will have different behavior on 60Hz and 144Hz. For example, a ball on a ballistic trajectory will travel farther with a larger timestep.
There is also the issue of anything that is supposed to happen on an interval not divided evenly by both 1/60 and 1/144. The frames they happen on will be uneven in different ways on both setups.
Yeah good point, you are right
With that said, I'm about done with this though, I have no idea what I am talking about half of the time because this shit is so far beyond my scope of knowledge. All I know is that I cannot find a way to ship my game that works smoothly on all monitor refresh rates. I'm getting really frustrated not at you guys, but at myself. I'm just stumped and honestly I'm giving up with all of this.
that is just how physics works, solutions adopted by other engines:
i) separate the entity's physics node and view node (ie. make them siblings) and use a script to set the rendered node's position through interpolation/extrapolation in _process (the Unity way...) ii) make them kinematic and move manually in _process (UCharacterMovementComponent...)
Again, I think this should not be too difficult to add to Godot so it happens automatically on most objects (fixed step interpolation) problem is, I have no test hardware.
On Fri, Jul 14, 2017 at 8:23 PM, tamkcr notifications@github.com wrote:
that is just how physics works, solutions adopted by other engines:
i) separate the entity's physics node and view node (ie. make them siblings) and use a script to set the rendered node's position through interpolation/extrapolation in _process (the Unity way...) ii) make them kinematic and move manually in _process (UCharacterMovementComponent...)
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/godotengine/godot/issues/9561#issuecomment-315490003, or mute the thread https://github.com/notifications/unsubscribe-auth/AF-Z23OLUdRCGLL3DwwO3JznggBWEOuBks5sN_iNgaJpZM4ORui1 .
on a 60hz monitor a physics fps of ~25 (or any lower than 60 number) should recreate the effect (amplified)
@tamkcr thanks i just implemented your option #2.
@reduz, understood. if I could ship u a 144hz monitor i would.
@raymoo, here is the movement with a kinematic body using move
with delta
inside _process
.
It's smooth as butter on my 144hz monitor. if you have a chance, please try this on your 60hz monitor
https://drive.google.com/file/d/0B7tVcnnVmWAWdk9sdmwzbjJkZmc/view?usp=sharing
i just tested this on a 23hz monitor and if i hold down D and wait 3 seconds I am still in the same place as playing on a 144hz monitor. Why is that, when there is still different delta times?
I thought different delta times is a bad thing. How can the character be in the EXACT same place when it's multiplying by different deltas?
@Dillybob92 It's smooth for me too (except for lag spikes)
I would say it's behaving similarly because all movement is linear. Euler integration works perfectly if you have a fixed velocity. Maybe you could try making some motion with an acceleration that has a strong effect (no capped velocity, high acceleration).
@raymoo
Okay, it seems like the solution is to use a kinematic body and move
under _process
as tamkcr alluded to.
I also found that using the Camera2D
when moving a kinematic body under _process WITH a 144hz monitor will cause jitter. This is because I believe Camera2D is updated at a fixed_fps of 60 by default. If I change fixed_fps
to 144, the Camera2D is smooth. However, that means for 60hz monitor users it will be jittery. Thus, if anyone sees this issue, use my code above and you will see no jitter on 144hz and 60hz monitors
Thank you so much raymoo for the testing.. We need to get reduz a 144hz monitor fast lol
e: I got the viewsonic xg2401 for only $189 off Amazon refurbished. Cheapest one that I think that is out there
@Dillybob92 Have you tested it with nonlinear movement?
@raymoo Like diagonal? Yep just tested that now, held down S+D for 2 seconds. Reached the same spot on the map for both 25hz and 144hz monitors
Code:
var direction = Vector2()
var speed = 15
func _process(delta):
if player_states.right:
direction.x = speed
if player_states.down:
direction.y = speed
if player_states.left:
direction.x = -speed
if player_states.up:
direction.y = -speed
if is_colliding():
var n = get_collision_normal()
direction = n.slide( direction )
velocity = (direction * speed) * delta
if get_global_pos().x > 0 and get_global_pos().y > 0:
move(velocity)
direction.x = 0
direction.y = 0
No, non-linear meaning the velocity changes over time, like a ball that accelerates downward.
not much reason to test that, when its kinematic only the scripts are moving it and the consistency becomes purely implementation specific, i.e. not related to this issue. (sometimes networked games faces a somewhat similar problem as net code updates at a different, variable rate)
@tamkcr Any code that does
velocity += acceleration * delta
move(velocity * delta)
etc will be affected.
that's the point, we already know such implementation will be affected and is not related the issue concerned, so let's not derail.
@tamkcr What implementation of acceleration (controlled by input) would not be affected? It's not unrelated to this issue because you get consistency if you have a fixed timestep.
e.g.(pseudo code) if W_is_pressed: set_pos(last_still_position + move_direction * (acceleration * (min(current_time - time_W_is_pressed, time_needed_to_max_speed)^2) / 2 + max_speed * max(0, (current_time - time_W_is_pressed - time_needed_to_max_speed)))
, this is an analogy to how some networked games implement movement abilities as packets arrive at different and variable rates. in single player there will still be slight error from when time stamps can be polled but it would not accumulate as much.
I say this is not related because the issue concerns on how position is read during the update loop for nodes managed by the physics engine, which I believe is provided "as is" currently. If you move nodes manually in _process the script should have full control and so bear responsibility to tackle these problems (you can recreate a fixed loop in it, ue4 does that for character movement IIRC).
@tamkcr Ok. It doesn't handle instantaneous velocity changes or if the player was moving already when they hit a key, but I see how it could be extended to cover those cases.
This issue though doesn't concern specifically how position is read, it is looking for a way to have a game look smooth on both 60Hz and 144Hz monitors. The reason I brought up differences caused by different timesteps was to argue that "just move movement to _process" would cause different behavior on different configurations. I had not considered an exact solution to movement, though, so thank you for bringing that up. However, doing it that way is significantly more complicated for the programmer, so interpolation between fixed frames would still be useful to have.
good movement code is bound to be complicated, that is why the physics system is there to assist us. yes optional interpolation between fixed frames is likely the best out-of-the-box solution, but it should be there only for movements happened in fixed loops.
if we write a script to move something in a jittery / inconsistent manner directly it should be jittery / inconsistent, as intended. if you dont want to face the complexity of moving things objects then use the physics tools, the solution is already there (fails in certain setups currently which is why this issue is reported).
@tamkcr Okay, it doesn't seem like we disagree.
reduz:
Probably you can change your monitor refresh rate to 75 hz or other rate in driver configuration and see the problem.
I have 2 screens, one at 60 hz other at 75 hz, when i execute my prototype and init the profiler it shows that godot leave empty frames when the game is in the 75 hz monitor, if the game screen is in the 60 hz monitor it´s ok. In 75hz the camera travelings are jerky. Animations and particle systems with no camera movements look equally and do not have perceptibly effect. This is at 75hz, I suppose that 144 hz should do more jittering.
@davarrcal Maybe just camera interpolation is enough then?
I don´t think so.... it´s something deeper. In my game probably camera interpolation it´s ok, because there is a lot of movement and particles, but if you execute "car demo", that doesn´t have camera, with the car movement at physics fixed at 60 fps, in the 75 hz monitor there is a continuous nauseating shake in the cars. Their turn fuzzy and jerky. I´m not expert, but i read other similar engines problems and one solution was frame interpolate (but i don´t understand deeply this concept, so I can´t suggest that).
Edit: This problem is not attached to the "stuttering" problem releated to the "car demo", this stuttering happens in both monitors. Maybe the cause is close to this problem and can have a jointly aprroach to the solution... who know´s.
Why close? This is actually a legitimate issue, not the OP doing something wrong.
Bug triage note: The original issue reporter closed all their issues before deleting their account. If you are affected by a similar issue/want a similar feature, please file a new ticket (referencing this one if it contains useful information) so that it can be further looked at and eventually resolved.
I still had this problem with a 100hz monitor in godot 3.0.2 stable. However, adding a late update method that updates camera position after the player has moved fixed the issue for me. This also made the whole game feel smoother 👍
Can you explain your camera "late update" aproach? Would be useful for all....
Basically my latest solution is adding the camera to the bottom of the node tree in every level. Camera is self contained with its own script, so it runs after all other nodes are finished calculating their positions. Would be really easy if godot had several game loops called at different times, like unity, gamemaker studio and monogame to name a few.
For me camera smoothing causes jitters if physics fps < monitor hz (and actual fps is higher than physics). If physics fps is higher than monitor hz then it's fine, but then it's kind of a waste of resources? Being able to adjust physics fps in a similar way to what Juan said here - https://twitter.com/reduzio/status/984783032459685890 would be great. Not sure when it would be implemented though.
I think you can do that now in gdscript... methods are exposed. You can detect engine fps... if you have enabled vsync, godot report to you current fps of current screen... so you can adjust physics fps to match that... i don't know if current proposal involves some other workarounds, but adjust physics fps in runtime is not new thing to the engine, it's only not documented.
Operating system or device - Godot version: 2.1.4, any
Issue description: I just found this nasty issue out after buying a 144hz monitor.
I previewed my game scene and there was a huge jitter when moving. I originally thought it had to do https://github.com/godotengine/godot/issues/2043#issue-85903385
The fix is changing your "fixed_fps" variable under physics to 144. Once you do that, there is ZERO jitter ANYWHERE. It's all gone
The problem is. In godot, there is no way to dynamically and programmatically set this before loading the game.
For example, if I ship my game out at a fixed_fps variable of 144. Only players who have a 144hz monitor will get NO JITTER. Anyone with a 60hz monitor wll experience massive jitter.
For example #2: If I ship my game out at a fixed_fps at 60 or "default" (0), people with a 144hz monitor will experience massive jitter.
I'm suggesting maybe a method that is available in the
OS
class that grabs the refresh rate of the monitor? Maybe that would help? And then godot developers can just call that before loading an extensive physics game world scene, etc.