Search Unity

Runtime snapping objects together based on anchor points.

Discussion in 'Scripting' started by dustinandrew, Aug 31, 2020.

  1. dustinandrew

    dustinandrew

    Joined:
    Apr 30, 2010
    Posts:
    102
    I'm creating a runtime object snapping system, similar to your typical game building mechanic. Each building object has anchor points that can snap to other object's anchor points.

    I already have everything working on getting the nearest object and anchor points while dragging a building object around. But, I'm struggling on how to calculate the rotation needed to snap the two objects together.

    What rotation should the snapping object be at, based on each anchor points direction? The anchor points parent forward makes it challenging. I would like this to work by aligning the anchor points, no matter the difference in the objects shape.

    Here what I have so far, position the snapping object at the snap to anchor point. Then move out from snap to anchor point in its forward direction. Next rotate the snapping object to align the anchor points.

    I'm just looking for help on understanding the vector math, not for plugins or full code solutions. Thanks!

    Code (CSharp):
    1.  
    2. // .... Get object near dragged object
    3. // .... Get closest anchor points between objects at look point
    4. // nearestObject = object that we found closest to look point
    5. // snapFromPoint = anchor point on object we are dragging
    6. // snapToPoint = closest anchor point on nearestObject
    7. float snappingDis = Vector3.Distance(Vector3.zero, snapFromPoint.localPosition);
    8. transform.position = snapToPoint.position + (snapToPoint.forward * snappingDis);
    9. transform.rotation = nearestObject.rotation // ??? need to offset rotation based on anchor point we are snapping to
    10.  
    The illustration shows what I would like to accomplish, blue = object's forward, green = anchors to snap to, black = other anchor points. Also the illustration doesn't show this, but the anchor points are rotated to face forward out from the surface.


     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    So what you want is to have the surfaces match up properly, and you already have the surface normals? I would do this:

    First, get the two surface normals you care about:

    S = the stationary surface normal. The normal on the surface of the object that is receiving the snapped object
    M = the mobile surface normal. The normal on the surface of the object that is being attached to the first object.

    Then the rotation of the object M is attached to should be such that the new direction of M will be perfectly opposite the current direction of S. The amount you need to rotate the new object is therefore the rotation you need to change the current rotation of M to equal -S. So something like this:

    Code (CSharp):
    1. // We want M to point opposite of S
    2. var desiredDirectionOfM = -S;
    3.  
    4. // What rotation do we have to apply for M to become -S?
    5. Quaternion rotationFromCurrent = Quaternion.FromToRotation(M, desiredDirectionOfM);
    6.  
    7. // Calculate the new rotation
    8. Quaternion newRotation = objectBeingSnapped.transform.rotation * rotationFromCurrent;
    9.  
    10. // rotate the object
    11. objectBeingSnapped.transform.rotation = newRotation;
    Once the object is rotated properly the positioning part should be fairly straightforward if you have anchor points on the edges.
     
    Last edited: Aug 31, 2020
  3. dustinandrew

    dustinandrew

    Joined:
    Apr 30, 2010
    Posts:
    102
    @PraetorBlue that worked! FromToRotation to get the normal direction difference was the key. Thank you!
     
    PraetorBlue likes this.