Camera2D smoothing looks shaky for low resolution sprites.

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By batmanasb
:warning: Old Version Published before Godot 3 was released.

I’m using a character made of a KinematicBody2D with a 32x32 sprite and Camera2D attached to it. I’ve noticed that when I enable smoothing on the Camera2D to something around 1 through 10, the smoothing effect looks nice when the sprite moves, but seems to shake for about 2 seconds when the character stops moving. The shaking seems to go back and forth and is very noticeable, and there is no shaking when the smoothing is off. This probably results from the low resolution.

Here’s a gif: http://i.imgur.com/2htpeGj.gifv

I’m using godot-2.0-stable on Linux if that makes a difference.

:bust_in_silhouette: Reply From: Doc Angelo

I think it is the effect of low resolution (big pixels) and no filtering. Slow movements result in “pixel jumps”.

A solution would be to enable filtering, but that would destroy the pixel look.

EDIT:
If you mean the 1px gap between the Godot logo and your character, then you might want to take a look at the position values of those. Inspector>Node2D>Transform>Pos(x,y). If both are whole numbers, this gap should not show up anymore.

EDIT2: “whole numbers”, not “even numbers”. But that would have worked also. :slight_smile:

I’m a little confused why that gap even shows up during smoothing but it’s not there without it. It’s as if the Character itself is moving…

batmanasb | 2016-03-06 03:46

You can test this behavior with a simple setup. Put 2 sprites on the screen. Make sure they are on exact pixel positions (even numbers). Move them both quite slowly in the same direction. Make it so slow that it “jumps” 1 pixel per second or so.

If they both have the same starting position (regarding the direction of movement), both will “jump” 1 pixel at the same time.

Now change the starting position of the second sprite. Move it 0.25 pixel in the direction of the movement. Now the second one will “jump” first, then the other - and so on.

Camera smoothing results in a very slow relative movement when the camera comes slowly to a halt. The whole pixel jumping becomes very visible. It looks at least a little more smooth if everything jumps at the same time.

It helps to activate “pixel snap” from the menu of the 2D editor.

Doc Angelo | 2016-03-06 12:19

I think one solution might be to manually set the camera position to (0,0) when it gets close to (0,0) and the sprite isn’t moving. This might get rid of the noticeable shaking, but I can’t find what variable the camera is using to move during smoothing. get_pos(), get_camera_pos(), get_offset(), and get_v_offset() don’t change.

batmanasb | 2016-03-07 01:09

My solution did not fix the issue?

Doc Angelo | 2016-03-07 01:42

I don’t understand your solution. Moving static objects isn’t ideal.

batmanasb | 2016-03-07 05:29

Have you tried looking at the position values?

I corrected my first answer. I meant “whole numbers”, not “even numbers”. English is not my mother tongue.

Doc Angelo | 2016-03-07 10:24

Moving in only whole numbers would look choppy on it’s own, but I understand what you are saying. However, I went ahead and wrote my own smoothing code with a cutoff just before the shaking starts.

batmanasb | 2016-03-07 10:53

You are using use_2d_pixel_snap = On in the project settings, if I see it right from your video. This results in whole number movements (or as I call it “pixel jumps”) regardless what you do. If you move a sprite 0.25 in one direction, the renderer will not show it, because use_2d_pixel_snap will let it snap to a rounded number. If it’s fast enough (let’s say 10 jumps per second or more), it is not visible. When it gets slower, it will be more visible. Especially if one sprite is jumping at frame 1 of 60, and the other at frame 30 of 60. That’s why it is important to keep every Sprite (or its parents) at perfect, rounded, whole position values.

Doc Angelo | 2016-03-07 11:17

Actually use_2d_pixel_snapwas always off.

batmanasb | 2016-03-07 11:23

Have you turned off filtering for those sprites? (Texture Resource Properties > ImageTexture > Flags) It has the same effect.

Doc Angelo | 2016-03-07 12:29

Yeah, filtering is off. At first I imported the spritesheet and turned off filtering, but now I’m just using a PNG.

batmanasb | 2016-03-07 20:14

Just want to say I am having the same issue. I did the Texture Resource → ImageTexture → Flags, and checked filter. The jitterness has stopped (pixel_snap is off). Although, there is a tiny, and I mean now even tinier little jitter (smoothness 6). but it’s barely noticable. Anyways, it’s a lot better than before and will work fine in production. I will try @batmansab code snippet later too. Thanks Doc Angelo!

wombatTurkey | 2016-07-29 23:33

This was from a while ago, and my solution only helped a little. I need to look deeper into this problem…

batmanasb | 2016-07-30 09:11

:bust_in_silhouette: Reply From: batmanasb

Edit: It’s better but still shaky. I still need to find a better solution…

I figured out an acceptable solution. Instead of parenting the camera to the character, I made an independent one in the main scene, then wrote my own smooth following code based on what was explained in this Unity Tutorial. The resulting code worked identically to the built in method (still shaky when the character stops), so I added a cutoff (set to 20.0 in my script) that works similarly to drag margins. So the camera stops following when it gets within the cutoff distance, which I set to just as the shaking starts. Here’s the code:

func _fixed_process(delta):
    if(target):
		var x = lerp(get_pos().x, target.get_pos().x, lerpRate*delta)
		var y = lerp(get_pos().y, target.get_pos().y, lerpRate*delta)
		var pos = Vector2(x,y)
		if(pos.distance_to(target.get_pos()) > cutoff):
			set_pos(pos)