Skip to content

Commit 625d686

Browse files
committed
SetPivot editor window
1 parent edb5d72 commit 625d686

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

Scripts/Editor/SetPivot.cs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Version: 1.0
3+
* Author: Yilmaz Kiymaz (@VoxelBoy)
4+
* Purpose: To be able to change the pivot of Game Objects
5+
* without needing to use a separate 3D application.
6+
* License: Free to use and distribute, in both free and commercial projects.
7+
* Do not try to sell as your own work. Simply put, play nice :)
8+
* Contact: VoxelBoy on Unity Forums
9+
*/
10+
11+
/*
12+
* TODO:
13+
* - Doesn't work properly with rotated objects.
14+
* - Can't compensate for the positioning of Mesh Colliders.
15+
* - Need to figure out if the "Instantiating mesh" error in Editor is a big issue, if not, how to supress it.
16+
* - Allowing the pivot to move outside the bounds of the mesh, ideally using the movement gizmo but only affecting the pivot.
17+
*/
18+
19+
20+
using UnityEngine;
21+
using UnityEditor;
22+
23+
public class SetPivot : EditorWindow {
24+
25+
Vector3 p; //Pivot value -1..1, calculated from Mesh bounds
26+
Vector3 last_p; //Last used pivot
27+
28+
GameObject obj; //Selected object in the Hierarchy
29+
MeshFilter meshFilter; //Mesh Filter of the selected object
30+
Mesh mesh; //Mesh of the selected object
31+
Collider col; //Collider of the selected object
32+
33+
bool pivotUnchanged; //Flag to decide when to instantiate a copy of the mesh
34+
35+
[MenuItem ("GameObject/Set Pivot")] //Place the Set Pivot menu item in the GameObject menu
36+
static void Init () {
37+
SetPivot window = (SetPivot)EditorWindow.GetWindow (typeof (SetPivot));
38+
window.RecognizeSelectedObject(); //Initialize the variables by calling RecognizeSelectedObject on the class instance
39+
window.Show ();
40+
}
41+
42+
void OnGUI() {
43+
if(obj) {
44+
if(mesh) {
45+
p.x = EditorGUILayout.Slider("X", p.x, -1.0f, 1.0f);
46+
p.y = EditorGUILayout.Slider("Y", p.y, -1.0f, 1.0f);
47+
p.z = EditorGUILayout.Slider("Z", p.z, -1.0f, 1.0f);
48+
if(p != last_p) { //Detects user input on any of the three sliders
49+
//Only create instance of mesh when user changes pivot
50+
if(pivotUnchanged) mesh = meshFilter.mesh; pivotUnchanged = false;
51+
UpdatePivot();
52+
last_p = p;
53+
}
54+
if(GUILayout.Button("Center")) { //Set pivot to the center of the mesh bounds
55+
//Only create instance of mesh when user changes pivot
56+
if(pivotUnchanged) mesh = meshFilter.mesh; pivotUnchanged = false;
57+
p = Vector3.zero;
58+
UpdatePivot();
59+
last_p = p;
60+
}
61+
GUILayout.Label("Bounds " + mesh.bounds.ToString());
62+
} else {
63+
GUILayout.Label("Selected object does not have a Mesh specified.");
64+
}
65+
} else {
66+
GUILayout.Label("No object selected in Hierarchy.");
67+
}
68+
}
69+
70+
//Achieve the movement of the pivot by moving the transform position in the specified direction
71+
//and then moving all vertices of the mesh in the opposite direction back to where they were in world-space
72+
void UpdatePivot() {
73+
Vector3 diff = Vector3.Scale(mesh.bounds.extents, last_p - p); //Calculate difference in 3d position
74+
obj.transform.position -= Vector3.Scale(diff, obj.transform.localScale); //Move object position by taking localScale into account
75+
//Iterate over all vertices and move them in the opposite direction of the object position movement
76+
Vector3[] verts = mesh.vertices;
77+
for(int i=0; i<verts.Length; i++) {
78+
verts[i] += diff;
79+
}
80+
mesh.vertices = verts; //Assign the vertex array back to the mesh
81+
mesh.RecalculateBounds(); //Recalculate bounds of the mesh, for the renderer's sake
82+
//The 'center' parameter of certain colliders needs to be adjusted
83+
//when the transform position is modified
84+
if(col) {
85+
if(col is BoxCollider) {
86+
((BoxCollider) col).center += diff;
87+
} else if(col is CapsuleCollider) {
88+
((CapsuleCollider) col).center += diff;
89+
} else if(col is SphereCollider) {
90+
((SphereCollider) col).center += diff;
91+
}
92+
}
93+
}
94+
95+
//Look at the object's transform position in comparison to the center of its mesh bounds
96+
//and calculate the pivot values for xyz
97+
void UpdatePivotVector() {
98+
Bounds b = mesh.bounds;
99+
Vector3 offset = -1 * b.center;
100+
p = last_p = new Vector3(offset.x / b.extents.x, offset.y / b.extents.y, offset.z / b.extents.z);
101+
}
102+
103+
//When a selection change notification is received
104+
//recalculate the variables and references for the new object
105+
void OnSelectionChange() {
106+
RecognizeSelectedObject();
107+
}
108+
109+
//Gather references for the selected object and its components
110+
//and update the pivot vector if the object has a Mesh specified
111+
void RecognizeSelectedObject() {
112+
Transform t = Selection.activeTransform;
113+
obj = t ? t.gameObject : null;
114+
if(obj) {
115+
meshFilter = obj.GetComponent(typeof(MeshFilter)) as MeshFilter;
116+
mesh = meshFilter ? meshFilter.sharedMesh : null;
117+
if(mesh)
118+
UpdatePivotVector();
119+
col = obj.GetComponent(typeof(Collider)) as Collider;
120+
pivotUnchanged = true;
121+
} else {
122+
mesh = null;
123+
}
124+
}
125+
}

0 commit comments

Comments
 (0)