Search Unity

Question how to finding nearest vertex to object or ray or mouse position?

Discussion in 'World Building' started by yairk333, Feb 18, 2021.

  1. yairk333

    yairk333

    Joined:
    Mar 26, 2020
    Posts:
    23
    how to finding nearest vertex to object or ray or mouse position?
     
  2. Flavelius

    Flavelius

    Joined:
    Jul 8, 2012
    Posts:
    945
    Retrieve the mesh from collider or meshrenderer, loop through all vertices, transform them to worldspace, compare distances, pick closest
     
  3. yairk333

    yairk333

    Joined:
    Mar 26, 2020
    Posts:
    23
    but how to do that?
     
  4. yairk333

    yairk333

    Joined:
    Mar 26, 2020
    Posts:
    23
  5. Flavelius

    Flavelius

    Joined:
    Jul 8, 2012
    Posts:
    945
    GetComponent<T>() to get the collider or meshrenderer. those have .mesh or .sharedMesh field. That in turn has a .vertices field which is a an array of Vector3. transform has .TransformPoint().
    If you need a ray from mouseposition camera has .ScreenPointToRay().
    the rest ist math, which you can find via your favourite search engine, by searching for 'distance point to ray' for example.
     
  6. yairk333

    yairk333

    Joined:
    Mar 26, 2020
    Posts:
    23
    and how to find the closer vertex?

    Flavelius
     
  7. yairk333

    yairk333

    Joined:
    Mar 26, 2020
    Posts:
    23
  8. nukadelic

    nukadelic

    Joined:
    Aug 5, 2017
    Posts:
    78
    There is `HandleUtility.FindNearestVertex` with little documentation to no - seems straight forward , however i didn't have any luck using it , maybe because I'm using a skinned mesh renderer.

    Since I already have vertex data I do a simple search based on the vertex distance to a line ( ray ) + the distance to the scene view camera :)

    Code (CSharp):
    1. [CustomEditor(typeof(SkinnedMeshVertex))]
    2. class CustomInspector : Editor
    3. {
    4.     void OnSceneGUI()
    5.     {
    6.        var script = ( SkinnedMeshVertex ) target; // or whatever its called
    7.        if( script.vertices == null || script.vertices.Length == 0 ) return;
    8.  
    9.         Vector3 mouse = Event.current.mousePosition;
    10.         Ray ray = HandleUtility.GUIPointToWorldRay(mouse);
    11.         mouse = ray.origin + ray.direction;
    12.         var pos = script.transform.position;
    13.         var forward = SceneView.currentDrawingSceneView.camera.transform.position - pos;
    14.         var camera = SceneView.currentDrawingSceneView.camera;
    15.  
    16.         int nearest_idx = 0;
    17.         float nearest_dist = float.PositiveInfinity;
    18.  
    19.         float d1 = 0, d2 = 0;
    20.  
    21.         for (var i = 0; i < script.vertices.Length; ++i)
    22.         {
    23.             d1 = Vector3.Distance(script.vertices[i], ray.origin) / 2f;
    24.             d2 = Vector3.Cross(ray.direction, script.vertices[i] - ray.origin).magnitude;
    25.  
    26.             var di = d1 + d2;
    27.  
    28.             if (di < nearest_dist)
    29.             {
    30.                 nearest_idx = i;
    31.                 nearest_dist = di;
    32.             }
    33.         }
    34.  
    35.         //Handles.Label(pos, d1.ToString("N2") + "  ::  " + d2.ToString("N2"));
    36.  
    37.         var v = script.vertices[ nearest_idx ];
    38.  
    39.         var scale = (HandleUtility.GetHandleSize(v) / 7f) * 1.0f;
    40.  
    41.         bool hasIndex = script.gizmoIndexes.Contains(nearest_idx);
    42.  
    43.         Handles.color = hasIndex ? Color.red : Color.green;
    44.  
    45.         if ( Handles.Button( v , Quaternion.identity , scale, scale * 1.1f, Handles.SphereHandleCap ) )
    46.         {
    47.             Debug.Log( nearest_idx );
    48.             Undo.RecordObject(target, "Index");
    49.             if( hasIndex ) script.gizmoIndexes.Remove(nearest_idx);
    50.             else script.gizmoIndexes.Add(nearest_idx);
    51.         }
    52.     }
    53. }