Skip to content

Commit

Permalink
Bugfix, UI changes and improved handling of Object conversion
Browse files Browse the repository at this point in the history
- Fixed a bug where the TrainAR authoring tool could display center instead of Pivot as the gizmo handle (which might be misleading as TrainAR always grabbs at the pivot)
- Changed and imporved the way Objects are simplified: They are now instantiated as a copy, simplified and then later on finalization replace the original GameObject in the scene
- Further improved the Conversion Window Editor GUI
  • Loading branch information
jblattgerste committed Dec 1, 2023
1 parent 2dc3306 commit 5ce7a02
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 46 deletions.
60 changes: 36 additions & 24 deletions Assets/Editor/Scripts/ConvertToTrainARObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,47 +108,59 @@ public static void AddConvertionContextItem()
}

/// <summary>
/// Initializes the conversion process for the given object.
/// Finalizes the conversion process for the given object, replacing the original object in the scene.
/// </summary>
/// <param name="selectedObject">The object that is to be converted to a TrainAR Object</param>
/// <param name="originalObject">The original GameObject in the scene.</param>
/// <param name="instantiatedPreviewObject">The instantiated copy of the GameObject.</param>
/// <param name="trainARObjectName">The specified name of the TrainAR Object.</param>
public static void InitConversion(GameObject selectedObject, string trainARObjectName)
/// <param name="pivotPointOffset">The offset of the pivot if it was moved (0,0,0 otherwise)</param>
public static void FinalizeConversion(GameObject originalObject, GameObject instantiatedPreviewObject, string trainARObjectName)
{
// If selected object is a part of a prefab instance, unpack it completely.
if (PrefabUtility.IsPartOfPrefabInstance(selectedObject))
instantiatedPreviewObject = Instantiate(instantiatedPreviewObject);

// Convert the instantiated object to a TrainAR object
instantiatedPreviewObject.AddComponent<TrainARObject>();
instantiatedPreviewObject.tag = "TrainARObject";

// Apply the TrainAR Object name
instantiatedPreviewObject.name = trainARObjectName;

// Replace original object in the scene with the instantiated object
if (originalObject != null)
{
PrefabUtility.UnpackPrefabInstance(selectedObject, PrefabUnpackMode.Completely, InteractionMode.UserAction);
instantiatedPreviewObject.transform.position = originalObject.transform.position;
instantiatedPreviewObject.transform.rotation = originalObject.transform.rotation;
instantiatedPreviewObject.transform.localScale = Vector3.one;

GameObject.DestroyImmediate(originalObject);
}

//Enables the read/write of vertices/indeces of shared meshes
EnableReadWriteOnMeshes(selectedObject);

//Combine all meshes into one
GameObject newSelectedObject = CombineMeshes(selectedObject);
Undo.RegisterCreatedObjectUndo(newSelectedObject.gameObject, "Convert to TrainAR Object");

//Convert the object to a TrainAR object
//TrainARObject.cs automatically imports dependencies and all the other necessary scripts when attached
newSelectedObject.AddComponent<TrainARObject>();
newSelectedObject.tag = "TrainARObject";

// Apply the TrainAR Object name
newSelectedObject.name = trainARObjectName;

//Reset the selection to the newly converted GameObject
Selection.activeTransform = newSelectedObject.transform;
// Reset the selection to the newly converted GameObject
Selection.activeTransform = instantiatedPreviewObject.transform;
Selection.selectionChanged.Invoke();
Debug.Log("Successfully converted GameObject to TrainAR Object.");
}


/// <summary>
/// Combines all meshes of the selected object (e.g. all meshes in child structures) into a singular mesh,
/// saving it into the Models folder and deleting all the children to make the mesh structure work with TrainAR.
/// </summary>
/// <param name="objectToCombineAllMeshesFor">The GameObject which meshes (parent and child) should be combined</param>
/// <returns></returns>
private static GameObject CombineMeshes(GameObject objectToCombineAllMeshesFor)
public static GameObject CombineMeshes(GameObject objectToCombineAllMeshesFor)
{
Undo.RegisterCreatedObjectUndo(objectToCombineAllMeshesFor.gameObject, "Convert to TrainAR Object");

// If selected object is a part of a prefab instance, unpack it completely.
if (PrefabUtility.IsPartOfPrefabInstance(objectToCombineAllMeshesFor))
{
PrefabUtility.UnpackPrefabInstance(objectToCombineAllMeshesFor, PrefabUnpackMode.Completely, InteractionMode.UserAction);
}

//Enables the read/write of vertices/indeces of shared meshes
EnableReadWriteOnMeshes(objectToCombineAllMeshesFor);

//Create a new empty parent for the combination
GameObject newGameObjectWithCombinedMeshes = new GameObject(objectToCombineAllMeshesFor.name, typeof(MeshFilter), typeof(MeshRenderer));
newGameObjectWithCombinedMeshes.transform.SetPositionAndRotation(objectToCombineAllMeshesFor.transform.position, objectToCombineAllMeshesFor.transform.rotation);
Expand Down
3 changes: 3 additions & 0 deletions Assets/Editor/Scripts/TrainAREditorMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ public static void SwitchToTrainARMode()

//Force Unity into 3D mode
SceneView.lastActiveSceneView.in2DMode = false;

//Force Unity Scene into Pivot mode
Tools.pivotMode = PivotMode.Pivot;

Debug.Log("Successfully switched to TrainAR authoring tool. ");
}
Expand Down
65 changes: 43 additions & 22 deletions Assets/Editor/Scripts/TrainARObjectConversionWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,17 @@ public class TrainARObjectConversionWindow : EditorWindow

//GUI elements and variables
private string trainARObjectName = "TrainAR Object Name";
private bool pivotWasCentered = false;
private float changedQuality = 1.0f;
private int targetMeshPolygons = 0;
private bool preserveBorderEdges = false;
private bool preserveSurfaceCurvature = false;
private bool preserveUVSeamEdges = false;
private bool preserveUVFoldoverEdges = false;
private List<Mesh> originalMeshes = new List<Mesh>();
private GameObject originalTrainARObjectReferenceInScene;
private GameObject trainARObject;
private UnityEditor.Editor gameObjectEditor;
bool advancedQualityOptionstatus = false;
private PreviewRenderUtility previewRendererUtility;
private Vector2 currentUserOptionsScrollPosition;
private Quaternion accumulatedRotation = Quaternion.Euler(0, 0, 0);
Expand All @@ -64,22 +65,14 @@ public class TrainARObjectConversionWindow : EditorWindow
void OnEnable()
{
// Get the selected TrainAR Object when Editor Window is created
trainARObject = GameObject.Instantiate(Selection.activeTransform.gameObject);
originalTrainARObjectReferenceInScene = Selection.activeTransform.gameObject;
trainARObject = GameObject.Instantiate(originalTrainARObjectReferenceInScene);
trainARObject.transform.position = Vector3.zero;
trainARObject.hideFlags = HideFlags.HideAndDontSave;

trainARObject.hideFlags = HideFlags.None;
// Add the window to the list of active windows
activeWindows.Add(this);

// Safe the original Meshfilters
foreach (MeshFilter meshFilter in trainARObject.GetComponentsInChildren<MeshFilter>())
{
originalMeshes.Add(meshFilter.sharedMesh);
}

// Set the name of the GameObject as the default TrainAR Object name
trainARObjectName = trainARObject.gameObject.name;


// Title of the window
titleContent = new GUIContent("Convert TrainAR Object");

Expand All @@ -89,6 +82,20 @@ void OnEnable()
// Focus this window
this.Focus();

EditorUtility.DisplayProgressBar("Preparing GameObject", "Unpacking the GameObject and combining all meshes...", 0.99f); //At least this is some indication that something is happening...
//Combine all meshes of the TrainAR Object into one mesh
trainARObject = ConvertToTrainARObject.CombineMeshes(trainARObject);
EditorUtility.ClearProgressBar();

// Safe the original Meshfilters
foreach (MeshFilter meshFilter in trainARObject.GetComponentsInChildren<MeshFilter>())
{
originalMeshes.Add(meshFilter.sharedMesh);
}

// Set the name of the original GameObject as the default TrainAR Object name
trainARObjectName = originalTrainARObjectReferenceInScene.gameObject.name;

// Load the 3D render preview Utility
previewRendererUtility = new PreviewRenderUtility();
CreateAxisLines(trainARObject);
Expand All @@ -108,6 +115,12 @@ private void OnDisable()
{
DestroyImmediate(gameObjectEditor);
}

// Destroy the instantiated trainARObject
if (trainARObject != null)
{
DestroyImmediate(trainARObject);
}
}

void OnGUI()
Expand Down Expand Up @@ -178,6 +191,7 @@ void OnGUI()
{
trainARObject.GetComponent<MeshFilter>().sharedMesh =
CenterPivot(trainARObject.GetComponent<MeshFilter>().sharedMesh);
pivotWasCentered = true;
}

EditorGUILayout.HelpBox(
Expand Down Expand Up @@ -210,6 +224,11 @@ void OnGUI()
if (GUILayout.Button(new GUIContent("Simplify")))
{
//...

if(pivotWasCentered) //If the pivot was centered before, center it again
trainARObject.GetComponent<MeshFilter>().sharedMesh =
CenterPivot(trainARObject.GetComponent<MeshFilter>().sharedMesh);
ExtractMeshInfo(trainARObject);
}
}
else //Fast Quadric Error Metrics
Expand All @@ -223,6 +242,10 @@ void OnGUI()
// Apply Mesh simplification on the mesh filters of the original selection
ConvertToTrainARObject.SimplifyMeshes(originalMeshes, trainARObject, changedQuality,
preserveBorderEdges, preserveSurfaceCurvature, preserveUVSeamEdges, preserveUVFoldoverEdges);

if(pivotWasCentered) //If the pivot was centered before, center it again
trainARObject.GetComponent<MeshFilter>().sharedMesh =
CenterPivot(trainARObject.GetComponent<MeshFilter>().sharedMesh);

ExtractMeshInfo(trainARObject);
}
Expand Down Expand Up @@ -267,13 +290,6 @@ void OnGUI()
"This object has more than 10.000 polygons. It might take some time to convert but is ok for large or detailed objects. TrainAR trainings should not exceed 100.000 polygons in total. Consider Simplification.",
MessageType.Warning);
}
else
{
EditorGUILayout.HelpBox(
polygonCount +
" polygons looks good. Note: It is advised to not exceed 100.000 polygons for the entire training. Polygon counts >500.000 will cause performance problems.",
MessageType.Info);
}

// Continuously update the preview window
if (EditorGUI.EndChangeCheck())
Expand All @@ -288,7 +304,12 @@ void OnGUI()
convertButtonStyle.normal.textColor = Color.green;
if (GUILayout.Button("Convert to TrainAR Object", convertButtonStyle))
{
ConvertToTrainARObject.InitConversion(trainARObject, trainARObjectName);
// Destroy the Axes lines before conversion
trainARObject.transform.Cast<Transform>().ToList().ForEach(child => GameObject.DestroyImmediate(child.gameObject));
//Apply the standard shader before conversion, regardless of the selected shader for the preview
ApplyShaderToTarget("Standard");
// Finalize the conversion process
ConvertToTrainARObject.FinalizeConversion(originalTrainARObjectReferenceInScene, trainARObject, trainARObjectName);
// Editors created this way need to be destroyed explicitly
DestroyImmediate(gameObjectEditor);
Close();
Expand Down

0 comments on commit 5ce7a02

Please sign in to comment.