Search Unity

Snapping to vertex on one axis only (while holding V in scene editor)?

Discussion in 'Editor & General Support' started by redmotion_games, Dec 19, 2020.

  1. redmotion_games

    redmotion_games

    Joined:
    May 6, 2013
    Posts:
    84
    In the Unity scene editor, I'd like to position an object in relation to another one nearby. In a 3d software, I could move it once in one or two axis' horizontally first and then move it again to align it vertically.

    To do this, I would need to be able to lock one or two axis'. For example, to move an object down to snap in the Z axis, you can temporarily disable the X and Y movement.

    In Blender you would press Z to lock an object you're moving to the Z axis or shift-Z to lock it to X and Y.

    Is there a way to do this with a Unity editor script?

    Could it be scripted? Is there an asset in the asset store that allows this?
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    Are you trying to move the object via an editor script, or via your mouse?

    If it's your mouse, you can just use the individual arrows on the position gizmo to move the object on only a particular axis, or use one of the 3 small "squares" at the center of the gizmo to move the object along a particular plane (along 2 axes).

    https://docs.unity3d.com/Manual/PositioningGameObjects.html
     
  3. Kragh

    Kragh

    Joined:
    Jan 22, 2008
    Posts:
    657
    "Snapping to vertex". It's in the title ;)

    And I am looking for the same functionality... Holding v to snap vertices is great and all, but one would normally also have the functionality to constrain the vertex-snap along a chosen axis. I haven't found this to be possible in Unity. But I will code it myself now
     
  4. Kragh

    Kragh

    Joined:
    Jan 22, 2008
    Posts:
    657
    Ok, I have made a thing. It might have been made before by others, but at least I never found it.
    This recreate some functionality I have been missing from 3Ds Max, and which the OP also seem to need, where you can constrain movement in the editor to only one axis, even when snapping to vertices and such. It is an Overlay script with a new element that goes along. And so it NEEDS to be placed in folder called "Editor" (Filename: AxisConstrainOverlay.cs).

    To activate it you as you do with other scene overlay tools: Three dots->Overlay Menu->Axis Constrain
    It's a toggle and dropdown in one, and can be activated and deactived by clicking the name, and the axis chosen by clicking the arrow. Also F5, F6 and F7 changes the axis (And if held down while the tool is deactive, it will activate until key up)

    Anyways. Fun to make, learned something new. Some hacks in it (Don't mention the icon creation!!!), but otherwise pretty robust. Probably did something backwards, but it is what it is :D


    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using UnityEditor.Toolbars;
    4. using UnityEditor.Overlays;
    5. using UnityEngine.UIElements;
    6. using UnityEditor;
    7.  
    8. [Overlay(typeof(SceneView), "AxisConstrain", "Axis Constrain", true)]
    9. public class AxisConstrainOverlay : ToolbarOverlay
    10. {
    11.     public static Dictionary<Transform, Vector3> initPositions = new Dictionary<Transform, Vector3>();
    12.     public static Texture2D icon;
    13.     AxisConstrainOverlay() : base(
    14.         AxisDropDown.id
    15.         )
    16.     {
    17.         icon = Icon();
    18.         collapsedIcon = icon;
    19.     }
    20.  
    21.     public static Texture2D Icon ()
    22.     {
    23.         //Build the icon to prevent needing an asset for it. Oh well...
    24.         Color[] txColor = new Color[256];
    25.         txColor[0] = new Color(1f, 1f, 1f, 0f);
    26.         txColor[1] = new Color(1f, 1f, 1f, 0f);
    27.         txColor[2] = new Color(1f, 1f, 1f, 0f);
    28.         txColor[3] = new Color(1f, 1f, 1f, 0f);
    29.         txColor[4] = new Color(1f, 1f, 1f, 0f);
    30.         txColor[5] = new Color(1f, 1f, 1f, 0f);
    31.         txColor[6] = new Color(1f, 1f, 1f, 0f);
    32.         txColor[7] = new Color(1f, 1f, 1f, 0f);
    33.         txColor[8] = new Color(1f, 1f, 1f, 0f);
    34.         txColor[9] = new Color(1f, 1f, 1f, 0f);
    35.         txColor[10] = new Color(1f, 1f, 1f, 0f);
    36.         txColor[11] = new Color(1f, 1f, 1f, 0f);
    37.         txColor[12] = new Color(1f, 1f, 1f, 0f);
    38.         txColor[13] = new Color(1f, 1f, 1f, 0f);
    39.         txColor[14] = new Color(1f, 1f, 1f, 0f);
    40.         txColor[15] = new Color(1f, 1f, 1f, 0f);
    41.         txColor[16] = new Color(1f, 1f, 1f, 0f);
    42.         txColor[17] = new Color(1f, 1f, 1f, 0f);
    43.         txColor[18] = new Color(1f, 1f, 1f, 0f);
    44.         txColor[19] = new Color(1f, 1f, 1f, 0f);
    45.         txColor[20] = new Color(1f, 1f, 1f, 0f);
    46.         txColor[21] = new Color(1f, 1f, 1f, 0f);
    47.         txColor[22] = new Color(1f, 1f, 1f, 0f);
    48.         txColor[23] = new Color(1f, 1f, 1f, 0f);
    49.         txColor[24] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    50.         txColor[25] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    51.         txColor[26] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    52.         txColor[27] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    53.         txColor[28] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    54.         txColor[29] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    55.         txColor[30] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    56.         txColor[31] = new Color(1f, 1f, 1f, 0f);
    57.         txColor[32] = new Color(1f, 1f, 1f, 0f);
    58.         txColor[33] = new Color(1f, 1f, 1f, 0f);
    59.         txColor[34] = new Color(1f, 1f, 1f, 0f);
    60.         txColor[35] = new Color(1f, 1f, 1f, 0f);
    61.         txColor[36] = new Color(1f, 1f, 1f, 0f);
    62.         txColor[37] = new Color(1f, 1f, 1f, 0f);
    63.         txColor[38] = new Color(1f, 1f, 1f, 0f);
    64.         txColor[39] = new Color(1f, 1f, 1f, 0f);
    65.         txColor[40] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    66.         txColor[41] = new Color(1f, 0.4313726f, 0.2509804f, 0f);
    67.         txColor[42] = new Color(1f, 0.4313726f, 0.2509804f, 0f);
    68.         txColor[43] = new Color(1f, 0.4313726f, 0.2509804f, 0f);
    69.         txColor[44] = new Color(1f, 0.4313726f, 0.2509804f, 0f);
    70.         txColor[45] = new Color(1f, 0.4313726f, 0.2509804f, 0f);
    71.         txColor[46] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    72.         txColor[47] = new Color(1f, 1f, 1f, 0f);
    73.         txColor[48] = new Color(1f, 1f, 1f, 0f);
    74.         txColor[49] = new Color(1f, 1f, 1f, 0f);
    75.         txColor[50] = new Color(1f, 1f, 1f, 0f);
    76.         txColor[51] = new Color(1f, 1f, 1f, 0f);
    77.         txColor[52] = new Color(1f, 1f, 1f, 0f);
    78.         txColor[53] = new Color(1f, 1f, 1f, 0f);
    79.         txColor[54] = new Color(1f, 1f, 1f, 0f);
    80.         txColor[55] = new Color(1f, 1f, 1f, 0f);
    81.         txColor[56] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    82.         txColor[57] = new Color(1f, 0.4313726f, 0.2509804f, 0f);
    83.         txColor[58] = new Color(1f, 1f, 1f, 0.03921569f);
    84.         txColor[59] = new Color(1f, 1f, 1f, 0.6078432f);
    85.         txColor[60] = new Color(1f, 1f, 1f, 0.8352942f);
    86.         txColor[61] = new Color(1f, 0.4313726f, 0.2509804f, 0f);
    87.         txColor[62] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    88.         txColor[63] = new Color(1f, 1f, 1f, 0f);
    89.         txColor[64] = new Color(1f, 1f, 1f, 0f);
    90.         txColor[65] = new Color(1f, 1f, 1f, 0.2941177f);
    91.         txColor[66] = new Color(1f, 1f, 1f, 0.1960784f);
    92.         txColor[67] = new Color(1f, 1f, 1f, 0f);
    93.         txColor[68] = new Color(1f, 1f, 1f, 0f);
    94.         txColor[69] = new Color(1f, 1f, 1f, 0f);
    95.         txColor[70] = new Color(1f, 1f, 1f, 0f);
    96.         txColor[71] = new Color(1f, 1f, 1f, 0f);
    97.         txColor[72] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    98.         txColor[73] = new Color(1f, 1f, 1f, 0.1960784f);
    99.         txColor[74] = new Color(1f, 1f, 1f, 0.8470589f);
    100.         txColor[75] = new Color(1f, 1f, 1f, 0.5882353f);
    101.         txColor[76] = new Color(1f, 1f, 1f, 0.03921569f);
    102.         txColor[77] = new Color(1f, 0.4313726f, 0.2509804f, 0f);
    103.         txColor[78] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    104.         txColor[79] = new Color(1f, 1f, 1f, 0f);
    105.         txColor[80] = new Color(1f, 1f, 1f, 0f);
    106.         txColor[81] = new Color(1f, 1f, 1f, 0.282353f);
    107.         txColor[82] = new Color(1f, 1f, 1f, 0.854902f);
    108.         txColor[83] = new Color(1f, 1f, 1f, 0.7607844f);
    109.         txColor[84] = new Color(1f, 1f, 1f, 0.3333333f);
    110.         txColor[85] = new Color(1f, 1f, 1f, 0.01568628f);
    111.         txColor[86] = new Color(1f, 1f, 1f, 0f);
    112.         txColor[87] = new Color(1f, 1f, 1f, 0.003921569f);
    113.         txColor[88] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    114.         txColor[89] = new Color(1f, 1f, 1f, 0.8980393f);
    115.         txColor[90] = new Color(1f, 1f, 1f, 0.3058824f);
    116.         txColor[91] = new Color(1f, 0.4313726f, 0.2509804f, 0f);
    117.         txColor[92] = new Color(1f, 0.4313726f, 0.2509804f, 0f);
    118.         txColor[93] = new Color(1f, 0.4313726f, 0.2509804f, 0f);
    119.         txColor[94] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    120.         txColor[95] = new Color(1f, 1f, 1f, 0f);
    121.         txColor[96] = new Color(1f, 1f, 1f, 0f);
    122.         txColor[97] = new Color(1f, 1f, 1f, 0f);
    123.         txColor[98] = new Color(1f, 1f, 1f, 0.007843138f);
    124.         txColor[99] = new Color(1f, 1f, 1f, 0.2941177f);
    125.         txColor[100] = new Color(1f, 1f, 1f, 0.7254902f);
    126.         txColor[101] = new Color(1f, 1f, 1f, 0.8862746f);
    127.         txColor[102] = new Color(1f, 1f, 1f, 0.4784314f);
    128.         txColor[103] = new Color(1f, 1f, 1f, 0.7333333f);
    129.         txColor[104] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    130.         txColor[105] = new Color(1f, 1f, 1f, 0.1019608f);
    131.         txColor[106] = new Color(1f, 0.4313726f, 0.2509804f, 0f);
    132.         txColor[107] = new Color(1f, 0.4313726f, 0.2509804f, 0f);
    133.         txColor[108] = new Color(1f, 0.4313726f, 0.2509804f, 0f);
    134.         txColor[109] = new Color(1f, 0.4313726f, 0.2509804f, 0f);
    135.         txColor[110] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    136.         txColor[111] = new Color(1f, 1f, 1f, 0f);
    137.         txColor[112] = new Color(1f, 1f, 1f, 0f);
    138.         txColor[113] = new Color(1f, 1f, 1f, 0f);
    139.         txColor[114] = new Color(1f, 1f, 1f, 0f);
    140.         txColor[115] = new Color(1f, 1f, 1f, 0f);
    141.         txColor[116] = new Color(1f, 1f, 1f, 0f);
    142.         txColor[117] = new Color(1f, 1f, 1f, 0.1568628f);
    143.         txColor[118] = new Color(1f, 1f, 1f, 0.5490196f);
    144.         txColor[119] = new Color(1f, 1f, 1f, 0.937255f);
    145.         txColor[120] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    146.         txColor[121] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    147.         txColor[122] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    148.         txColor[123] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    149.         txColor[124] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    150.         txColor[125] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    151.         txColor[126] = new Color(1f, 0.4313726f, 0.2509804f, 1f);
    152.         txColor[127] = new Color(1f, 1f, 1f, 0f);
    153.         txColor[128] = new Color(1f, 1f, 1f, 0f);
    154.         txColor[129] = new Color(1f, 1f, 1f, 0f);
    155.         txColor[130] = new Color(1f, 1f, 1f, 0f);
    156.         txColor[131] = new Color(1f, 1f, 1f, 0f);
    157.         txColor[132] = new Color(1f, 1f, 1f, 0f);
    158.         txColor[133] = new Color(1f, 1f, 1f, 0f);
    159.         txColor[134] = new Color(1f, 1f, 1f, 0.05882353f);
    160.         txColor[135] = new Color(1f, 1f, 1f, 0.9411765f);
    161.         txColor[136] = new Color(1f, 1f, 1f, 0f);
    162.         txColor[137] = new Color(1f, 1f, 1f, 0f);
    163.         txColor[138] = new Color(1f, 1f, 1f, 0f);
    164.         txColor[139] = new Color(1f, 1f, 1f, 0f);
    165.         txColor[140] = new Color(1f, 1f, 1f, 0f);
    166.         txColor[141] = new Color(1f, 1f, 1f, 0f);
    167.         txColor[142] = new Color(1f, 1f, 1f, 0f);
    168.         txColor[143] = new Color(1f, 1f, 1f, 0f);
    169.         txColor[144] = new Color(1f, 1f, 1f, 0f);
    170.         txColor[145] = new Color(1f, 1f, 1f, 0f);
    171.         txColor[146] = new Color(1f, 1f, 1f, 0f);
    172.         txColor[147] = new Color(1f, 1f, 1f, 0f);
    173.         txColor[148] = new Color(1f, 1f, 1f, 0f);
    174.         txColor[149] = new Color(1f, 1f, 1f, 0f);
    175.         txColor[150] = new Color(1f, 1f, 1f, 0.05882353f);
    176.         txColor[151] = new Color(1f, 1f, 1f, 0.9411765f);
    177.         txColor[152] = new Color(1f, 1f, 1f, 0f);
    178.         txColor[153] = new Color(1f, 1f, 1f, 0f);
    179.         txColor[154] = new Color(1f, 1f, 1f, 0f);
    180.         txColor[155] = new Color(1f, 1f, 1f, 0f);
    181.         txColor[156] = new Color(1f, 1f, 1f, 0f);
    182.         txColor[157] = new Color(1f, 1f, 1f, 0f);
    183.         txColor[158] = new Color(1f, 1f, 1f, 0f);
    184.         txColor[159] = new Color(1f, 1f, 1f, 0f);
    185.         txColor[160] = new Color(1f, 1f, 1f, 0f);
    186.         txColor[161] = new Color(1f, 1f, 1f, 0f);
    187.         txColor[162] = new Color(1f, 1f, 1f, 0f);
    188.         txColor[163] = new Color(1f, 1f, 1f, 0f);
    189.         txColor[164] = new Color(1f, 1f, 1f, 0f);
    190.         txColor[165] = new Color(1f, 1f, 1f, 0f);
    191.         txColor[166] = new Color(1f, 1f, 1f, 0.05882353f);
    192.         txColor[167] = new Color(1f, 1f, 1f, 0.9411765f);
    193.         txColor[168] = new Color(1f, 1f, 1f, 0f);
    194.         txColor[169] = new Color(1f, 1f, 1f, 0f);
    195.         txColor[170] = new Color(1f, 1f, 1f, 0f);
    196.         txColor[171] = new Color(1f, 1f, 1f, 0f);
    197.         txColor[172] = new Color(1f, 1f, 1f, 0f);
    198.         txColor[173] = new Color(1f, 1f, 1f, 0f);
    199.         txColor[174] = new Color(1f, 1f, 1f, 0f);
    200.         txColor[175] = new Color(1f, 1f, 1f, 0f);
    201.         txColor[176] = new Color(1f, 1f, 1f, 0f);
    202.         txColor[177] = new Color(1f, 1f, 1f, 0f);
    203.         txColor[178] = new Color(1f, 1f, 1f, 0f);
    204.         txColor[179] = new Color(1f, 1f, 1f, 0f);
    205.         txColor[180] = new Color(1f, 1f, 1f, 0f);
    206.         txColor[181] = new Color(1f, 1f, 1f, 0f);
    207.         txColor[182] = new Color(1f, 1f, 1f, 0.05882353f);
    208.         txColor[183] = new Color(1f, 1f, 1f, 0.9411765f);
    209.         txColor[184] = new Color(1f, 1f, 1f, 0f);
    210.         txColor[185] = new Color(1f, 1f, 1f, 0f);
    211.         txColor[186] = new Color(1f, 1f, 1f, 0f);
    212.         txColor[187] = new Color(1f, 1f, 1f, 0f);
    213.         txColor[188] = new Color(1f, 1f, 1f, 0f);
    214.         txColor[189] = new Color(1f, 1f, 1f, 0f);
    215.         txColor[190] = new Color(1f, 1f, 1f, 0f);
    216.         txColor[191] = new Color(1f, 1f, 1f, 0f);
    217.         txColor[192] = new Color(1f, 1f, 1f, 0f);
    218.         txColor[193] = new Color(1f, 1f, 1f, 0f);
    219.         txColor[194] = new Color(1f, 1f, 1f, 0f);
    220.         txColor[195] = new Color(1f, 1f, 1f, 0f);
    221.         txColor[196] = new Color(1f, 1f, 1f, 0f);
    222.         txColor[197] = new Color(1f, 1f, 1f, 0f);
    223.         txColor[198] = new Color(1f, 1f, 1f, 0.05882353f);
    224.         txColor[199] = new Color(1f, 1f, 1f, 0.9411765f);
    225.         txColor[200] = new Color(1f, 1f, 1f, 0f);
    226.         txColor[201] = new Color(1f, 1f, 1f, 0f);
    227.         txColor[202] = new Color(1f, 1f, 1f, 0f);
    228.         txColor[203] = new Color(1f, 1f, 1f, 0f);
    229.         txColor[204] = new Color(1f, 1f, 1f, 0f);
    230.         txColor[205] = new Color(1f, 1f, 1f, 0f);
    231.         txColor[206] = new Color(1f, 1f, 1f, 0f);
    232.         txColor[207] = new Color(1f, 1f, 1f, 0f);
    233.         txColor[208] = new Color(1f, 1f, 1f, 0f);
    234.         txColor[209] = new Color(1f, 1f, 1f, 0f);
    235.         txColor[210] = new Color(1f, 1f, 1f, 0f);
    236.         txColor[211] = new Color(1f, 1f, 1f, 0f);
    237.         txColor[212] = new Color(1f, 1f, 1f, 0f);
    238.         txColor[213] = new Color(1f, 1f, 1f, 0f);
    239.         txColor[214] = new Color(1f, 1f, 1f, 0.05882353f);
    240.         txColor[215] = new Color(1f, 1f, 1f, 0.9411765f);
    241.         txColor[216] = new Color(1f, 1f, 1f, 0f);
    242.         txColor[217] = new Color(1f, 1f, 1f, 0f);
    243.         txColor[218] = new Color(1f, 1f, 1f, 0f);
    244.         txColor[219] = new Color(1f, 1f, 1f, 0f);
    245.         txColor[220] = new Color(1f, 1f, 1f, 0f);
    246.         txColor[221] = new Color(1f, 1f, 1f, 0f);
    247.         txColor[222] = new Color(1f, 1f, 1f, 0f);
    248.         txColor[223] = new Color(1f, 1f, 1f, 0f);
    249.         txColor[224] = new Color(1f, 1f, 1f, 0f);
    250.         txColor[225] = new Color(1f, 1f, 1f, 0f);
    251.         txColor[226] = new Color(1f, 1f, 1f, 0f);
    252.         txColor[227] = new Color(1f, 1f, 1f, 0f);
    253.         txColor[228] = new Color(1f, 1f, 1f, 0f);
    254.         txColor[229] = new Color(1f, 1f, 1f, 0f);
    255.         txColor[230] = new Color(1f, 1f, 1f, 0.03137255f);
    256.         txColor[231] = new Color(1f, 1f, 1f, 0.4705883f);
    257.         txColor[232] = new Color(1f, 1f, 1f, 0f);
    258.         txColor[233] = new Color(1f, 1f, 1f, 0f);
    259.         txColor[234] = new Color(1f, 1f, 1f, 0f);
    260.         txColor[235] = new Color(1f, 1f, 1f, 0f);
    261.         txColor[236] = new Color(1f, 1f, 1f, 0f);
    262.         txColor[237] = new Color(1f, 1f, 1f, 0f);
    263.         txColor[238] = new Color(1f, 1f, 1f, 0f);
    264.         txColor[239] = new Color(1f, 1f, 1f, 0f);
    265.         txColor[240] = new Color(1f, 1f, 1f, 0f);
    266.         txColor[241] = new Color(1f, 1f, 1f, 0f);
    267.         txColor[242] = new Color(1f, 1f, 1f, 0f);
    268.         txColor[243] = new Color(1f, 1f, 1f, 0f);
    269.         txColor[244] = new Color(1f, 1f, 1f, 0f);
    270.         txColor[245] = new Color(1f, 1f, 1f, 0f);
    271.         txColor[246] = new Color(1f, 1f, 1f, 0f);
    272.         txColor[247] = new Color(1f, 1f, 1f, 0f);
    273.         txColor[248] = new Color(1f, 1f, 1f, 0f);
    274.         txColor[249] = new Color(1f, 1f, 1f, 0f);
    275.         txColor[250] = new Color(1f, 1f, 1f, 0f);
    276.         txColor[251] = new Color(1f, 1f, 1f, 0f);
    277.         txColor[252] = new Color(1f, 1f, 1f, 0f);
    278.         txColor[253] = new Color(1f, 1f, 1f, 0f);
    279.         txColor[254] = new Color(1f, 1f, 1f, 0f);
    280.         txColor[255] = new Color(1f, 1f, 1f, 0f);
    281.         Texture2D iconTx = new Texture2D(16, 16, TextureFormat.ARGB32, false);
    282.         iconTx.filterMode = FilterMode.Point;
    283.         iconTx.wrapMode = TextureWrapMode.Clamp;
    284.         iconTx.SetPixels(txColor);
    285.         iconTx.Apply();
    286.  
    287.         return iconTx;
    288.     }
    289. }
    290.  
    291. [EditorToolbarElement(id, typeof(SceneView))]
    292. class AxisDropDown : EditorToolbarDropdownToggle, IAccessContainerWindow
    293. {
    294.  
    295.     public const string id = "AxisConstrain/Axis";
    296.     public EditorWindow containerWindow { get; set; }
    297.     public bool constrainActive;
    298.     static int axisIndex = 0;
    299.     static readonly string[] axisName = new string[] { "x", "y", "z" };
    300.  
    301.     UndoPropertyModification[] changedMods = null;
    302.     static readonly Color[] btnColors = new Color[] { new Color(0.3686275f, 0.1254902f, 0.1341253f), new Color(0.162876f, 0.3679245f, 0.126691f), new Color(0.1460929f, 0.19f, 0.4622641f) };
    303.  
    304.     bool preConstrainActive;
    305.     bool down;
    306.     public AxisDropDown()
    307.     {
    308.         //Load some values from registry to make tool persistent in editor load instances.
    309.         SetActive(EditorPrefs.GetBool("AxisConstrainActive", false), EditorPrefs.GetInt("AxisConstrainAxis", 0));
    310.  
    311.         //Subscribe the dropdown function
    312.         dropdownClicked += ShowMenu;
    313.         //Subscribe the toggle click
    314.         this.RegisterValueChangedCallback(SetConstrain);
    315.         //Subscribe to scene view changes
    316.         SceneView.duringSceneGui -= ConstrainPositions;
    317.         SceneView.duringSceneGui += ConstrainPositions;
    318.  
    319.         icon = AxisConstrainOverlay.icon;
    320.     }
    321.  
    322.     void ConstrainPositions(SceneView view)
    323.     {
    324.         //Only run when visible
    325.         if (containerWindow != null && containerWindow.TryGetOverlay("AxisConstrain", out Overlay result))
    326.         {
    327.             if (!result.displayed)
    328.             {
    329.                 SceneView.duringSceneGui -= ConstrainPositions;
    330.                 ObjectChangeEvents.changesPublished -= ObjectChangeEventsHandler;
    331.                 Undo.postprocessModifications -= PostprocessModifications;
    332.                 return;
    333.             }
    334.         }
    335.  
    336.         if (view != containerWindow)
    337.         {
    338.             return;
    339.         }
    340.  
    341.         if (constrainActive)
    342.         {
    343.             //Convert curretn rotation handle to its matrix form, so we can grab an axis
    344.             Matrix4x4 handleOrientation = Matrix4x4.TRS(Vector3.zero, Tools.handleRotation, Vector3.one);
    345.             Vector3 compareAxis = handleOrientation.GetColumn(axisIndex).normalized;
    346.  
    347.             //Do to rounding errors in floats, constraining with initial value before moving is best.
    348.             foreach (KeyValuePair<Transform, Vector3> entry in AxisConstrainOverlay.initPositions)
    349.             {
    350.                 //Delta vector of current local position vs initial local position when action started
    351.                 Vector3 moveVector = entry.Key.localPosition - entry.Value;
    352.  
    353.                 if (entry.Key.parent != null)
    354.                 {
    355.                     //The changed property is in local coordinates. Transform to world using parent
    356.                     moveVector = entry.Key.parent.localToWorldMatrix.MultiplyPoint3x4(moveVector) - entry.Key.parent.position;
    357.                 }
    358.                 //Project the delta vector on to the constrain axis (In world space)
    359.                 Vector3 modMoveVector = Vector3.Project(moveVector, compareAxis);
    360.  
    361.                 //Offset the transform by how the projected vector differs from the delta vector
    362.                 entry.Key.position += modMoveVector - moveVector;
    363.             }
    364.         }
    365.  
    366.         if (Event.current != null)
    367.         {
    368.             if (Event.current.type == EventType.MouseUp)
    369.             {
    370.                 //Clear all init positions on MouseUp, to prepare for next move action
    371.                 AxisConstrainOverlay.initPositions.Clear();
    372.             }
    373.             else if (Event.current.type == EventType.KeyDown && !down)
    374.             {
    375.                 preConstrainActive = constrainActive;
    376.            
    377.                 if (Event.current.keyCode == KeyCode.F5)
    378.                 {
    379.                     down = true;
    380.                     SetActive(true, 0);
    381.                 }
    382.                 else if (Event.current.keyCode == KeyCode.F6)
    383.                 {
    384.                     down = true;
    385.                     SetActive(true, 1);
    386.                 }
    387.                 else if (Event.current.keyCode == KeyCode.F7)
    388.                 {
    389.                     down = true;
    390.                     SetActive(true, 2);
    391.                 }
    392.             }
    393.             else if (Event.current.type == EventType.KeyUp && down)
    394.             {
    395.                 if (Event.current.keyCode == KeyCode.F5)
    396.                 {
    397.                     down = false;
    398.                     SetActive(preConstrainActive, 0);
    399.                 }
    400.                 else if (Event.current.keyCode == KeyCode.F6)
    401.                 {
    402.                     down = false;
    403.                     SetActive(preConstrainActive, 1);
    404.                 }
    405.                 else if (Event.current.keyCode == KeyCode.F7)
    406.                 {
    407.                     down = false;
    408.                     SetActive(preConstrainActive, 2);
    409.                 }
    410.             }
    411.         }
    412.     }
    413.  
    414.     void SetConstrain(ChangeEvent<bool> toggle)
    415.     {
    416.         //Save toggle state in both var and registry and appearance
    417.         SetActive(toggle.newValue, axisIndex);
    418.     }
    419.  
    420.     public UndoPropertyModification[] PostprocessModifications(UndoPropertyModification[] modifications)
    421.     {
    422.         //Save this undo event to make sure we have the initial values of the objects being moved
    423.         changedMods = modifications;
    424.         return modifications;
    425.     }
    426.  
    427.     public void ObjectChangeEventsHandler(ref ObjectChangeEventStream stream)
    428.     {
    429.         int changes = stream.length;
    430.  
    431.         for (int i = 0; i < changes && changedMods != null && changedMods.Length > 0; i++)
    432.         {
    433.             //Find the "kind" of change i
    434.             ObjectChangeKind changeKind = stream.GetEventType(i);
    435.             if (changeKind == ObjectChangeKind.ChangeGameObjectOrComponentProperties)
    436.             {
    437.                 //"Kind" is the one we are looking for: Component changes.
    438.                 //Grab the data of this change
    439.                 stream.GetChangeGameObjectOrComponentPropertiesEvent(i, out ChangeGameObjectOrComponentPropertiesEventArgs data);
    440.  
    441.                 //Get the Object of this change based on instanceID
    442.                 Object instance = EditorUtility.InstanceIDToObject(data.instanceId);
    443.  
    444.                 if (instance is Transform)
    445.                 {
    446.                     //Changed object is of type: Transform
    447.                     Transform changedTransform = instance as Transform;
    448.  
    449.                     //Check if we have this object stored already!
    450.                     if (!AxisConstrainOverlay.initPositions.ContainsKey(changedTransform))
    451.                     {
    452.                         //Create and initialize initPos with local positions of changed transform (So that components of the Vector3 localPosition that are NOT changed are still saved)
    453.                         Vector3 initPos;
    454.                         initPos = changedTransform.localPosition;
    455.  
    456.                         //Loop through undo ops and find one that matches this change
    457.                         for (int j = 0; j < changedMods.Length; j++)
    458.                         {
    459.                             UndoPropertyModification currentMod = changedMods[j];
    460.  
    461.                             if (currentMod.previousValue.target == changedTransform)
    462.                             {
    463.                                 if (float.TryParse(currentMod.previousValue.value, out float valueAsFloat))
    464.                                 {
    465.                                     //Value is a float. Find the vector component by the property path
    466.                                     if (currentMod.previousValue.propertyPath == "m_LocalPosition.x")
    467.                                     {
    468.                                         initPos.x = valueAsFloat;
    469.                                     }
    470.                                     else if (currentMod.previousValue.propertyPath == "m_LocalPosition.y")
    471.                                     {
    472.                                         initPos.y = valueAsFloat;
    473.                                     }
    474.                                     else if (currentMod.previousValue.propertyPath == "m_LocalPosition.z")
    475.                                     {
    476.                                         initPos.z = valueAsFloat;
    477.                                     }
    478.                                 }
    479.                             }
    480.                         }
    481.                         //Store init value in dict.
    482.                         AxisConstrainOverlay.initPositions.Add(changedTransform, initPos);
    483.                     }
    484.                 }
    485.             }
    486.         }
    487.     }
    488.  
    489.     void ShowMenu()
    490.     {
    491.         //Create and show drop down of toggle element. Add actions on value change
    492.         GenericMenu menu = new GenericMenu();
    493.         menu.AddItem(new GUIContent("x-axis"), axisIndex == 0, () => { SetActive(true, 0); });
    494.         menu.AddItem(new GUIContent("y-axis"), axisIndex == 1, () => { SetActive(true, 1); });
    495.         menu.AddItem(new GUIContent("z-axis"), axisIndex == 2, () => { SetActive(true, 2); });
    496.         menu.ShowAsContext();
    497.     }
    498.  
    499.     void SetActive (bool active, int axis)
    500.     {
    501.         constrainActive = active;
    502.         EditorPrefs.SetBool("AxisConstrainActive", constrainActive);
    503.         SetValueWithoutNotify(constrainActive);
    504.         axisIndex = axis;
    505.         EditorPrefs.SetInt("AxisConstrainAxis", axisIndex);
    506.         SetText();
    507.  
    508.         ObjectChangeEvents.changesPublished -= ObjectChangeEventsHandler;
    509.         Undo.postprocessModifications -= PostprocessModifications;
    510.         if (active)
    511.         {
    512.             ObjectChangeEvents.changesPublished += ObjectChangeEventsHandler;
    513.             Undo.postprocessModifications += PostprocessModifications;
    514.         }
    515.     }
    516.  
    517.     void SetText ()
    518.     {
    519.         //Change text based on if active...
    520.         if (constrainActive)
    521.         {
    522.             text = "<color=#" + ColorUtility.ToHtmlStringRGB(btnColors[axisIndex] * 4) + "><b>Constrain to " + axisName[axisIndex] + "-axis";
    523.         }
    524.         else
    525.         {
    526.             text = "<b>Axis Constrain Off";
    527.         }
    528.     }
    529. }
     
    Last edited: Oct 19, 2023