Properly clamping the mouse delta

I’m working on my view model for my FPS system and I ran into an issue regarding clamping the mouse delta. The mouse delta is being used as a way to add sway when you move your camera. The only issue is you can’t directly clamp the value. It’s being updated every frame, but the mouse delta’s quantitative size can change with the framerate.

Think about it: if the framerate is really low, the game sees the amount you moved your mouse that frame to be very large. If the framerate is high, this value will shrink as you’re checking the mouse delta more often. If you multiply by delta time, it ends up creating an inconsistent result across different framerates.

I do, however, want to limit how far the sway can make the view model physically move, so that it doesn’t move off screen. What’s the best way to go about this?

3 Likes

When you get the mouse delta, use the deltatime parameter in the runservice heartbeat function and use this equation: mousedelta/deltatime * camerasway factor

This isn’t really what I’m trying to accomplish. The issue isn’t that I need to clamp the physical distance it can move with respect to the framerate. If you need me to clarify my explanation in the original post, let me know.

Im pretty sure that his solution would work if you just added in the clamp statement
If Im understanding correctly, hes just telling you how to turn the mouse delta into a useful value that can be compared to your maximum rate

Youd probably do something like

math.clamp(mousedelta/deltatime * cameraswayfactor, -maxrate, maxrate)

UserInputService:GetMouseDelta() returns a Vector2. I assume that you’d take each component and put it in place of the “mousedelta” variable in your code sample?

Yeah, you should be able to do all of the math on the vector2 up until the clamp, when youll have to split and reconstruct it

Unfortunately, the result of implementing this was the same issue I described in my original post. At high FPS (what the constants are configured to) the movement produced is just right. At lower FPS (say, 15, which is what I tested at coming from a few hundred FPS) the movement was nonexistent.

Maybe instead of using deltaTime with the actual mouse delta, it should be implemented in some constants? This wouldn’t make them constants anymore, but they would scale with framerate.

So Ive done a bit of testing, and it seems like this is the proper answer:

The relation between delta mouse and the rate which I mistakenly thought was the answer is:

deltaMouse (pixels per frame) / deltaTime  (seconds per frame) = rate (pixels per second)

But theres also another relation youre making which throws a monkey wrench into things which was the confusion:

deltaMouse (pixels per frame) * cameraswayfactor (sway per pixel) = swayFrame (sway per frame)

You want to limit the sway per second, so you can just convert it by multiplying it by the framerate (the same as dividing by deltatime)

swayFrame (sway per frame) / deltaTime (seconds per frame) = swayRate (sway per second)

So we know both of the rate values and we can now compare them

local clampedSwayRate = math.clamp(deltaMouse * cameraswayfactor * 1/deltaTime, -maxSwayRate, maxSwayRate)

Now you need to convert this rate into a per frame value by doing:

clampedSwayRate (sway per second) * deltaTime (seconds per frame) = clampedSwayPerFrame (sway per frame)

So the final Lua code would be (in its simplified form) something like:

local clampedSwayPerFrame = Vector2.new(
    math.clamp(deltaMouse.X * cameraswayfactor, -maxSwayRate * deltaTime, maxSwayRate * deltaTime),
    math.clamp(deltaMouse.Y * cameraswayfactor, -maxSwayRate * deltaTime, maxSwayRate * deltaTime)
)

This is a test of this system with a preset mouseDelta of (15,0), maxswayrate of 5 and sway factor of 2
You can see how the black arrow, representing the sway per frame goes up and down to set a constant rate of 5 (which is what my max rate is)

This is a freeform test with my mouse movement

3 Likes

Awesome! This was exactly what I was looking for. Nice work.

2 Likes