"transform.basis = Basis()" or else ?

Godot Version

4.5.1 stable

Question

sorry if this was asked before .. im new here
In fps/tps camera tutorials, you should rotate only the camera (on X axis) and whole player (on Y axis) based on how much mouse moved on screen (screen_realtive).
Some tutorials (like brackeys “How to make 3D Games in Godot” tutorial) say that you must reset the basis (rotation & other things) to zero before executing the actual rotation code line (rotate_x & rotate_y) and some (well, they are not few tbh) say the opposite BECAUSE IT CAUSES JITTERNESS ON LOW SPEC PCS and that its a bad code habit. so .. is transform.basis = Basis() bad or good? and if its bad, whats the ultimate solution ?

brackeys 's proto-controller looking around code (from: “How to make 3D Games in Godot” yt vid) :

## Rotate us to look around.
## Base of controller rotates around y (left/right). Head rotates around x (up/down).
## Modifies look_rotation based on rot_input, then resets basis and rotates by look_rotation.
func rotate_look(rot_input : Vector2):
	look_rotation.x -= rot_input.y * look_speed
	look_rotation.x = clamp(look_rotation.x, deg_to_rad(-85), deg_to_rad(85))
	look_rotation.y -= rot_input.x * look_speed

	transform.basis = Basis() # <<<<<<<<<<<<<<<<<<< HERE

	rotate_y(look_rotation.y)

	head.transform.basis = Basis() # <<<<<<<<<<<<<< HERE

	head.rotate_x(look_rotation.x)

That seems odd and unnecessary to me unless either something is going on under the hood (like, say, calling rotate_y() takes the old y rotation into consideration), or it’s trying to clear out other rotations from (say) screen shake.

I’d try without and see if it makes a difference. You can always put it back if you need to, but it’s very easy to wind up with “dunno what this magic thing is for” scattered through your code. Unless you can demonstrate you need it (do you maybe have a crappy old laptop around somewhere you can test on?) I’d suggest getting rid of it.

It’s certainly strange to update this transform twice per rotation where one assignment (per rotation) would do.

rotation.y = look_rotation.y
head.rotation.x = look_rotation.x

Then similarly why have look_rotation if it’s only purpose is to be assigned to rotation on the same frame

func rotate_look(rot_input: Vector2) -> void:
	const MAX_PITCH = deg_to_rad(85)
	head.rotation.x -= rot_input.y * look_speed
	head.rotation.x = clamp(head.rotation.x, -MAX_PITCH, MAX_PITCH)
	rotation.y -= rot_input.x * look_speed

Brackey’s code may be very slightly less efficient but I don’t see how it would jitter, maybe others are implementing it wrong, in part because it’s extra components are confusing.

1 Like

I am working on a similar problem.

In the Godot documentation it states:

Doing successive operations on transforms will result in a loss of precision due to floating-point error. This means the scale of each axis may no longer be exactly 1.0, and they may not be exactly 90 degrees from each other.

If a transform is rotated every frame, it will eventually start deforming over time. This is unavoidable.

you can read the relevant section here

Setting transform.basis = Basis() resets the rotation to prevent precision errors.

To prevent the camera jitteriness, I have just started working on solving this for my own game, but what I have discovered so far:

In project settings under the physics tab there is a setting (this might be a new setting in Godot 4) called physics interpolation. By enabling this, the engine will interpolate the transform of physics objects between physics frames (so they no longer jitter if the physics tick and game tick are out of sequence).

To take advantage of this, you will need to update the rotation of the player and camera for the FPS in the physics process function.

My technique so far has been to create a new variable on the player called mouse_look_input of type Vector2 and I accumulatively add event.relative in the unhandled input function. I.e

# _unhandled_input function where you get the mouse input
mouse_look_input += event.relative

Then inside the physics process I put:

if mouse_look_input:

    # Do aim code here

    mouse_look_input = Vector2.ZERO

This way the engine will handle all the smoothing and you’ll get a consistent experience on different hardware. You can test this by setting the physics tick to something low like 10 and you’ll still have smooth camera.

Hope this helps!

Edit:

It seems there is a more appropriate way to handle the camera using physics interpolation than updating it in the physics process function. That way it will still be responsive to user input:

1 Like

thank you .. it turns out that brackeys put the camera rotation code in _unhandled_input() function i didn’t understand the video you posted but i just put it as you did: getting screen.relative (mouse movement) in input and actually rotating the camera in _physics_process() and BOOM! it became smoother without jittering and it was a very huge difference without even trying the physics interpolation (which i couldn’t figure out)… so just putting movement of player and camera in physics process is the ultimate solution as resetting the basis is maybe a must-do thing in godot

If you are still interested in this, I made a basic first person controller using physics interpolation. The camera is dead smooth even if the physics tick rate is low.

GitHub repository is here.

1 Like