ShapeCast3d/RayCast3D target problems

(Godot 4.2)

Since SpringArm3D doesn’t work for my camera setup, I’ve attached a ShapeCast3D to my player. The shapecast is supposed to cast at the camera’s global position, the camera is child of a helper node which in turn is set to copy the position (not rotation) of the player. By rotating the helper, the camera orbits & looks at the player.
When the shapecast hits something, the camera gets translated towards and/or above the player, depending on the result of shapecast.get_closest_collision_safe_fraction(). If it’s not colliding, the camera’s y position handled in _input() and depends on mouse motion.
This works …kind of. Or it would work really well if the shapecast would consistently target the camera. But it will often just project in a totally different direction (see pics - the shapecast is the sphere), sometimes to really far away points. I can’t figure out why and would be really grateful for pointers.

root
-camera_helper (rotates w/ mouse movement; copies global_position from player)
–camera
—shapecast_target
-player
–look_at_target_helper
—ShapeCast3D

the code for the Shapecast3D is (in _physics_process)

	shapecast.set_target_position($"../../camera_helper/main_Camera3D/shapecast_target".global_position)
	shapecast.force_shapecast_update()
	if shapecast.is_colliding():
		safe_margin = shapecast.get_closest_collision_safe_fraction ()
		if safe_margin < 0.2:
			camera.transform.origin.z = lerp(camera.transform.origin.z, camera_close, 0.05)
		elif safe_margin 	>= 0.2:
			camera.transform.origin.z = lerp(camera.transform.origin.z, camera_default_z*safe_margin, 0.05)
			camera.transform.origin.y = lerp(camera.transform.origin.y, 3.0, 0.01)
	else:
		camera.transform.origin.z = lerp(camera.transform.origin.z, camera_default_z, 0.05)

1 Like

note: I’ve changed the target’s position to be in the ShapeCast3D’s local space like so:
shapecast.set_target_position(to_local($“…/…/camera_helper/main_Camera3D/shapecast_target”.global_position))
…but still no dice. The cast goes all over the place and overshoots the orbit distance.

Hey I have this issue too, my shapecast is in front of my player, and it keeps finding objects that are behind. Have you found a solution?

kind of. It’s a bit convoluted, but putting all related code (movement, camera) in physics_process was the biggest help. Especially the mouse look which moves the camera. I am now calling _input(InputEventMouseMotion) in physics_process, and this helps a lot.
Also, I think dynamically changing the target position doesn’t work. Maybe I’m just misunderstanding how it is supposed to work, but the above + using shapecast.force_shapecast_update() in physics_process and having a fixed target position (in my case the maximum -z distance from the player) via inspector did the trick for me.

1 Like

Hey thanks, that is very helpful. I get an error when using the force update. Do you mind sharing the corresponding code snippet?

I tried this page for learning more but I think this is for gd3

not at all:

func _physics_process(delta):
	_input(InputEventMouseMotion)
	shapecast.look_at($"../../camera_helper/main_Camera3D/shapecast_target".global_position, Vector3.UP, false)
	shapecast.force_shapecast_update()
	if shapecast.is_colliding():
		safe_margin = shapecast.get_closest_collision_safe_fraction ()
		if safe_margin < 0.2:
			camera.transform.origin.z = lerp(camera.transform.origin.z, camera_close, 0.05)
		elif safe_margin 	>= 0.2:
			camera.transform.origin.z = lerp(camera.transform.origin.z, camera_default_z*safe_margin, 0.01)
			camera.transform.origin.y = lerp(camera.transform.origin.y, 3.0, 0.003)
	else:
		camera.transform.origin.z = lerp(camera.transform.origin.z, camera_default_z, 0.05)

	camera.look_at(look_at_target.global_transform.origin, Vector3.UP, false)
	var angle = smoothstep(camera_max_height, camera_min_height, camera.transform.origin.y)
	camera.rotate_object_local(Vector3(1,0,0), deg_to_rad(40.0*angle))
	interpolated_camera.v_offset = -0.9*angle
1 Like

the node setup is like this:

world
-movement_helper(Node3d)
–main_camera
—interpolated_camera_3d
—shapecast_target
[…]
-actors(Node3D)
–player(Node3D)
—player_scene
—look_at_target(Node3D)
----ShapeCast3D

1 Like

oh, and the mouse motion input event function that is called in _physics is:

func _input(event):
# camera orbits player by rotating parent via x-mouse-motion 
	if event is InputEventMouseMotion:
		movement_helper.rotate_y(-event.relative.x * mouse_sensitivity)
1 Like

thank you thank you