Search Unity

Align Object To Normal While Surface Snapping?

Discussion in 'Editor & General Support' started by CptOblivion, Sep 21, 2016.

  1. CptOblivion

    CptOblivion

    Joined:
    Mar 8, 2015
    Posts:
    9
    Hi all! I'm a beginner with Unity. I have a question that I think belongs here, but depending on the answer to the basic first bit it may be better suited in the scripting forum. But here goes:

    The title basically says it, but in more detail: is it possible to get an object to orient itself to the normal of a surface, while it's snapping to said surface? this is important for eg placing paintings, torches, decorative animal heads, etc on walls (especially when the walls don't perfectly align with two axes), but I can't seem to figure out how to do it and google gave me nothing helpful. Is there something obvious I missed?

    As a temporary fix I made a hacky script to cast a ray from the camera through the object when it's moving, and align it to the surface the ray hits, but I can't seem to find a way to check if the object is currently being moved with surface snapping- I'd rather the function not run if I move it along one axis, or drag it around in the scene without surface snapping, and so on. Is this a thing I can check for? As another hack I tried checking when shift and ctrl are held down, but despite my best efforts I couldn't get the script to return positive when any key was pressed.

    So! Is there a simple solution? Or is the clunky-to-use script the only way- and if so, is there a better one that someone else has already made that I just haven't found? Or if not, how might I go about making this script only work in the specific context of an object being snapped to a surface?

    The script in question: (apologies for the mess, I'm still learning C#)

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. [ExecuteInEditMode]
    5.  
    6.  
    7.  
    8. public class AlignToSurface : MonoBehaviour {
    9.     // list of axes for a drop-down
    10.     //the order is weird to put convenient values first (because Blender uses Z up, and then sometimes I model with things facing -Y) (don't ask)
    11.     public enum AxisList
    12.     {
    13.         PositiveZ, NegativeY, PositiveY, PositiveX, NegativeZ, NegativeX
    14.     }
    15.     public AxisList alignAxis;
    16.  
    17.     //tracking previous transforms so we can figure out if we've moved
    18.     private Vector3 oldPosition;
    19.     private Quaternion oldRotation;
    20.     private Vector3 oldScale;
    21.    
    22.     // Use this for initialization
    23.     void Start () {
    24.         //let's get initialized
    25.         //(use local position so children don't auto-align when their parent moves!)
    26.         oldPosition = transform.localPosition;
    27.         oldRotation = transform.localRotation;
    28.         oldScale = transform.localScale;
    29.     }
    30.  
    31.     // Update is called once per frame
    32.     void Update () {
    33.         if (transform.localPosition != oldPosition) //if we've moved
    34.         {
    35.             oldPosition = transform.localPosition;
    36.             //make sure the center isn't moving just because of rotation or scaling centered somewhere other than the pivot
    37.             if (oldRotation != transform.localRotation || oldScale != transform.localScale)
    38.             {
    39.                 oldRotation = transform.localRotation;
    40.                 oldScale = transform.localScale;
    41.                 oldPosition = transform.localPosition;
    42.             }
    43.             else//we're moving! Time to snap
    44.             {
    45.                 oldPosition = transform.localPosition;
    46.                 if (Camera.current != null) //make sure we are transforming in the viewport (as opposed to, say, inputting a value in the properties)
    47.                 {
    48.                     RaycastHit hit;
    49.                     Ray ray = Camera.current.ScreenPointToRay(Camera.current.WorldToScreenPoint(this.transform.position));
    50.                     //converting the object position into screen coordinates to cast a ray through afforementioned object position seems excessive
    51.                     //but I couldn't figure out how to get the viewport camera position so this will have to do I guess
    52.                     if (Physics.Raycast(ray, out hit))
    53.                     {
    54.                         //align the appropriate axis to the normal
    55.                         if (alignAxis == AxisList.PositiveX)
    56.                         {
    57.                             transform.right = hit.normal;
    58.                         }
    59.                         else if (alignAxis == AxisList.PositiveY)
    60.                         {
    61.                             transform.up = hit.normal;
    62.                         }
    63.                         else if (alignAxis == AxisList.PositiveZ)
    64.                         {
    65.                             transform.forward = hit.normal;
    66.                         }
    67.                         else if (alignAxis == AxisList.NegativeX)
    68.                         {
    69.                             transform.right = hit.normal * -1;
    70.                         }
    71.                         else if (alignAxis == AxisList.NegativeY)
    72.                         {
    73.                             transform.up = hit.normal * -1;
    74.                         }
    75.                         else { transform.forward = hit.normal * -1; }
    76.                     }
    77.                     oldRotation = transform.localRotation;
    78.                 }
    79.             }
    80.         }
    81.     }
    82. }
    83.