I am trying to get the closest point in the path3d from my object :

Both get_closest_point and get_closest_offset gave me an odd result. Am I doing it wrong ?

extends Node

@onready var path: Path3D = $"../../Path3D"
@onready var pathflw: PathFollow3D = $"../../Path3D/PathFollow3D"
@onready var ball: RigidBody3D = $"../../BallNodePosition/RigidBody3D"
@onready var byLocal: MeshInstance3D = $"../../Path3D/PathFollow3D/ByLocal"
@onready var byPoint: MeshInstance3D = $"../../ByPoint"

func _process(delta):
	var point = path.curve.get_closest_point( ball.global_transform.origin )
	var offset = path.curve.get_closest_offset( ball.global_transform.origin )
	pathflw.progress=offset
	byPoint.set_position( point + path.global_transform.origin )
  • xyz and stranger_anger replied to this.
  • IceBergyn You're passing ball's global position as an argument to get_closest_point(). Docs state that this argument should be in curve's local space. So try:

    var point = path.curve.get_closest_point( path.to_local(ball.global_transform.origin) )

    IceBergyn Those function operate on tessellated/baked linear segments. Try to decrease curve's bake_interval property. It represents the length of an individual linear segment in scene units. The smaller it is, the better the curve approximation.

      11 days later

      IceBergyn I tried that

      Post a minimal project that demonstrates the problem.

        IceBergyn
        Get_closest_offset gives you the baked point on the line that is closest to your desired point.

        If your curve bakes to 10k points, then you'll get back a number between 0 and 10k.

        I solved a similar problem by getting the closest_offset and dividing it by the total number of baked points and setting that to be my path follow's progress_ratio

          stranger_anger Whell, I am just putting the object that is in the path ( child at 0 ) at the progress offset : pathflw.progress=offset , and getting the exact same result as moving using the get_closest_offset, so it dont gives me a diferent result. Did you notice anything odd in your case or it was a perfect move ?

          To show what I was expecting : ( this is not the godot vanilla solution, just what I expect using my own kdtree path solution )

          xyz Following the code, 3 files , file 1 :
          Medtest.tscn

          [gd_scene load_steps=27 format=3 uid="uid://dg8mssy46f035"]
          
          [ext_resource type="Script" path="res://PrecisePath/MedTest/PlayerController.gd" id="1_0wxuw"]
          [ext_resource type="Script" path="res://PrecisePath/MedTest/MoveInPath.gd" id="3_2w35w"]
          
          [sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_kfbar"]
          sky_horizon_color = Color(0.64625, 0.65575, 0.67075, 1)
          ground_horizon_color = Color(0.64625, 0.65575, 0.67075, 1)
          
          [sub_resource type="Sky" id="Sky_oii2a"]
          sky_material = SubResource("ProceduralSkyMaterial_kfbar")
          
          [sub_resource type="Environment" id="Environment_1ehu8"]
          background_mode = 2
          sky = SubResource("Sky_oii2a")
          tonemap_mode = 2
          glow_enabled = true
          
          [sub_resource type="CameraAttributesPractical" id="CameraAttributesPractical_gg3q5"]
          dof_blur_far_distance = 50.0
          dof_blur_far_transition = 10.0
          
          [sub_resource type="Gradient" id="Gradient_xtpws"]
          
          [sub_resource type="FastNoiseLite" id="FastNoiseLite_td1eb"]
          frequency = 1.0
          
          [sub_resource type="NoiseTexture2D" id="NoiseTexture2D_ycgiy"]
          in_3d_space = true
          color_ramp = SubResource("Gradient_xtpws")
          noise = SubResource("FastNoiseLite_td1eb")
          
          [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_f538x"]
          albedo_texture = SubResource("NoiseTexture2D_ycgiy")
          
          [sub_resource type="PlaneMesh" id="PlaneMesh_l01uq"]
          material = SubResource("StandardMaterial3D_f538x")
          size = Vector2(500, 500)
          
          [sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_0cey5"]
          data = PackedVector3Array(250, 0, 250, -250, 0, 250, 250, 0, -250, -250, 0, 250, -250, 0, -250, 250, 0, -250)
          
          [sub_resource type="PhysicsMaterial" id="PhysicsMaterial_rynpv"]
          bounce = 0.49
          
          [sub_resource type="Gradient" id="Gradient_si50j"]
          offsets = PackedFloat32Array(0, 0.193103, 0.365517, 0.531034, 0.727586, 0.889655)
          colors = PackedColorArray(0, 0, 0, 1, 1, 1, 1, 1, 0.592157, 0.592157, 0.0313726, 1, 0.611765, 0.0196078, 0.611765, 1, 0.815905, 0.815905, 0.815905, 1, 0, 1, 1, 1)
          
          [sub_resource type="GradientTexture2D" id="GradientTexture2D_jm6xu"]
          gradient = SubResource("Gradient_si50j")
          
          [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_hvhso"]
          albedo_texture = SubResource("GradientTexture2D_jm6xu")
          metallic = 0.49
          metallic_specular = 0.15
          roughness = 0.32
          
          [sub_resource type="SphereMesh" id="SphereMesh_nt5qp"]
          material = SubResource("StandardMaterial3D_hvhso")
          
          [sub_resource type="SphereShape3D" id="SphereShape3D_2sn1t"]
          radius = 0.51
          
          [sub_resource type="Gradient" id="Gradient_7krnm"]
          
          [sub_resource type="GradientTexture2D" id="GradientTexture2D_hg0xc"]
          gradient = SubResource("Gradient_7krnm")
          
          [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_8wadc"]
          albedo_texture = SubResource("GradientTexture2D_hg0xc")
          
          [sub_resource type="CylinderMesh" id="CylinderMesh_2x84t"]
          material = SubResource("StandardMaterial3D_8wadc")
          top_radius = 0.15
          bottom_radius = 0.3
          height = 0.3
          
          [sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_tfbih"]
          points = PackedVector3Array(-5.87106e-05, -0.15, -0.3, -0.0294244, -0.15, -0.29859, -5.87106e-05, -0.0900059, -0.270047, 0.0293657, -0.15, -0.29859, -0.0264878, -0.0900059, -0.268755, -0.0585552, -0.15, -0.294244, -5.87106e-05, 0.15, -0.150059, 0.0264292, -0.0900059, -0.268755, 0.0584965, -0.15, -0.294244, -0.0176781, 0.0899765, -0.17919, -0.0435787, 0.15, -0.143598, -0.0293069, 0.15, -0.147122, -0.0870987, -0.15, -0.287138, -0.0147415, 0.15, -0.149295, 0.0146829, 0.15, -0.149295, 0.0176195, 0.0899765, -0.17919, 0.0292483, 0.15, -0.147122, 0.04352, 0.15, -0.143598, 0.08704, -0.15, -0.287138, -0.0574393, 0.15, -0.138606, -0.11482, -0.15, -0.277212, -0.103367, -0.0900059, -0.249491, 0.0573806, 0.15, -0.138606, 0.103309, -0.0900059, -0.249491, 0.114761, -0.15, -0.277212, -0.0707126, 0.15, -0.132322, -0.12733, -0.0900059, -0.238156, -0.141425, -0.15, -0.264585, 0.0706539, 0.15, -0.132322, 0.127271, -0.0900059, -0.238156, 0.141367, -0.15, -0.264585, -0.116699, 0.0299824, -0.174667, -0.0833398, 0.15, -0.124745, -0.16668, -0.15, -0.249491, -0.150059, -0.0900059, -0.22453, 0.0832812, 0.15, -0.124745, 0.116641, 0.0299824, -0.174667, 0.15, -0.0900059, -0.22453, 0.166621, -0.15, -0.249491, -0.0952036, 0.15, -0.115994, -0.190348, -0.15, -0.23193, 0.0951449, 0.15, -0.115994, 0.19029, -0.15, -0.23193, -0.12733, 0.0899765, -0.12733, -0.106069, 0.15, -0.106069, -0.212138, -0.15, -0.212138, 0.10601, 0.15, -0.106069, 0.127271, 0.0899765, -0.12733, 0.212079, -0.15, -0.212138, -0.115994, 0.15, -0.0952036, -0.23193, -0.15, -0.190348, 0.115936, 0.15, -0.0952036, 0.231872, -0.15, -0.190348, -0.124745, 0.15, -0.0833398, -0.22453, -0.0900059, -0.150059, -0.174667, 0.0299824, -0.116699, -0.249491, -0.15, -0.16668, 0.124687, 0.15, -0.0833398, 0.174608, 0.0299824, -0.116699, 0.224471, -0.0900059, -0.150059, 0.249432, -0.15, -0.16668, -0.132322, 0.15, -0.0707126, -0.238156, -0.0900059, -0.12733, -0.264585, -0.15, -0.141425, 0.132263, 0.15, -0.0707126, 0.238097, -0.0900059, -0.12733, 0.264526, -0.15, -0.141425, -0.138606, 0.15, -0.0574393, -0.277212, -0.15, -0.11482, -0.249491, -0.0900059, -0.103367, 0.138547, 0.15, -0.0574393, 0.249432, -0.0900059, -0.103367, 0.277154, -0.15, -0.11482, -0.143598, 0.15, -0.0435787, -0.287138, -0.15, -0.0870987, 0.14354, 0.15, -0.0435787, 0.287079, -0.15, -0.0870987, -0.294244, -0.15, -0.0585552, -0.147122, 0.15, -0.0293069, 0.147063, 0.15, -0.0293069, 0.294186, -0.15, -0.0585552, -0.29859, -0.15, -0.0294244, -0.268755, -0.0900059, -0.0264878, -0.17919, 0.0899765, -0.0176781, -0.149295, 0.15, -0.0147415, 0.149237, 0.15, -0.0147415, 0.179131, 0.0899765, -0.0176781, 0.268696, -0.0900059, -0.0264878, 0.298532, -0.15, -0.0294244, -0.3, -0.15, -5.87106e-05, -0.270047, -0.0900059, -5.87106e-05, -0.150059, 0.15, -5.87106e-05, 0.149941, 0.15, -5.87106e-05, 0.269988, -0.0900059, -5.87106e-05, 0.299941, -0.15, -5.87106e-05, -0.29859, -0.15, 0.0293657, -0.268755, -0.0900059, 0.0264292, -0.17919, 0.0899765, 0.0176195, -0.149295, 0.15, 0.0146829, 0.149237, 0.15, 0.0146829, 0.179131, 0.0899765, 0.0176195, 0.268696, -0.0900059, 0.0264292, 0.298532, -0.15, 0.0293657, -0.294244, -0.15, 0.0584965, -0.147122, 0.15, 0.0292483, 0.147063, 0.15, 0.0292483, 0.294186, -0.15, 0.0584965, -0.287138, -0.15, 0.08704, -0.143598, 0.15, 0.04352, 0.14354, 0.15, 0.04352, 0.287079, -0.15, 0.08704, -0.277212, -0.15, 0.114761, -0.249491, -0.0900059, 0.103309, -0.138606, 0.15, 0.0573806, 0.249432, -0.0900059, 0.103309, 0.277154, -0.15, 0.114761, 0.138547, 0.15, 0.0573806, -0.264585, -0.15, 0.141367, -0.238156, -0.0900059, 0.127271, -0.132322, 0.15, 0.0706539, 0.238097, -0.0900059, 0.127271, 0.264526, -0.15, 0.141367, 0.132263, 0.15, 0.0706539, -0.249491, -0.15, 0.166621, -0.22453, -0.0900059, 0.15, -0.174667, 0.0299824, 0.116641, -0.124745, 0.15, 0.0832812, 0.174608, 0.0299824, 0.116641, 0.224471, -0.0900059, 0.15, 0.249432, -0.15, 0.166621, 0.124687, 0.15, 0.0832812, -0.23193, -0.15, 0.19029, -0.115994, 0.15, 0.0951449, 0.115936, 0.15, 0.0951449, 0.231872, -0.15, 0.19029, -0.212138, -0.15, 0.212079, -0.12733, 0.0899765, 0.127271, -0.106069, 0.15, 0.10601, 0.10601, 0.15, 0.10601, 0.127271, 0.0899765, 0.127271, 0.212079, -0.15, 0.212079, -0.190348, -0.15, 0.231872, -0.0952036, 0.15, 0.115936, 0.0951449, 0.15, 0.115936, 0.19029, -0.15, 0.231872, -0.16668, -0.15, 0.249432, -0.150059, -0.0900059, 0.224471, -0.116699, 0.0299824, 0.174608, -0.0833398, 0.15, 0.124687, 0.0832812, 0.15, 0.124687, 0.116641, 0.0299824, 0.174608, 0.15, -0.0900059, 0.224471, 0.166621, -0.15, 0.249432, -0.141425, -0.15, 0.264526, -0.12733, -0.0900059, 0.238097, -0.0707126, 0.15, 0.132263, 0.0706539, 0.15, 0.132263, 0.127271, -0.0900059, 0.238097, 0.141367, -0.15, 0.264526, -0.11482, -0.15, 0.277154, -0.103367, -0.0900059, 0.249432, -0.0574393, 0.15, 0.138547, 0.0573806, 0.15, 0.138547, 0.103309, -0.0900059, 0.249432, 0.114761, -0.15, 0.277154, -0.0870987, -0.15, 0.287079, -0.0435787, 0.15, 0.14354, 0.04352, 0.15, 0.14354, 0.08704, -0.15, 0.287079, -0.0585552, -0.15, 0.294186, -0.0293069, 0.15, 0.147063, 0.0292483, 0.15, 0.147063, 0.0584965, -0.15, 0.294186, -0.0294244, -0.15, 0.298532, -0.0264878, -0.0900059, 0.268696, -0.0176781, 0.0899765, 0.179131, -0.0147415, 0.15, 0.149237, 0.0146829, 0.15, 0.149237, 0.0176195, 0.0899765, 0.179131, 0.0264292, -0.0900059, 0.268696, 0.0293657, -0.15, 0.298532, -5.87106e-05, -0.15, 0.299941, -5.87106e-05, -0.0900059, 0.269988, -5.87106e-05, 0.15, 0.149941)
          
          [sub_resource type="Curve3D" id="Curve3D_8lwa0"]
          bake_interval = 0.01
          _data = {
          "points": PackedVector3Array(-0.276182, 0, 2.26761, 0.276182, 0, -2.26761, 0.208208, 0, -9.12366, -3.53667, 0, 2.95403, 3.53667, 0, -2.95403, 4.15512, 0, -20.1636, -4.85231, 0, -0.764078, 4.85231, 0, 0.764078, 17.8835, 0, -22.852, -2.79305, 0, -3.22375, 2.79305, 0, 3.22375, 27.3218, 0, -16.8459, 0.812849, 0, -4.93156, -0.812849, 0, 4.93156, 29.381, 0, 3.7467, 1.67087, 0, -2.52909, -1.67087, 0, 2.52909, 24.9765, 0, 16.7887, 5.84659, 0, -0.698637, -5.84659, 0, 0.698637, 14.9662, 0, 21.994, 1.66442, 0, 2.24875, -1.66442, 0, -2.24875, 1.92426, 0, 13.3566, 0.705303, 0, 3.66793, -0.705303, 0, -3.66793, -1.01693, 0, 3.60257, 0, 0, 0, 0, 0, 0, 0.208208, 0, -9.12366),
          "tilts": PackedFloat32Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
          }
          point_count = 10
          
          [sub_resource type="CapsuleMesh" id="CapsuleMesh_1fpbd"]
          
          [sub_resource type="PrismMesh" id="PrismMesh_celvx"]
          
          [node name="Medtest" type="Node3D"]
          
          [node name="GeralEnv" type="Node3D" parent="."]
          
          [node name="WorldEnvironment" type="WorldEnvironment" parent="GeralEnv"]
          environment = SubResource("Environment_1ehu8")
          camera_attributes = SubResource("CameraAttributesPractical_gg3q5")
          
          [node name="Ground" type="MeshInstance3D" parent="GeralEnv"]
          mesh = SubResource("PlaneMesh_l01uq")
          skeleton = NodePath("../..")
          
          [node name="StaticBody3D" type="StaticBody3D" parent="GeralEnv/Ground"]
          
          [node name="CollisionShape3D" type="CollisionShape3D" parent="GeralEnv/Ground/StaticBody3D"]
          shape = SubResource("ConcavePolygonShape3D_0cey5")
          
          [node name="BallNodePosition" type="Node3D" parent="."]
          transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.498346, -4.8275)
          
          [node name="PlayerController" type="Node" parent="BallNodePosition"]
          script = ExtResource("1_0wxuw")
          
          [node name="BallBody" type="RigidBody3D" parent="BallNodePosition"]
          physics_material_override = SubResource("PhysicsMaterial_rynpv")
          linear_damp = 5.0
          angular_damp = 5.0
          
          [node name="MeshInstance3D" type="MeshInstance3D" parent="BallNodePosition/BallBody"]
          mesh = SubResource("SphereMesh_nt5qp")
          
          [node name="CollisionShape3D" type="CollisionShape3D" parent="BallNodePosition/BallBody"]
          shape = SubResource("SphereShape3D_2sn1t")
          
          [node name="HeadRigidBody3D" type="RigidBody3D" parent="BallNodePosition"]
          transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.672607, 0)
          axis_lock_angular_x = true
          axis_lock_angular_z = true
          angular_damp = 12.03
          
          [node name="Head" type="MeshInstance3D" parent="BallNodePosition/HeadRigidBody3D"]
          mesh = SubResource("CylinderMesh_2x84t")
          skeleton = NodePath("../..")
          
          [node name="Camera3D" type="Camera3D" parent="BallNodePosition/HeadRigidBody3D/Head"]
          transform = Transform3D(0.976681, -0.118959, 0.178724, 0, 0.832458, 0.554088, -0.214694, -0.541167, 0.813047, 0.715342, 2.6822, 3.25421)
          
          [node name="CollisionShape3D" type="CollisionShape3D" parent="BallNodePosition/HeadRigidBody3D"]
          shape = SubResource("ConvexPolygonShape3D_tfbih")
          
          [node name="PinJoint3D" type="PinJoint3D" parent="BallNodePosition"]
          node_a = NodePath("../BallBody")
          node_b = NodePath("../HeadRigidBody3D")
          exclude_nodes_from_collision = false
          
          [node name="Path3D" type="Path3D" parent="."]
          transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6.75779, 1.15986, 0)
          curve = SubResource("Curve3D_8lwa0")
          
          [node name="PathFollow3D" type="PathFollow3D" parent="Path3D"]
          transform = Transform3D(-0.992657, 0, 0.1209, 0, 1, 0, -0.1209, 0, -0.992657, 0.208208, 0, -9.12366)
          cubic_interp = false
          
          [node name="ByLocal" type="MeshInstance3D" parent="Path3D/PathFollow3D"]
          transform = Transform3D(1, 0, -7.45058e-09, 0, 1, 0, 7.45058e-09, 0, 1, 0, 0, 0)
          mesh = SubResource("CapsuleMesh_1fpbd")
          skeleton = NodePath("../..")
          
          [node name="MoveInPath" type="Node" parent="."]
          script = ExtResource("3_2w35w")
          
          [node name="ByPoint" type="MeshInstance3D" parent="."]
          transform = Transform3D(-0.992657, 0, 0.1209, 0, 1, 0, -0.1209, 0, -0.992657, -6.54958, 1.15986, -9.12366)
          mesh = SubResource("PrismMesh_celvx")
          skeleton = NodePath("../Path3D/PathFollow3D")

            IceBergyn File 2 and File 3:
            MoveInPath.gd

            extends Node
            
            @onready var path = $"../Path3D"
            @onready var pathflw = $"../Path3D/PathFollow3D"
            @onready var ball:RigidBody3D = $"../BallNodePosition/BallBody"
            @onready var byPoint = $"../ByPoint"
            @export var engine_power: float = 1
            
            var sphere_offset = Vector3(0.0, 0.568,  0)
            var speed_input: float = 0
            var rotate_input: float = 0
            var steering: float = 14
            var turnspeed: float = 8
            
            func _process(delta):
            	var point = path.curve.get_closest_point( ball.global_transform.origin )
            	var offset = path.curve.get_closest_offset( ball.global_transform.origin )
            	pathflw.progress=offset
            	byPoint.set_position( point + path.global_transform.origin )

            PlayerController.gd

            extends Node
            
            @onready var ball: RigidBody3D = $"../BallBody"
            @onready var head: MeshInstance3D = $"../HeadRigidBody3D/Head"
            @onready var HeadRigidBody3D: RigidBody3D = $"../HeadRigidBody3D"
            @export var engine_power: float = 1
            
            var sphere_offset = Vector3(0.0, 0.568,  0)
            var speed_input: float = 0
            var rotate_input: float = 0
            var steering: float = 14
            var turnspeed: float = 8
            
            func _physics_process(delta):
            	ball.remove_collision_exception_with(HeadRigidBody3D)
            	HeadRigidBody3D.remove_collision_exception_with(ball)
            	
            	rotate_input = 0
            	rotate_input += Input.get_action_strength("Car_Left")
            	rotate_input -= Input.get_action_strength("Car_Right")
            	rotate_input *= deg_to_rad(steering)
            	
            	speed_input = 0
            	speed_input += Input.get_action_strength("Car_Accelerate")
            	speed_input -= Input.get_action_strength("Car_Brake")
            	if(speed_input<0): speed_input=speed_input/2
            	speed_input *= engine_power
            	
            	# move ball front and back
            	ball.apply_central_impulse( HeadRigidBody3D.global_transform.basis.z * -speed_input )
            
            	# rotate head
            	HeadRigidBody3D.rotate_y( rotate_input *turnspeed * delta )

            IceBergyn You're passing ball's global position as an argument to get_closest_point(). Docs state that this argument should be in curve's local space. So try:

            var point = path.curve.get_closest_point( path.to_local(ball.global_transform.origin) )

              xyz Wow, that did the trick ! I not sure I understood what this function did thought, it says it transform the coord to local space of "this node", what node ? Is this able to "see" somehow the node I am refering in the next call ? I am asking because if I try to call using ball.transform.origin it dont work...

                IceBergyn Ha sorry, just figure out, "path" in this case is the Node its refering ! Thanks I didnt know about this function. 🙂