• Godot Help
  • Stuttering in scene on Ubuntu: Turning off Vsync slightly fixes it. Using Godot4

I'm having an issue with stutter in my Godot scene. It's a very simple setup with just a first-person controller, a plane, and a cube. Strangely enough, when I turn off Vsync in the project settings, the stutter somewhat goes away. But as soon as I turn it back on, the stutter returns.

The stutter happens once every few seconds.

I haven't encountered this problem with my own little C++ OpenGL game engine or when playing games like Cyberpunk 2077. It seems to be specific to Godot (in my case). I haven't had the chance to experiment with any other game engines besides Godot and my own, so I'm not sure if this is a common issue or not.

Some solutions I've tried:

  • Exporting a Release Build. Same stutter every few seconds. The issue happens the same way in the editor and with a exported release build.
  • Turned on "Deploy with Remove Debug" and "Small Deploy with Small Network FileSystem" just because I read the suggestion somewhere on the Internet. Unfortunately no luck.
  • Killed every single program running. No luck.
  • I also read the Fixing jitter, stutter and input lag article in the docs.

This is my setup:
Godot v4.0.1 Stable Official
CPU: i7-8700 @ 3.20 GHz
RAM: 16.0 GB
GPU: GeForce RTX 3070
OS: Ubuntu 22.0.2 LTS (Latest Updates installed)
Desktop Environment: GNOME Version: 42.5
Windowing System: X11
Monitor: 60hz (Not a fancy monitor, but no issues with games)

Thanks for reading! Hope there's a solution because I love using Godot and I do not want to go back to Windows 🙁

I'm afraid we'd need significantly more info than that. How have you architected your game. What does your composition look like. You make heavy use of physics? Where do the stutters occur, in physic or in process or what?

    Megalomaniak

    Hey there Mega, thank you very much for replying to my post. Absolutely, I'd be happy to share more information. I brought my laptop to work just in case.

    I'm actually not using heavy physics, yet. Just the following:

    • CSGBox3D
    • CSGMesh3D (for the floor) with collision on.
    • The Player

    When you mean if the stuttering occurs in _physics_process or _process, I got to be honest, I'm not very sure, but I can share the code below, it's very short. I am calling move_and_slide in _physics_process() though.

    1) Main Scene

    The project starts off with this scene. I'm using a Subviewport | VIewport since I plan on doing some post processing effects. Not yet though.
    You'll notice the PlayerCamera is on its own, however the Player Scene, located in the Sandbox scene, picks up the Camera and uses it.

    Let's look at that real quick:

    As you all can see, my player is not a complicated setup, just a CharacterBody3D and its collider. Let me go ahead and share the code though, it's not very long:

    extends CharacterBody3D
    
    @export var run_speed: float = 3.0
    
    var _current_speed: float
    var _look_axis: Vector2
    var _rotation_velocity: Vector2
    var _direction: Vector3 = Vector3.ZERO
    var _movement_velocity: Vector3 = Vector3.ZERO
    
    @onready var _body_collider: CollisionShape3D = $"BodyCollider"
    @onready var _head: Node3D = $"Head"
    var _camera: Camera3D
    
    func _ready () -> void:
    	Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
    	_camera = find_parent("SubViewport").find_child("PlayerCamera")
    	_current_speed = run_speed
    
    func _input(event: InputEvent) -> void:
    	if event is InputEventMouseMotion:
    		if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
    			_look_axis = event.relative
    
    func _process(delta: float) -> void:
    	_update_camera(delta)
    	_update_direction()
    	_reset()
    
    func _physics_process(_delta: float) -> void:
    	velocity = _movement_velocity
    	move_and_slide()
    
    	_camera.global_position.x = global_position.x
    	_camera.global_position.z = global_position.z
    	_camera.global_position.y = _head.position.y
    	
    func _update_camera(delta: float) -> void:
    	_rotation_velocity = _rotation_velocity.lerp(_look_axis * 0.3, delta * 13.0)
    	_head.rotate_x(-deg_to_rad(_rotation_velocity.y)) # Pitch
    	rotate_y(-deg_to_rad(_rotation_velocity.x))	# Yaw
    	_head.rotation_degrees.x = clamp(_head.rotation_degrees.x, -90.0, 90.0)
    	_camera.global_position.y =  _head.global_position.y
    	_camera.rotation_degrees.x = _head.rotation_degrees.x
    	_camera.rotation.y = rotation.y
    
    func _update_direction () -> void:
    	var move_input: Vector2 = Vector2.ZERO
    	move_input.x = Input.get_action_strength("Move Right") - Input.get_action_strength("Move Left")
    	move_input.y = Input.get_action_strength("Move Backward") - Input.get_action_strength("Move Forward")
    	move_input = move_input.normalized()
    	_direction = transform.basis * Vector3(move_input.x, 0.0, move_input.y)	
    	
    	_movement_velocity = _direction * _current_speed
    
    func _reset () -> void:
    	_look_axis = Vector2.ZERO

    That's all. That' the game so far 😃
    In terms of project settings:

    • I just made sure Vsync is ENABLED which I believe it is by default
    • Viewport Width/Height is set to 1280x720 and the mode is Windowed.
      Physics Ticks Per Second was left at the default 60. Nothing else was changed.

    I also forgot to mention in my post, I ran nvidia-smi in the terminal I get the following:

    NVIDIA-SMI 525.85.05    Driver Version: 525.85.05    CUDA Version: 12.0 

    If you need more information, I can provide anything you need. I'm refreshing this page all the time so I'm here.

    Thanks again!

      DonnieDarko When you mean if the stuttering occurs in _physics_process or _process, I got to be honest, I'm not very sure

      If you look at the profiler in editor when the stutter occurs in the running game instance, there should likely be a spike or some set of spikes in the profiler graph. Which color line do they occur in? You might have to toggle profiling flag to on for specific things on the right side of the profiler.

        Megalomaniak

        Hopefully this is what you're referring to, forgive me if it's not though:

        The bars all look greenish. The other three options (physics and process time) look unticked but before taking the screenshot they were ticked.

        Yes, tick the process and physics time on as well. As follow up later also explore perhaps the Script Functions options.

        Also while the in editor profiler is good to have it is worth noting there are some good alternatives too such as RenderDoc.

          Also worth looking at the monitor tab. And try and see what happens in the game when the spikes occur.

          Mind you it could be as simple as since your project isn't very demanding yet every little thing can cause a relative spike. Once you have more demanding things going on both graphically and with regards to physics the things that are currently noticeable as significant spikes might become just comparatively small noise.

          But getting to know the profiling tools is likely going to come in handy since they can help find out what frame the time spikes were on and help you narrow down where and what might be taking place causing them.

            Megalomaniak

            Got it, just checked! I also updated my previous post with a second screenshot and the spike is in the _process(), huge spike. I also checked the monitor tab and it also seems to point to the process tab.

            I might appear offline, but I'm here. Internet is very poor where I am so I need to switch my modems all the time 😅

              DonnieDarko I also updated my previous post

              So did I. Seems I did so a minute later than you. Looking at the screenshot it doesn't seem to be a script function. At least that's not immediately obvious.

              1 thought though, what if you temporarily moved things out from underneath the viewport/container and hid or maybe even temporarily removed the viewport and container.

                Megalomaniak
                That's a good idea, just did. I completely removed the Subviewport|Viewport stuff and it's an even simpler scene:

                However I get the same stuttering. I tried removing the update_camera function since the profiler is saying the issue is in _process, but same issue.

                That's one thing ruled out, another is to see if the CSG might be causing it. Note: if it is, you can still use CSG meshes and try and see if configuring some properties might affect/improve it or there is also an option to export your CSG mesh as a static one that you can then load into a 3D modeling tool or just import/load back as is into godot as a static mesh.

                  Megalomaniak

                  I just removed all the CSG stuff and imported a GLB of a cube from Blender and unfortunately I still get the stutter. The scene is the Player, PlayerCamera and the cube imported from Blender.

                  Also did a few more things:

                  • I removed all the code from the Player Script, there's only one line which is extends CharacterBody3D and I'm still getting a spike in the profiler.
                  • Removed everything in the scene, so no code, player, meshes, just an empty Node3D and still getting a spike in Process Time, it's clocking at 25 to 65.3

                  Yeah, so it leads me to conclude that it might just be

                  Megalomaniak Mind you it could be as simple as since your project isn't very demanding yet every little thing can cause a relative spike. Once you have more demanding things going on both graphically and with regards to physics the things that are currently noticeable as significant spikes might become just comparatively small noise.

                  Or it could be something in the core of godot that will get fixed in the upcoming releases in which case you have nothing to do until then but just keep working on your project and updating it to newer point releases of the engine until one of them fixes this. But again, it could also be that as your project complexity grows it over takes this and the current stutter you perceive will disappear on it's own as just minuscule background noise.

                  This is why the age old adage is not to optimize early. Seriously read the link, it actually refutes the notion that you shouldn't be concerned with optimization but the point still holds, you also shouldn't get bogged down with trying to optimize something that turns out not to be a real issue at all in the end.

                  If you are really still desperate to test something out though, you can try adding a script to every node in the scene and in the _ready(): set the nodes processing to false. Mind you that would just confirm my background noise theory. By default every node processes, just a node without a script processes nothing.

                  The cost is really tiny, but as I said, if you don't yet have much going on in your project it might seem more significant that it really is.

                    Megalomaniak

                    Understood and thank you for sharing that article btw, I'll 100% give it a read, I was definitely worrying about these spikes too much and I got nothing yet.

                    You did give me an idea when you spoke about future releases fixing these issues. I downloaded Godot 3.x (LTS) and I didn't add anything, just an empty scene and the profiler doesn't seem to spike like I showed you. I'll try making a quick first person controller and test a little more.

                    But you're right, I'll keep working on the project in Godot 4 and wait for future releases.

                    Mega, thanks again for taking the time to help me out. I really appreciate it. Hope you have a great day.