Camera Jitter using Lerp - Instances and Surfaces

Moth27

Member
I discovered something while building a very smooth camera and using the lerp function.
It seems the camera will jitter as it gets very close to the object its following if the lerp value is below 1.0
Mine is 0.05
I began to solve this by using "div" instead of "/" in any division calls inside the camera scripts, however surfaces and instances would sort of displace for a few frames as the camera was in its final few frames of settling. They appeared to be jumping/jittering around.

I solved this issue with the surfaces by simply calling their attach points from inside the camera object, but the instances continued to "jump/jitter" around a few frames.

I found a way to stop this today by simply using floor(x) and floor(y) in all the draw functions of every instance and surface on screen.
For example, instead of:
draw_sprite(sprite,index,x,y);

I'm using:
draw_sprite(sprite,index,floor(x),floor(y));

This has completely solved the jitter issue and the camera is ultra smooth now.
Im curious as to why this works. It seems this could have been built into the draw_sprite functions. Any thoughts?
 

TsukaYuriko

☄️
Forum Staff
Moderator
It works because it is not specified how something is drawn "in between" pixels. There are only full pixels. How to render stuff drawn to partial pixels is up to the hardware to determine, and this may differ between different hardware.

It could have been built into the draw functions for sure, but what if someone wants to draw to partial pixels for whatever reason? Then they're stumped. This way, everyone can use them however they want.
 

Cpaz

Member
This is a good catch. I've been wondering about the sprite/camera jitter I'd see on occasion.
Personally, I would appreciate if there was an game setting you could set to only draw on floored/rounded pixels.
I kinda get why they don't do that, but so I don't have to go through and change every single draw_self/draw_sprite, it would be massively convenient.
 

TsukaYuriko

☄️
Forum Staff
Moderator
You can theoretically override default functions like this:
GML:
__original_draw_text = draw_text;

function draw_text(x, y, string)
{
    __original_draw_text(round(x), round(y), string);
}
Plopping that in a script will effectively round all drawn text. Do the same for draw_sprite and the rest of that family and you also have all sprite draws rounded.

That's the theory. In practice, I don't recommend doing this as it's one of those situations where you define something, forget about it and then it bites you in the back later when it affects something it's not supposed to affect. What I'd suggest instead is this, which should be pretty self-explanatory:

GML:
function draw_text_rounded(x, y, string)
{
    draw_text(round(x), round(y), string);
}
... and then you just use those variants instead of the defaults whenever you want them to be rounded. Shows up in autocomplete, saves you from typing round(...) twice for every drawn thing, doesn't break anything internally or in your future code.
 

Moth27

Member
It works because it is not specified how something is drawn "in between" pixels. There are only full pixels. How to render stuff drawn to partial pixels is up to the hardware to determine, and this may differ between different hardware.

It could have been built into the draw functions for sure, but what if someone wants to draw to partial pixels for whatever reason? Then they're stumped. This way, everyone can use them however they want.
Ah yes, this makes a lot of sense.
 

Moth27

Member
This is a good catch. I've been wondering about the sprite/camera jitter I'd see on occasion.
Personally, I would appreciate if there was an game setting you could set to only draw on floored/rounded pixels.
I kinda get why they don't do that, but so I don't have to go through and change every single draw_self/draw_sprite, it would be massively convenient.
haha convenient indeed!
 

Moth27

Member
You can theoretically override default functions like this:
GML:
__original_draw_text = draw_text;

function draw_text(x, y, string)
{
    __original_draw_text(round(x), round(y), string);
}
Plopping that in a script will effectively round all drawn text. Do the same for draw_sprite and the rest of that family and you also have all sprite draws rounded.

That's the theory. In practice, I don't recommend doing this as it's one of those situations where you define something, forget about it and then it bites you in the back later when it affects something it's not supposed to affect. What I'd suggest instead is this, which should be pretty self-explanatory:

GML:
function draw_text_rounded(x, y, string)
{
    draw_text(round(x), round(y), string);
}
... and then you just use those variants instead of the defaults whenever you want them to be rounded. Shows up in autocomplete, saves you from typing round(...) twice for every drawn thing, doesn't break anything internally or in your future code.
wow this is a great idea! I’m going to try it.
 
Top