Skip to content

Instantly share code, notes, and snippets.

@levilansing
Created February 6, 2018 04:13
Show Gist options
  • Save levilansing/9bbbc7985c7c4896426f125526af7fe4 to your computer and use it in GitHub Desktop.
Save levilansing/9bbbc7985c7c4896426f125526af7fe4 to your computer and use it in GitHub Desktop.
Unity3d Editor script to put pivot point in ProBuilder objects back on the mesh after manipulating the faces/edges/verts
/* Fix ProBuilder Pivot
* An action to move the pivot back to the mesh in cases where you've
* manipulated the edges/faces of a mesh and left the pivot far behind
* Author: Levi Lansing (https://github.com/levilansing)
* Feb 2018
*/
using UnityEngine;
using UnityEditor;
using ProBuilder2.Common;
using ProBuilder2.EditorCommon;
namespace Zephlabs.Actions
{
/**
* This class is responsible for loading the pb_MenuAction into the toolbar and menu.
*/
[InitializeOnLoad]
static class RegisterCustomAction {
/**
* Static initializer is called when Unity loads the assembly.
*/
static RegisterCustomAction()
{
// This registers a new MakeFacesDoubleSided menu action with the toolbar.
pb_EditorToolbarLoader.RegisterMenuItem(InitCustomAction);
}
/**
* Helper function to load a new menu action object.
*/
static pb_MenuAction InitCustomAction()
{
return new FixProBuilderPivot();
}
/**
* Usually you'll want to add a menu item entry for your action.
* https://docs.unity3d.com/ScriptReference/MenuItem.html
*/
[MenuItem("Tools/ProBuilder/Fix Pivot %#&F", true)]
static bool MenuVerifyDoSomethingWithPbObject()
{
// Using pb_EditorToolbarLoader.GetInstance keeps MakeFacesDoubleSided as a singleton.
FixProBuilderPivot instance = pb_EditorToolbarLoader.GetInstance<FixProBuilderPivot>();
return instance != null && instance.IsEnabled();
}
[MenuItem("Tools/ProBuilder/Fix Pivot %#&F", false, pb_Constant.MENU_GEOMETRY + 3)]
static void MenuDoDoSomethingWithPbObject()
{
FixProBuilderPivot instance = pb_EditorToolbarLoader.GetInstance<FixProBuilderPivot>();
if(instance != null)
pb_EditorUtility.ShowNotification(instance.DoAction().notification);
}
}
/**
* This is the actual action that will be executed.
*/
public class FixProBuilderPivot : pb_MenuAction
{
public override pb_ToolbarGroup group { get { return pb_ToolbarGroup.Geometry; } }
public override Texture2D icon { get { return null; } }
public override pb_TooltipContent tooltip { get { return _tooltip; } }
/**
* What to show in the hover tooltip window. pb_TooltipContent is similar to GUIContent, with the exception that it also
* includes an optional params[] char list in the constructor to define shortcut keys (ex, CMD_CONTROL, K).
*/
static readonly pb_TooltipContent _tooltip = new pb_TooltipContent
(
"Fix Pivot",
"Moves the pivot to a vertex on the edge of the mesh."
);
/**
* Determines if the action should be enabled or grayed out.
*/
public override bool IsEnabled()
{
// `selection` is a helper property on pb_MenuAction that returns a pb_Object[] array from the current selection.
return pb_Editor.instance != null && selection != null && selection.Length > 0;
}
/**
* Determines if the action should be loaded in the menu (ex, face actions shouldn't be shown when in vertex editing mode).
*/
public override bool IsHidden()
{
return pb_Editor.instance == null || pb_Editor.instance.editLevel != EditLevel.Geometry;
}
/**
* Do the thing. Return a pb_ActionResult indicating the success/failure of action.
*/
public override pb_ActionResult DoAction()
{
pbUndo.RecordObjects(selection, "Fix Pivot");
foreach(pb_Object pb in selection)
{
// find bottom-most, left-most, nearest vertex
var index = 0;
var mf = pb.GetComponent<MeshFilter>();
if (mf != null) {
var mesh = mf.sharedMesh;
if (mesh) {
var minY = mesh.vertices[0].y;
for (int i = 0; i < mesh.vertices.Length; i++) {
var vert = mesh.vertices[i];
if (minY > vert.y) {
minY= vert.y;
index = i;
}
}
var minX = mesh.vertices[index].x;
for (int i = 0; i < mesh.vertices.Length; i++) {
var vert = mesh.vertices[i];
if (Mathf.Approximately(vert.y, minY) && minX > vert.x) {
minX = vert.x;
index = i;
}
}
var minZ = mesh.vertices[index].z;
for (int i = 0; i < mesh.vertices.Length; i++) {
var vert = mesh.vertices[i];
if (Mathf.Approximately(vert.y, minY) && Mathf.Approximately(vert.x, minX) && minZ > vert.z) {
minZ = vert.z;
index = i;
}
}
}
}
pb_EditorUtility.SetPivotAndSnapWithPref(pb, new int[] { index });
pb.ToMesh();
pb.Refresh();
pb.Optimize();
}
// This is necessary! Otherwise the pb_Editor will be working with caches from
// outdated meshes and throw errors.
pb_Editor.Refresh();
return new pb_ActionResult(Status.Success, "Fix Pivot");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment