Search Unity

Detecting snap points on a mesh....

Discussion in 'Scripting' started by Marcus_Nordstrom, Mar 1, 2021.

  1. Marcus_Nordstrom

    Marcus_Nordstrom

    Joined:
    Apr 20, 2017
    Posts:
    8
    Hello! I'm trying to put snap points on gameobjects with a single script and detect each side of the mesh top, bottom, left, right, front, back and give them a "snap point" in the center of each side.

    I have tried all bounds methods but they only work on cubes or rectangular shaped objects.

    I have tried looping thru vertices of the mesh and getting the correct vertexes but it never works for different meshes as they (obviously) are different from one another. And comparing to a closest point combined with bounds is probably doable but I don't know how to do it.

    Barycentric i have tried but cannot quite grasp it.

    Help is much appreciated.

    //Marcus N
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    When I want to do this kind of thing I usually use "empty" GameObjects that are children of my object and position them exactly in the place where I want the snapping to happen. It then becomes fairly trivial to use the position and orientation of that empty child to snap two objects together.
     
    Kurt-Dekker likes this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    If you're doing stuff like building dungeon rooms and trying to runtime connect rooms, this way works really well, and you can make ultra simple rooms in various configurations to just prove out that your connection algebra is correct.
     
  4. Marcus_Nordstrom

    Marcus_Nordstrom

    Joined:
    Apr 20, 2017
    Posts:
    8
    I want to Dynamically, create those points which you describe as Empty Gameobjects that are snap points.

    Based on the Mesh outer bounds, and now i mean the real 'bounds' as in where the actual Mesh ends, as in it''s collider for example, in each direction front, back, top, bottom, left and right.

    Without actually making the gameobjects manually, i would rather have a code which makes those gameobjects. But all i need to do so is some way to get the actual bounds of the mesh, and not the bounds that unity has built in :/
     
  5. _met44

    _met44

    Joined:
    Jun 1, 2013
    Posts:
    633
    if you're looking at a simple bounds detection what you need is transform the AABB bounds of the mesh *when zeroed* into its runtime world equivalent based on the gameobject's transform (transform.TransformPoint()).
     
  6. Marcus_Nordstrom

    Marcus_Nordstrom

    Joined:
    Apr 20, 2017
    Posts:
    8
    Hmm i tried this , but isn't the bounds always rectangular? because they seem to not actually be the actual bounds of the mesh model.

    On a cube it works fine, but on a sphere for example, there is a distance between the bounds point and the actual mesh. Which means it actually draws the "snap-point" not on the mesh, but a distance away from the mesh.
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    You can pluck out the vertices involved by iterating the vertices array in the Mesh, which is located in the MeshFilter component, sort of the reverse of procedural generation: instead of creating points you are reading them. You can see examples of procedural generation in my MakeGeo project at:

    MakeGeo is presently hosted at these locations:

    https://bitbucket.org/kurtdekker/makegeo

    https://github.com/kurtdekker/makegeo

    https://gitlab.com/kurtdekker/makegeo

    https://sourceforge.net/p/makegeo

    Those points come out in local space for the object you so need to apply the Transform properties (transform, rotate, scale) to get the world coordinates.


    Once you have the set of points the issue becomes how you want to define the word "bounds." An AABB (what Unity gets you ) is easy, as you just take the minimum in each axis direction.

    A harder problem is to find the Minimum Bounding Box (2D) or Volume (3D), but this is a well-studied area of geometry:

    https://en.wikipedia.org/wiki/Minimum_bounding_box#:~:text=In geometry, the minimum or,which all the points lie.
     
  8. _met44

    _met44

    Joined:
    Jun 1, 2013
    Posts:
    633
    @Rahkzor it depends what you're trying to snap can you show a picture ? if you're trying to snap to octopus tentacles obviously its not a simple case so bounds trick wont work.

    If you're trying to snap objects with always the same relative distance & orientation (but possibly different for each axis) based on the original transform then it works fine, even with spheres like shapes (that would work for an ark/connan -like build system).

    If you're trying to conform/paint an object onto another then you need to look at vertices as Kurt pointed out, but you mention wanting a snap point on the center of each side...
     
  9. Marcus_Nordstrom

    Marcus_Nordstrom

    Joined:
    Apr 20, 2017
    Posts:
    8
    Like this, i now recreated the problem on 2 corners on each mesh. On a cube the snapping points is good, as it clearly is a cube and the bounds which i use to draw gizmos on are also a cube.





    But on the second picture the bounds is still a cube, even tho the mesh is a sphere.

    Now what i ultimately want in the end is to only have gizmos in the corners and the middle of the models, and if it's a sphere for example the gizmos is actually ON THE MODEL and not far away as shown in the picture.


    Thank you, this approach seems promising :)
     
  10. Marcus_Nordstrom

    Marcus_Nordstrom

    Joined:
    Apr 20, 2017
    Posts:
    8
    I found a solution!

    It's a bit haxxy and inconvenient but i don't know a cleaner way of doing it atm.

    This is the code:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class SnapPoints : MonoBehaviour
    4. {
    5.     void OnDrawGizmos() {
    6.         var vertices = GetComponent<MeshFilter>().sharedMesh.vertices;
    7.  
    8.         float largestX = 0;
    9.         float smallestX = 1000;
    10.  
    11.         float largestY = 0;
    12.         float smallestY = 1000;
    13.  
    14.         float largestZ = 0;
    15.         float smallestZ = 1000;
    16.        
    17.         for (var i = 0; i < vertices.Length; i++) {
    18.             if (vertices[i].x > largestX) {
    19.                 largestX = vertices[i].x;
    20.             }
    21.  
    22.             if (vertices[i].x < smallestX) {
    23.                 smallestX = vertices[i].x;
    24.             }
    25.  
    26.             if (vertices[i].y > largestY) {
    27.                 largestY = vertices[i].y;
    28.             }
    29.  
    30.             if (vertices[i].y < smallestY) {
    31.                 smallestY = vertices[i].y;
    32.             }
    33.  
    34.             if (vertices[i].z > largestZ) {
    35.                 largestZ = vertices[i].z;
    36.             }
    37.  
    38.             if (vertices[i].z < smallestZ) {
    39.                 smallestZ = vertices[i].z;
    40.             }
    41.         }
    42.        
    43.         Gizmos.DrawSphere(transform.TransformPoint(new Vector3(largestX, 0, 0)), 0.1f);
    44.         Gizmos.DrawSphere(transform.TransformPoint(new Vector3(smallestX, 0, 0)), 0.1f);
    45.        
    46.         Gizmos.DrawSphere(transform.TransformPoint(new Vector3(0, largestY, 0)), 0.1f);
    47.         Gizmos.DrawSphere(transform.TransformPoint(new Vector3(0, smallestY, 0)), 0.1f);
    48.        
    49.         Gizmos.DrawSphere(transform.TransformPoint(new Vector3(0, 0, largestZ)), 0.1f);
    50.         Gizmos.DrawSphere(transform.TransformPoint(new Vector3(0, 0, smallestZ)), 0.1f);
    51.     }
    52. }
    53.  

    And a picture to show the result i get, which is what i wanted:

     
  11. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    WIN!! SHIP IT, QUICKLY!!!
     
    Marcus_Nordstrom likes this.