What I usually do to setup a camera that only rotates around two axes (X and Y) is to write a script that handles the two rotations and applies them in the right order. So quaternions are not necessarily needed.
This script is made for debugging so it also has strafing control, however it works just like any other FPS camera.
The interesting part is how the camera rotates. I get the mouse motion and add X and Y motion to the two angles, then I update the camera’s rotation in a specific order:
# Add to rotations
_yaw -= motion.x * sensitivity
_pitch += motion.y * sensitivity
# Clamp pitch (prevents looking upside-down)
var e = 0.001
if _pitch > max_angle-e:
_pitch = max_angle-e
elif _pitch < min_angle+e:
_pitch = min_angle+e
# Apply rotations
set_rotation(Vector3(0, deg2rad(_yaw), 0)) # First, reset the rotation starting by the horizontal rotation
rotate_x(deg2rad(_pitch)) # Then rotate for the vertical rotation
This way you won’t have issues with the camera rolling.
Note, this is one way of doing it (maybe there are others), I just happen to use it because it works.
OK i find solution
func _input(event):
if event.type == InputEvent.MOUSE_MOTION:
yaw = fmod(yaw - event.relative_x * view_sensitivity, 360)
pitch = max(min(pitch - event.relative_y * view_sensitivity, 45), -45)
get_node(“YawControl”).set_rotation(Vector3(0, deg2rad(yaw), 0)) # here rotate only YAW Spatial node but Camera is a parent then go all
get_node(“YawControl/Camera”).set_rotation(Vector3(deg2rad(pitch), 0, 0))# here rotate Node Camera pitch only