Rotating player head based on mouse position?

Godot Version 4.3(3d)

I’ve seen somewhat similar questions but none seem to answer my problem well or I just don’t understand :confused:

Essentially, I’ve been trying to get a node(3d) to rotate in response to a mouse position on the screen which would move the head up and down. I’ve seen many tutorials on youtube use raytracing from the camera onto a plane and then use the look_at function to turn a node or object but it’s just kind of funky and doesn’t really “look at” the mouse position, it kind of gets cockeyed and then pivots around? It also doesn’t help that all of the tutorials I find are from older versions so I have to alter their tutorial code and I don’t fully understand what is happening since they dont explain the nitty gritty of what is being done…

My other solution was to use that same raytracing system to place an invisible node where my mouse should be and use the look_at function for that but I can’t figure that out either…

All of my code is garbage and I’ve just trashed it so there’s nothing I can show but if anyone has any tutorials or solutions I should look into for this particular idea I would greatly appreciate it!

I do it like that:

var rotation_speed: float = 0.005
func _unhandled_input(event: InputEvent) -> void:
	if event is InputEventMouseMotion:
		var mouse_motion_event: InputEventMouseMotion = event as InputEventMouseMotion
		rotation.y -= mouse_motion_event.relative.x * rotation_speed
		head.rotation.x -= mouse_motion_event.relative.y * rotation_speed
		head.rotation.x = clampf(head.rotation.x, PI/-2, PI/2)

You just need to have a separate child Node3D for “head” pivot so that they both can rotate in 2 axis independently, otherwise it’s hard to synchronize rotation in both axis on one node.
This way you have a first-person-like movement.

I realized last night that my post was not as specific as I should ahve made it but I couldnt edit it during the approval process :confused:
This does solve the first person movement issue but unfortunately I’m working in 3rd person.

I essentially want to move the mouse around the screen and have the head rotate to track it
I was sleep deprived last night when i was making the original post, thanks for the help though!

Ok, gotcha. Then the look_at() function is definitely the correct approach. Only the raycasting from Camera position is a bit complicated, but it can be done - see below my ugly demo.

This is the scene structure:

This is the script on the Head node:

extends Node3D

const RAYCAST_LENGTH: float = 1000.0

func _physics_process(delta: float) -> void:
	var space_state = get_world_3d().direct_space_state
	var camera: Camera3D = get_viewport().get_camera_3d()
	var mouse_position = get_viewport().get_mouse_position()
	
	var origin = camera.project_ray_origin(mouse_position)
	var end = origin + camera.project_ray_normal(mouse_position) * RAYCAST_LENGTH
	var query = PhysicsRayQueryParameters3D.create(origin, end)
	
	var result: Dictionary = space_state.intersect_ray(query)
	
	if result != {}:
		look_at(result.position)

You can find a bit more information about raycasting here:

3 Likes

This does mostly what I wanted, so thank you!
Is there any way to put restrictions on how far the head will tilt for the look_at?

this is what I have. I want the head to stop tilting at a certain height…

extends MeshInstance3D
const RAYCAST_LENGTH: float = 1000.0
@onready var head: Node3D = $".."
@onready var info: Label3D = $"../Info"

func _physics_process(delta: float) -> void:
	var space_state = get_world_3d().direct_space_state
	var camera: Camera3D = get_viewport().get_camera_3d()
	var mouse_position = get_viewport().get_mouse_position()
	
	var origin = camera.project_ray_origin(mouse_position)
	var end = origin + camera.project_ray_normal(mouse_position) * RAYCAST_LENGTH
	var query = PhysicsRayQueryParameters3D.create(origin, end)
	
	var result: Dictionary = space_state.intersect_ray(query)
	
	
	if result != {}:
		var lookcursor = Vector3(result.position.x,result.position.y,0)
		head.look_at(lookcursor)```

You can clamp rotation on the X axis afterwards, e.g. this will make it tilt only ±45 degrees up or down.

	if result != {}:
		var lookcursor = Vector3(result.position.x,result.position.y,0)
		head.look_at(lookcursor)
		head.rotation.x = clampf(head.rotation.x, -PI/4, PI/4)
2 Likes