Is there a toggle for snap to grid?

Currently the only way I know of to use Snap to Grid feature when moving objects is to hold down the “Command” (or “Control” for PC).

Is there anywhere in the editor you can toggle this option so you don’t have to hold down a button all the time for object placement?

If there is not a toggle option some where, what would be the best way to go about adding this feature to the editor?

Since this is the first result for “unity snap to grid” in Google, I figured we should also have an updated answer here for newer Unity versions and for the benefit of other people landing on this page.

  1. Press control while dragging
  2. Edit snap settings in Edit > Snap Settings…
  3. More info in this doc page

I scoured the docs, but it doesn't look like this is something configurable. Instead, I wrote this little editor script that does essentially the same thing. (Note- It will always round down, but this could be pretty easily fixed)

Place this script in a folder named "Editor", and hit CTRL-L or open Edit/AutoSnap to access the menu.

@script ExecuteInEditMode()

class autoSnap extends EditorWindow
{
    var prevPosition    : Vector3;
    var doSnap  : boolean = false;
    var snapValue: float = 1;
    @MenuItem("Edit/Auto Snap %_l")

    static function Init () 
    {
        var window : autoSnap = EditorWindow.GetWindow(autoSnap);
    }

    function OnGUI()
    {
        doSnap = EditorGUILayout.Toggle("Autosnap", doSnap);
        snapValue = EditorGUILayout.FloatField("Snap Value", snapValue);
    }

    function Update()
    {
        if(Selection.transforms.Length > 0 && !EditorApplication.isPlaying)
        if(doSnap && Selection.transforms[0].position != prevPosition)
            snap();
    }

    function snap()
    {
        try
        {
            for(i = 0; i < Selection.transforms.Length; i++)
            {               
                var t : Vector3 = Selection.transforms*.transform.position;* 
 *t.x = round(t.x);*
 *t.y = round(t.y);*
 *t.z = round(t.z);*
 _Selection.transforms*.transform.position = t;*_
 _*}*_
 _*prevPosition = Selection.transforms[0].position;*_
 _*}*_
 _*catch(e)*_
 _*{*_
 _*// Nothing to move.*_
 _*Debug.LogError("Nothing to move.  " + e);*_
 _*}*_
 _*}*_
 _*function round(input : float)*_
 _*{*_
 _*var snappedValue : float;*_
 <em>_snappedValue = snapValue * Mathf.Round((input / snapValue));_</em>
 _*return(snappedValue);*_
 _*}*_
_*}*_
_*```*_

Here is the C# version.

using UnityEngine;
using UnityEditor;

public class AutoSnap : EditorWindow
{
	private Vector3 prevPosition;
	private bool doSnap = true;
	private float snapValue = 1;

	[MenuItem( "Edit/Auto Snap %_l" )]

	static void Init()
	{
		var window = (AutoSnap)EditorWindow.GetWindow( typeof( AutoSnap ) );
		window.maxSize = new Vector2( 200, 100 );
	}

	public void OnGUI()
	{
		doSnap = EditorGUILayout.Toggle( "Auto Snap", doSnap );
		snapValue = EditorGUILayout.FloatField( "Snap Value", snapValue );
	}

	public void Update()
	{
		if ( doSnap
			&& !EditorApplication.isPlaying
			&& Selection.transforms.Length > 0
			&& Selection.transforms[0].position != prevPosition )
		{
			Snap();
			prevPosition = Selection.transforms[0].position;
		}
	}

	private void Snap()
	{
		foreach ( var transform in Selection.transforms )
		{
			var t = transform.transform.position;
			t.x = Round( t.x );
			t.y = Round( t.y );
			t.z = Round( t.z );
			transform.transform.position = t;
		}
	}

	private float Round( float input )
	{
		return snapValue * Mathf.Round( ( input / snapValue ) );
	}
}

I found the scripts in here would fail once the auto snap window was closed. It has to do with the update event. I’ve also added snap to scaling, so here’s my version:

 using UnityEngine; 
 using UnityEditor;
 
 public class AutoSnap : EditorWindow
 {
	private Vector3 prevPosition;
	private Vector3 prevScale;
	private Vector3 prevRotation;
	
	// These need to be static because the auto snap window is
	// recreated when opened from the menu
	private static bool doSnap = false;
	private static bool doScaleSnap = false;
	private static bool doRotateSnap = false;
	private static float snapValueX = 1;
	private static float snapValueY = 1;
	private static float snapValueZ = 1;
	private static float snapRotateValue = 1;
	
	// We need to remember the window doing the snap updates
	// so it will do it when the window is closed
	private static AutoSnap updateWindow = null;
 
	private const string doSnapKey        	= "AutoSnap_doSnapKey";
	private const string doScaleSnapKey		= "AutoSmap_doScaleSnapKey";
	private const string doRotateSnapKey  	= "AutoSnap_doRotateSnapKey";
	private const string snapValueXKey    	= "AutoSnap_snapValueXKey";
	private const string snapValueYKey    	= "AutoSnap_snapValueYKey";
	private const string snapValueZKey    	= "AutoSnap_snapValueZKey";
	private const string snapRotateValueKey = "AutoSnap_snapRotateValueKey";
 
	[MenuItem( "Edit/Auto Snap %_l" )]
	  
	static void Init()
	{
		// Debug.Log("AutoSnap: Init");
		  
		AutoSnap window = (AutoSnap)EditorWindow.GetWindow( typeof( AutoSnap ) );
		window.maxSize = new Vector2( 200, 125 );
		window.Show();
	}
	  
	public void OnGUI()
	{
		// Debug.Log("AutoSnap: OnGUI");
		  
		doSnap = EditorGUILayout.Toggle( "Auto Snap", doSnap );
		doScaleSnap = EditorGUILayout.Toggle( "Auto Snap Scale", doScaleSnap);
		doRotateSnap = EditorGUILayout.Toggle ("Auto Snap Rotation", doRotateSnap);

		snapValueX = EditorGUILayout.FloatField( "Snap X Value", snapValueX );
		snapValueY = EditorGUILayout.FloatField( "Snap Y Value", snapValueY );
		snapValueZ = EditorGUILayout.FloatField( "Snap Z Value", snapValueZ );

		snapRotateValue = EditorGUILayout.FloatField ("Rotation Snap Value", snapRotateValue);
	}
	  
	public void Update()
	{
		if (!EditorApplication.isPlaying && Selection.transforms.Length > 0)
		{
			// Debug.Log("AutoSnap: Update");
		
			if ( doSnap				
				&& Selection.transforms[0].position != prevPosition )
			{
				Snap();
				prevPosition = Selection.transforms[0].position;
			}
			
			if ( doScaleSnap
				&& Selection.transforms[0].localScale != prevScale)
			{
				ScaleSnap();
				prevScale = Selection.transforms[0].localScale;
			}
  
			if ( doRotateSnap
				&& Selection.transforms[0].eulerAngles != prevRotation )
			{
				RotateSnap();
				prevRotation = Selection.transforms[0].eulerAngles;
			}
		}
	}
  
	private void Snap()
	{
		// Debug.Log("AutoSnap: Snap");
		  
		foreach ( var transform in Selection.transforms )
		{
			var t = transform.transform.position;
			t.x = RoundX( t.x );
			t.y = RoundY( t.y );
			t.z = RoundZ( t.z );
			transform.transform.position = t;
		}
	}
	  
	private void ScaleSnap()
	{
		// Debug.Log("AutoSnap: ScaleSnap");
		  
		foreach ( var transform in Selection.transforms )
		{
			var s = transform.transform.localScale;
			s.x = ScaleRoundX(s.x);
			s.y = ScaleRoundY(s.y);
			s.z = ScaleRoundZ(s.z);
			transform.transform.localScale = s;
		}
	}
  
	private void RotateSnap()
	{
		// Debug.Log("AutoSnap: RotateSnap");
		  
		foreach (var transform in Selection.transforms)
		{
			var r = transform.transform.eulerAngles;
			r.x = RotateRound (r.x);
			r.y = RotateRound (r.y);
			r.z = RotateRound (r.z);
			transform.transform.eulerAngles = r;
		}
	}
	  
	private float RoundX( float input )
	{
		return snapValueX * Mathf.Round( ( input / snapValueX ) );
	}
	  
	private float RoundY( float input )
	{
		return snapValueY * Mathf.Round( ( input / snapValueY ) );
	}
	  
	private float RoundZ( float input )
	{
		return snapValueZ * Mathf.Round( ( input / snapValueZ ) );
	}
	
	private float ScaleRoundX( float input )
	{
		return snapValueX * Mathf.Round( ( input / snapValueX ) );
	}
	  
	private float ScaleRoundY( float input )
	{
		return snapValueY * Mathf.Round( ( input / snapValueY ) );
	}
	  
	private float ScaleRoundZ( float input )
	{
		return snapValueZ * Mathf.Round( ( input / snapValueZ ) );
	}
  
	private float RotateRound( float input )
	{
		return snapRotateValue * Mathf.Round( ( input / snapRotateValue ) );
	}
  
	public void OnEnable() 
	{
		// Debug.Log("AutoSnap: OnEnable");
		  
		if (EditorPrefs.HasKey(doSnapKey)) 
		{
			 doSnap = EditorPrefs.GetBool(doSnapKey);
		}
		
		if (EditorPrefs.HasKey(doScaleSnapKey))
		{
			doScaleSnap = EditorPrefs.GetBool(doScaleSnapKey);
		}
		
		if (EditorPrefs.HasKey(doRotateSnapKey)) 
		{
			 doRotateSnap = EditorPrefs.GetBool(doRotateSnapKey);
		}
		
		if (EditorPrefs.HasKey(snapValueXKey)) 
		{
			 snapValueX = EditorPrefs.GetFloat(snapValueXKey);
		}
		
		if (EditorPrefs.HasKey(snapValueYKey)) 
		{
			 snapValueY = EditorPrefs.GetFloat(snapValueYKey);
		}
		
		if (EditorPrefs.HasKey(snapValueZKey)) 
		{
			 snapValueZ = EditorPrefs.GetFloat(snapValueZKey);
		}
		
		if (EditorPrefs.HasKey(snapRotateValueKey)) 
		{
			 snapRotateValue = EditorPrefs.GetFloat(snapRotateValueKey);
		}
		
		// Here, if a previous auto snap window was doing updates,
		// remove it
		if (updateWindow != null)
		{
			EditorApplication.update -= updateWindow.Update;
		}
 
		// Now make this window handle the updates
		EditorApplication.update += Update;
	}
 
	public void OnDisable()
	{
		Debug.Log("AutoSnap: OnDisable");
		  
		EditorPrefs.SetBool(doSnapKey, doSnap);
		EditorPrefs.SetBool(doScaleSnapKey, doScaleSnap);
		EditorPrefs.SetBool(doRotateSnapKey, doRotateSnap);
		EditorPrefs.SetFloat(snapValueXKey, snapValueX);
		EditorPrefs.SetFloat(snapValueYKey, snapValueY);
		EditorPrefs.SetFloat(snapValueZKey, snapValueZ);
		EditorPrefs.SetFloat(snapRotateValueKey, snapRotateValue);
		
		// Remember we're doing the updates
		updateWindow = this;
		
		// Normally you'd remove the window, however we don't
		// as we want the snapping to continue when this window is closed
		//EditorApplication.update -= Update;
	}
}

Hi all,

Here is AutoSnap modified to save your previous Snap Values (C#):

using UnityEngine; using UnityEditor;

 public class AutoSnap : EditorWindow
 {
     private Vector3 prevPosition;
     private Vector3 prevRotation;
     private bool doSnap = true;
     private bool doRotateSnap = true;
     private float snapValueX = 1;
     private float snapValueY = 1;
     private float snapValueZ = 1;
     private float snapRotateValue = 1;

    private const string doSnapKey        = "AutoSnap_doSnapKey";
    private const string doRotateSnapKey  = "AutoSnap_doRotateSnapKey";
    private const string snapValueXKey    = "AutoSnap_snapValueXKey";
    private const string snapValueYKey    = "AutoSnap_snapValueYKey";
    private const string snapValueZKey    = "AutoSnap_snapValueZKey";
    private const string snapRotateValueKey = "AutoSnap_snapRotateValueKey";

     [MenuItem( "Edit/Auto Snap %_l" )]
     
     static void Init()
     {
         AutoSnap window = (AutoSnap)EditorWindow.GetWindow( typeof( AutoSnap ) );
         window.maxSize = new Vector2( 200, 125 );
     }
     
     public void OnGUI()
     {
         doSnap = EditorGUILayout.Toggle( "Auto Snap", doSnap );
         doRotateSnap = EditorGUILayout.Toggle ("Auto Snap Rotation", doRotateSnap);
         snapValueX = EditorGUILayout.FloatField( "Snap X Value", snapValueX );
         snapValueY = EditorGUILayout.FloatField( "Snap Y Value", snapValueY );
         snapValueZ = EditorGUILayout.FloatField( "Snap Z Value", snapValueZ );
         snapRotateValue = EditorGUILayout.FloatField ("Rotation Snap Value", snapRotateValue);
     }
     
     public void Update()
     {
         if ( doSnap
             && !EditorApplication.isPlaying
             && Selection.transforms.Length > 0
             && Selection.transforms[0].position != prevPosition )
         {
             Snap();
             prevPosition = Selection.transforms[0].position;
         }
 
         if ( doRotateSnap
             && !EditorApplication.isPlaying
             && Selection.transforms.Length > 0
             && Selection.transforms[0].eulerAngles != prevRotation )
         {
             RotateSnap();
             prevRotation = Selection.transforms[0].eulerAngles;
             //Debug.Log("Value of rotation " + Selection.transforms[0].rotation);
             //Debug.Log ("Value of old Rotation " + prevRotation);
         }
     }
 
     private void Snap()
     {
         foreach ( var transform in Selection.transforms )
         {
             var t = transform.transform.position;
             t.x = RoundX( t.x );
             t.y = RoundY( t.y );
             t.z = RoundZ( t.z );
             transform.transform.position = t;
         }
     }
 
     private void RotateSnap()
     {
         foreach (var transform in Selection.transforms)
         {
             var r = transform.transform.eulerAngles;
             r.x = RotRound (r.x);
             r.y = RotRound (r.y);
             r.z = RotRound (r.z);
             transform.transform.eulerAngles = r;
         }
     }
     
     private float RoundX( float input )
     {
         return snapValueX * Mathf.Round( ( input / snapValueX ) );
     }
     private float RoundY( float input )
     {
         return snapValueY * Mathf.Round( ( input / snapValueY ) );
     }
     private float RoundZ( float input )
     {
         return snapValueZ * Mathf.Round( ( input / snapValueZ ) );
     }
 
     private float RotRound( float input )
     {
         //Debug.Log ("The division is: " + (input / snapRotateValue ) );
         //Debug.Log ("The rounding is: " + Mathf.Round( ( input / snapRotateValue ) ) );
         //Debug.Log ("The return is: " + (snapRotateValue * Mathf.Round( ( input / snapRotateValue ) )));
         return snapRotateValue * Mathf.Round( ( input / snapRotateValue ) );
     }
 
     public void OnEnable() {
        if (EditorPrefs.HasKey(doSnapKey)) {
            doSnap = EditorPrefs.GetBool(doSnapKey);
        }
        if (EditorPrefs.HasKey(doRotateSnapKey)) {
            doRotateSnap = EditorPrefs.GetBool(doRotateSnapKey);
        }
        if (EditorPrefs.HasKey(snapValueXKey)) {
            snapValueX = EditorPrefs.GetFloat(snapValueXKey);
        }
        if (EditorPrefs.HasKey(snapValueYKey)) {
            snapValueY = EditorPrefs.GetFloat(snapValueYKey);
        }
        if (EditorPrefs.HasKey(snapValueZKey)) {
            snapValueZ = EditorPrefs.GetFloat(snapValueZKey);
        }
        if (EditorPrefs.HasKey(snapRotateValueKey)) {
            snapRotateValue = EditorPrefs.GetFloat(snapRotateValueKey);
        }

        EditorApplication.update += Update;
     }

     public void OnDisable() {
        EditorPrefs.SetBool(doSnapKey, doSnap);
        EditorPrefs.SetBool(doRotateSnapKey, doRotateSnap);
        EditorPrefs.SetFloat(snapValueXKey, snapValueX);
        EditorPrefs.SetFloat(snapValueYKey, snapValueY);
        EditorPrefs.SetFloat(snapValueZKey, snapValueZ);
        EditorPrefs.SetFloat(snapRotateValueKey, snapRotateValue);
     }
 }

Also if you change your code to this it will allow for rotational snapping as well, this is in c#, credit goes to robertbu at Snapping Quaternion Rotations in Script - Questions & Answers - Unity Discussions for the code snippets, I just put it together.

`


using UnityEngine;
using UnityEditor;

public class AutoSnap : EditorWindow
{
	private Vector3 prevPosition;
	private Vector3 prevRotation;
	private bool doSnap = true;
	private bool doRotateSnap = true;
	private float snapValue = 1;
	private float snapRotateValue = 1;
	
	[MenuItem( "Edit/Auto Snap %_l" )]
	
	static void Init()
	{
		var window = (AutoSnap)EditorWindow.GetWindow( typeof( AutoSnap ) );
		window.maxSize = new Vector2( 200, 100 );
	}
	
	public void OnGUI()
	{
		doSnap = EditorGUILayout.Toggle( "Auto Snap", doSnap );
		doRotateSnap = EditorGUILayout.Toggle ("Auto Snap Rotation", doRotateSnap);
		snapValue = EditorGUILayout.FloatField( "Snap Value", snapValue );
		snapRotateValue = EditorGUILayout.FloatField ("Rotation Snap Value", snapRotateValue);
	}
	
	public void Update()
	{
		if ( doSnap
		    && !EditorApplication.isPlaying
		    && Selection.transforms.Length > 0
		    && Selection.transforms[0].position != prevPosition )
		{
			Snap();
			prevPosition = Selection.transforms[0].position;
		}

		if ( doRotateSnap
			&& !EditorApplication.isPlaying
			&& Selection.transforms.Length > 0
			&& Selection.transforms[0].eulerAngles != prevRotation )
		{
			RotateSnap();
			prevRotation = Selection.transforms[0].eulerAngles;
			//Debug.Log("Value of rotation " + Selection.transforms[0].rotation);
			//Debug.Log ("Value of old Rotation " + prevRotation);
		}
	}

	private void Snap()
	{
		foreach ( var transform in Selection.transforms )
		{
			var t = transform.transform.position;
			t.x = Round( t.x );
			t.y = Round( t.y );
			t.z = Round( t.z );
			transform.transform.position = t;
		}
	}

	private void RotateSnap()
	{
		foreach (var transform in Selection.transforms)
		{
			var r = transform.transform.eulerAngles;
			r.x = RotRound (r.x);
			r.y = RotRound (r.y);
			r.z = RotRound (r.z);
			transform.transform.eulerAngles = r;
		}
	}
	
	private float Round( float input )
	{
		return snapValue * Mathf.Round( ( input / snapValue ) );
	}

	private float RotRound( float input )
	{
		Debug.Log ("The division is: " + (input / snapRotateValue ) );
		Debug.Log ("The rounding is: " + Mathf.Round( ( input / snapRotateValue ) ) );
		Debug.Log ("The return is: " + (snapRotateValue * Mathf.Round( ( input / snapRotateValue ) )));
		return snapRotateValue * Mathf.Round( ( input / snapRotateValue ) );
	}

	public void OnEnable() { EditorApplication.update += Update; }
}

`

@imekon @karl_ Thank you !

Updated the Snap method to support RectTransform’s that are part of the UI system

private void Snap()
	{
		foreach ( var transform in Selection.transforms )
		{
			RectTransform rectTrans = transform.transform as RectTransform;
			if (rectTrans) {
				var pos = rectTrans.anchoredPosition;
				pos.x = Round(pos.x);
				pos.y = Round(pos.y);
				rectTrans.anchoredPosition = pos;
				var size = rectTrans.sizeDelta;
				size.x = Round(size.x);
				size.y = Round(size.y);
				rectTrans.sizeDelta = size;
			}
			else {
				var t = transform.transform.position;
				t.x = Round( t.x );
				t.y = Round( t.y );
				t.z = Round( t.z );
				transform.transform.position = t;
			}
		}
	}

For me this was all I needed. Add this script to a game object that exists only once in the scene.

using Unity.Mathematics;
using UnityEditor;
using UnityEngine;

[ExecuteInEditMode]
class SelectionSnap : MonoBehaviour
{
    void Update()
    {
#if UNITY_EDITOR
        foreach (var transform in Selection.transforms)
            transform.position = math.round(transform.position);
#endif
    }
}

No, there is not a toggle for this. And I do not know the best way to add this.