0

How do I get the 3D mouse position in godot 4.1? Every thing ive tried dosent work and all the YT toutorials don't work!

I've tried to use documentation and YT toutorials. And i expected it to work!!!

I think its a problem with intersect_ray() function in godot because it only allows 1 argument instead of 2.

1 Answers1

0

You must be looking at Godot 3 tutorials. Be aware that since Godot 2 was very niche, many Godot 3 tutorials released before Godot 4 do not specify for which version of Godot they are.

About the documentation: you can the version of Godot for which you are reading the documentation in the bottom left, and also in the URL.


As per intersect_ray, the concept is the same, but the API is different. In particular: in Godot 3 intersect_ray takes many optional arguments. Bug for Godot 4 they were unified into an object.

So in GODOT 3 you would be doing something like this:

var space_state := get_world().direct_space_state
var result := space_state.intersect_ray(origin, end)

You can look at the documentation for intersect_ray in Godot 3 for the extra parameters. The article Ray-casting (in Godot 3) has further explanation.

The same in GODOT 4 would be like this:

var space_state := get_world_3d().direct_space_state
var query := PhysicsRayQueryParameters3D.create(origin, end)
var result := space_state.intersect_ray(query)

You can look at the PhysicsRayQueryParameters3D class for the extra properties. The article Ray-casting (in Godot 4) has further explanation.


To get the position in 3D the mouse is hovering over in Godot 4, you first need to get the mouse position and the current Camera3D:

var viewport := get_viewport()
var mouse_position := viewport.get_mouse_position()
var camera := viewport.get_camera_3d()

Then we can get the origin and direction of the ray for that point:

var origin := camera.project_ray_origin(mouse_position)
var direction := camera.project_ray_normal(mouse_position)

Since we need origin and end, we compute end using the origin the direction, and some maximum length for the ray... Let us use far from the Camera3D for the length of the ray:

var ray_length := camera.far
var end := origin + direction * ray_length

And, of course, let us use intersect_ray:

var space_state := get_world_3d().direct_space_state
var query := PhysicsRayQueryParameters3D.create(origin, end)
var result := space_state.intersect_ray(query)

And, of course, read the position:

var mouse_position_3D:Vector3 = result["position"]

Which reminds me, if there was no intersection, you get an empty Dictionary, let us deal with that:

var mouse_position_3D:Vector3 = result.get("position", end)

Here if the result is empty (and thus, does not have a "position" key) you get the end of the ray as position.


Know that if you want to deal with this by other means, you can check if the result is empty instead:

var mouse_position_3D := end
if not result.is_empty():
    mouse_position_3D = result["position"]

Also, you can write result.position instead of result["position"], but I'm using the latter here to highlight that it is a key in a Dictionary.


You can, of course make the code shorter (I broke it into simple steps for the explanation). You could use a more sensible ray length. And perhaps cache viewport so you don't have to get it every call... (you only would need to get it when the Node where this code is running enters the scene tree).

In fact, you can use get_world_3d on the Viewport, in case you don't want to run this code on a Node3D:

var space_state := viewport.get_world_3d().direct_space_state

And, of course, you can configure PhysicsRayQueryParameters3D to exclude objects, to intersect areas in addition (or instead of) bodies, and to have an specific collision mask.

Theraot
  • 31,890
  • 5
  • 57
  • 86