# How would I get the closest point on a Curve3D in world space?

Attention Topic was automatically imported from the old Question2Answer platform.

get_closest_point works in the curve’s local space but I need to be working in world space, so somehow I need to be able to transform a point between the two.

I don’t think a PathFollow will work for what I have in mind since it takes a scalar offset (Between 0 and 1) and what I’m trying to accomplish is to have a camera clamped to a figurative rail (A Curve3D from a Path node in this case) and I need to find where on this rail is closest to an arbitrary position such as a player.

I found this question yesterday when I was searching for a solution to the same problem, and decided to leave this tab open in case I figured it out.

I’m no Godot expert, so this might not be the best way to do this, but it’s working for my use case, and might help you get where you want to be.

First I want to bring something about PathFollow to your attention. You say the problem is that it takes a scalar for its offset, which it does as `unit_offset`, but there is also a property for its actual offset (just called `offset`) which is as long as the path.

I’m also using `get_closest_offset()` instead of `get_closest_point()` because it will return something I think is easier to work with.

To solve the problem of converting the Player’s World Space to the Path’s Local Space to be able to use `get_closest_offset()`, I made a Position3D as a child of the Path, called it `follow_target`, then in `_physics_process()` matched it’s `global_transform.origin` to the player:

``````follow_target.global_transform.origin = player.global_transform.origin
``````

Then I get the translation (i.e. local space) of the `follow_target` and use that to `get_closest_offset()` of the path.curve, and set it as the PathFollow’s offset.

``````path_follow.set_offset(path.curve.get_closest_offset(follow_target.get_translation()))
``````

This works fine for straight paths, and probably works for linear paths that don’t double back on themselves, but if you have a horseshoe-shaped camera path (which I did), it can make the PathFollow rush from end to end (i.e. the player can be closest to the beginning of the path, then closest to the end of the path without passing through any of the intermediate points).

To solve this, I created a second path, which I called `reference_path`, which is a straight line from the beginning to the end of the path I want to lock the camera to.
Then I use the above code to set the offset on the `reference_path`, then copy the `unit_offset` of the PathFollow on the `reference_path` to the `unit_offset` of the PathFollow on the `camera_path`.
N.B. using `unit_offset` for this part because the paths are different lengths, so their regular offsets won’t match up.

So that whole script keeps a PathFollow in the position I want the camera, and looks like this:

``````extends Spatial

func _physics_process(_delta: float) -> void:
follow_target.global_transform.origin = player.global_transform.origin
reference_path_follow.set_offset(reference_path.curve.get_closest_offset(follow_target.get_translation()))
path_follow.set_unit_offset(lerp(path_follow.unit_offset, reference_path_follow.get_unit_offset(), 1))
``````

Then I pass the `path_follow` to my CameraRig as `rails_cam_position`, and in the `_physics_process()`, I lerp from the `camera_rig.global_transform.origin to the rails_cam_position.global_transform.origin`.

``````func physics_process(delta: float) -> void:
camera_rig.global_transform.origin = Vector3(lerp(camera_rig.global_transform.origin, camera_rig.rails_cam_position.global_transform.origin, 10 * delta)
``````

My camera uses `look_at()` to always face the player, so none of this code takes the path’s rotation into consideration, so if you get weird rotation issues, you’ll want to tinker with your PathFollow’s Rotation Mode settings, I guess.

This worked really well for me. Thanks!

jmtstorres | 2020-08-28 13:46

This is very old but I just googled this myself as I didn’t know Curve3D had `get_closest_offset()`. The original answer to manage local space / world space is very ingenious but this can be done in one line just by multiplying in global vector by the curve’s inverse transform matrix (because maths):
``````func get_offset():