I am trying to project a ray from the mouses camera position to the world to select and interact with objects but i can’t get the projection right.
here is my code:
func _init_mouse_line():
mouse_line = Game.debug_line(Vector3.ZERO, Vector3.ZERO, Color.BLACK)
mouse_point = Game.debug_point(Vector3.ZERO, 0.05)
func get_mouse_pos():
var space = get_world_3d().direct_space_state
var mouse_pos = get_viewport().get_mouse_position()
var ray_length = 1000
var ray_origin = camera.project_ray_origin(mouse_pos)
var ray_end = ray_origin + camera.project_ray_normal(mouse_pos) * ray_length
var params = PhysicsRayQueryParameters3D.create(ray_origin, ray_end)
params.collide_with_areas = true
raycast_result = space.intersect_ray(params)
if !raycast_result.is_empty():
var mouse_line_immediate_mesh = mouse_line.mesh as ImmediateMesh
mouse_line_immediate_mesh.clear_surfaces()
mouse_line_immediate_mesh.surface_begin(Mesh.PRIMITIVE_LINES)
mouse_line_immediate_mesh.surface_add_vertex(ray_origin)
mouse_line_immediate_mesh.surface_add_vertex(raycast_result.position)
mouse_line_immediate_mesh.surface_end()
mouse_point.position = raycast_result.position
I have a debug point mesh to show the ray collisions and a line from the rays origin and end. Here is a clip of my problem
The collision point follows the mouse but it is not aligned with the mouse the way i want. How do i get the projection to point directly to what is behind the mouse?
Might need more details about how your scene is set up, specifically the hierarchy and transform of related objects, and what the mysterious Game singleton is.
One thing I noticed about your code is that you’re setting the mouse_point.position, which is in local space, but raycast_result.position is in global space.
It seems like you’re using some sort of global singleton to make the mouse_point object, so I assume it is not in a transformed space. But it might be worth trying mouse_point.global_position = raycast_result.position instead.
Make sure that nothing related to these objects is rotated or scaled weirdly.
Also check if the inaccuracy is affected by window size, if it is that might indicate an issue with the viewport’s scaled mouse coordinates.
The Game singleton is pretty much an event bus for other parts of my project, it just where i placed the function to create the meshes for the line and point debug:
func debug_line(point_a: Vector3, point_b: Vector3, color = Color.WHITE_SMOKE) -> MeshInstance3D:
var mesh_instance = MeshInstance3D.new()
var immediate_mesh = ImmediateMesh.new()
var material = ORMMaterial3D.new()
mesh_instance.mesh = immediate_mesh
mesh_instance.cast_shadow = false
immediate_mesh.surface_begin(Mesh.PRIMITIVE_LINES, material)
immediate_mesh.surface_add_vertex(point_a)
immediate_mesh.surface_add_vertex(point_b)
immediate_mesh.surface_end()
material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
material.albedo_color = color
get_tree().root.add_child(mesh_instance)
return mesh_instance
func debug_point(pos: Vector3, radius = 0.1, color = Color.WHITE_SMOKE, persist_ms = 0):
var mesh_instance := MeshInstance3D.new()
var sphere_mesh := SphereMesh.new()
var material := ORMMaterial3D.new()
mesh_instance.mesh = sphere_mesh
mesh_instance.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
mesh_instance.position = pos
sphere_mesh.radius = radius
sphere_mesh.height = radius*2
sphere_mesh.material = material
material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
material.albedo_color = color
get_tree().root.add_child(mesh_instance)
return mesh_instance
I tried your suggestion, changing mouse_point.global_position = raycast_result.position did not have any effect.
The script in my op is attached to the PlayerCamera node, the CameraRoot node moves the horizontal node anf vertical spring arm to move the camera around the player as shown in the video in op.
Here is that script:
@onready var cameraRotation_horizontal = %Horizontal
@onready var cameraSpringArm:SpringArm3D = %Vertical
const springLengthMin = -20
const springLengthMax = -6
@export_range(springLengthMin,springLengthMax) var springLength = -10
var direction: Vector3
var camroot_h = 0
var camroot_v = 0
@export var cam_v_max = 75
@export var cam_v_min = -55
var h_sensitivity: float = 0.01
var v_sensitivity: float = 0.01
var h_acceleration: float = 10.0
var v_acceleration: float = 10.0
var horizontal_camRotation
func _ready() -> void:
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
springLength = -10
horizontal_camRotation = cameraRotation_horizontal.global_transform.basis.get_euler().y
direction = Vector3.BACK.rotated(Vector3.UP, cameraRotation_horizontal.global_transform.basis.get_euler().y)
func _input(event: InputEvent) -> void:
if event is InputEventMouseMotion and Input.is_action_pressed("camera_drag"):
camroot_h += -event.relative.x * h_sensitivity
camroot_v += event.relative.y * v_sensitivity
if event is InputEventMouseButton and Input.is_action_pressed("camera_drag"):
direction = cameraRotation_horizontal.global_transform.basis.z
if Input.is_action_just_released("mouse_scroll_up"):
print("Wheel Up")
springLength += 2
elif Input.is_action_just_released("mouse_scroll_down"):
print("Wheel Down")
springLength -= 2
func _physics_process(delta: float):
self.transform = Game.player.transform
cameraSpringArm.spring_length = lerpf(cameraSpringArm.spring_length, springLength, 0.1)
if springLength < springLengthMin:
springLength = springLengthMin
if springLength > springLengthMax:
springLength = springLengthMax
camroot_v = clamp(camroot_v, deg_to_rad(cam_v_min), deg_to_rad(cam_v_max))
%Horizontal.rotation.y = lerpf(%Horizontal.rotation.y, camroot_h, delta*h_acceleration)
%Vertical.rotation.x = lerpf(%Vertical.rotation.x, camroot_v, delta*v_acceleration)
This whole PlayerCamera scene is attached to my player character and added into the main scene.
One thing i have noticed is that the point aligns with the mouse when its in the top left corner of the screen but gets further away from the mouse when it moves away from the corner.