- Home /
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?
If the grid is visible it should be on. I think it's quite stupid that the toggle only affects it being visible or not. Turning on/off should also make it useful.
Answer by karl_ · Jul 27, 2011 at 02:15 AM
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[i].transform.position;
t.x = round(t.x);
t.y = round(t.y);
t.z = round(t.z);
Selection.transforms[i].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;
snappedValue = snapValue * Mathf.Round((input / snapValue));
return(snappedValue);
}
}
is this a C# script? i get this error:
NullReferenceException: Object reference not set to an instance of an object
UnityEditor.EditorWindow.GetWindow (System.Type t, Boolean utility, System.String title, Boolean focus)
UnityEditor.EditorWindow.GetWindow (System.Type t)
autoSnap.Init () (at /users/dc/Dropbox/travagent/un1/app1/Assets/Editor/GridSnap.js:12)
which is this line:
var window : autoSnap = EditorWindow.GetWindow(autoSnap);
window var is also flagged as not used...
Cool, great script, thanks!
Just a note for others, it seems that the window needs to stay open for the autosnapping to function. But you can just leave it in the background behind other windows.
You can also dock it somewhere to keep it open and out of the way.
Answer by DannyB · Sep 10, 2013 at 03:24 PM
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.
Press control while dragging
Edit snap settings in Edit > Snap Settings...
More info in this doc page
Great stuff, thanks for this.
Unity not having proper grid setup out of the box is very strange.
Personally I consider anything being off grid as a bug.
Thanks for adding this note. Logged in so I could upvote this second comment and let it be first soon.
Answer by mweldon · Apr 15, 2012 at 09:13 PM
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 ) );
}
}
Awesome job karl_ and mweldon. Above and beyond. Very generous use of your time.
If you add
void OnEnable() { EditorApplication.update += Update; }
the script will keep running even when it is in a hidden tab, or closed, which will make it truly a toggle. You'll have to open it again to disable the snapping to grid if you close it.
Answer by imekon · Dec 19, 2015 at 03:00 PM
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;
}
}
Excellent! But the rotation snap is not working correctly for me :(
Yes works great except for rotation! EDIT I'm a dummy lol. You have to turn it on for it to work. Works Great!
Still awesome! I needed that for axis independent grid snapping. Pro grids sadly doesn't support that <.< Thanks for adding this extended version.
Answer by XOR-Gaming · May 29, 2015 at 09:12 AM
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);
}
}