diff --git a/Assets/FbxExporters/Editor/ConvertToModel.cs b/Assets/FbxExporters/Editor/ConvertToModel.cs
index 129f814c4..ba94abfd5 100644
--- a/Assets/FbxExporters/Editor/ConvertToModel.cs
+++ b/Assets/FbxExporters/Editor/ConvertToModel.cs
@@ -168,7 +168,7 @@ public static GameObject Convert (
// Export to FBX. It refreshes the database.
{
- var fbxActualPath = ModelExporter.ExportObject (fbxFullPath, toConvert);
+ var fbxActualPath = ModelExporter.ExportObject (fbxFullPath, toConvert, lodExportType: EditorTools.ExportSettings.LODExportType.All);
if (fbxActualPath != fbxFullPath) {
throw new System.Exception ("Failed to convert " + toConvert.name);
}
diff --git a/Assets/FbxExporters/Editor/FbxExportSettings.cs b/Assets/FbxExporters/Editor/FbxExportSettings.cs
index 75c575292..b2269ae65 100644
--- a/Assets/FbxExporters/Editor/FbxExportSettings.cs
+++ b/Assets/FbxExporters/Editor/FbxExportSettings.cs
@@ -62,6 +62,11 @@ public override void OnInspectorGUI() {
exportSettings.ExportFormatSelection = EditorGUILayout.Popup(exportSettings.ExportFormatSelection, new string[]{"Binary", "ASCII"});
GUILayout.EndHorizontal();
+ GUILayout.BeginHorizontal();
+ EditorGUILayout.LabelField(new GUIContent("LOD Export:", "Select which LOD to export."), GUILayout.Width(LabelWidth - FieldOffset));
+ exportSettings.lodExportType = (ExportSettings.LODExportType)EditorGUILayout.Popup((int)exportSettings.lodExportType, new string[]{"All", "Highest", "Lowest"});
+ GUILayout.EndHorizontal();
+
GUILayout.BeginHorizontal();
EditorGUILayout.LabelField(new GUIContent(
"Export Path:",
@@ -442,6 +447,15 @@ public static string[] DCCVendorLocations
public int selectedDCCApp = 0;
+ [SerializeField]
+ public LODExportType lodExportType = LODExportType.All;
+
+ public enum LODExportType {
+ All = 0,
+ Highest = 1,
+ Lowest = 2
+ }
+
///
/// The path where Convert To Model will save the new fbx and prefab.
///
diff --git a/Assets/FbxExporters/Editor/FbxExporter.cs b/Assets/FbxExporters/Editor/FbxExporter.cs
index e0d921b04..0807f463f 100644
--- a/Assets/FbxExporters/Editor/FbxExporter.cs
+++ b/Assets/FbxExporters/Editor/FbxExporter.cs
@@ -7,6 +7,7 @@
using System.Linq;
using UnityEngine.Playables;
using UnityEngine.Timeline;
+using FbxExporters.EditorTools;
namespace FbxExporters
{
@@ -1922,7 +1923,9 @@ private string GetUniqueName(string name)
protected int ExportTransformHierarchy(
GameObject unityGo, FbxScene fbxScene, FbxNode fbxNodeParent,
int exportProgress, int objectCount, Vector3 newCenter,
- TransformExportType exportType = TransformExportType.Local)
+ TransformExportType exportType = TransformExportType.Local,
+ ExportSettings.LODExportType lodExportType = ExportSettings.LODExportType.All
+ )
{
int numObjectsExported = exportProgress;
@@ -1957,9 +1960,45 @@ protected int ExportTransformHierarchy(
fbxNodeParent.AddChild (fbxNode);
+ // if this object has an LOD group, then export according to the LOD preference setting
+ var lodGroup = unityGo.GetComponent();
+ if (lodGroup && lodExportType != ExportSettings.LODExportType.All) {
+ LOD[] lods = lodGroup.GetLODs ();
+
+ // LODs are ordered from highest to lowest.
+ // If exporting lowest LOD, reverse the array
+ if (lodExportType == ExportSettings.LODExportType.Lowest) {
+ // reverse the array
+ LOD[] tempLods = new LOD[lods.Length];
+ System.Array.Copy (lods, tempLods, lods.Length);
+ System.Array.Reverse (tempLods);
+ lods = tempLods;
+ }
+
+ for(int i = 0; i < lods.Length; i++){
+ var lod = lods [i];
+ bool exportedRenderer = false;
+ foreach (var renderer in lod.renderers) {
+ // only export if parented under LOD group
+ if (renderer.transform.parent == unityGo.transform) {
+ numObjectsExported = ExportTransformHierarchy (renderer.gameObject, fbxScene, fbxNode, numObjectsExported, objectCount, newCenter, lodExportType: lodExportType);
+ exportedRenderer = true;
+ } else if(Verbose) {
+ Debug.LogFormat ("FbxExporter: Not exporting LOD {0}: {1}", i, renderer.name);
+ }
+ }
+
+ // if at least one renderer for this LOD was exported, then we succeeded
+ // so stop exporting.
+ if (exportedRenderer) {
+ return numObjectsExported;
+ }
+ }
+ }
+
// now unityGo through our children and recurse
foreach (Transform childT in unityGo.transform) {
- numObjectsExported = ExportTransformHierarchy (childT.gameObject, fbxScene, fbxNode, numObjectsExported, objectCount, newCenter);
+ numObjectsExported = ExportTransformHierarchy (childT.gameObject, fbxScene, fbxNode, numObjectsExported, objectCount, newCenter, lodExportType: lodExportType);
}
return numObjectsExported;
@@ -2665,7 +2704,11 @@ public enum TransformExportType { Local, Global, Reset };
///
/// This refreshes the asset database.
///
- public int ExportAll (IEnumerable unityExportSet, Dictionary animationExportData, TransformExportType exportType = TransformExportType.Global)
+ public int ExportAll (
+ IEnumerable unityExportSet,
+ Dictionary animationExportData,
+ TransformExportType exportType = TransformExportType.Global,
+ ExportSettings.LODExportType lodExportType = ExportSettings.LODExportType.All)
{
exportCancelled = false;
@@ -2780,7 +2823,7 @@ public int ExportAll (IEnumerable unityExportSet, Dictionary
}
else {
exportProgress = this.ExportTransformHierarchy (unityGo, fbxScene, fbxRootNode,
- exportProgress, count, center, exportType);
+ exportProgress, count, center, exportType, lodExportType);
}
if (exportCancelled || exportProgress < 0) {
Debug.LogWarning ("Export Cancelled");
@@ -3545,7 +3588,7 @@ private static void OnExport (AnimationExportType exportType = AnimationExportTy
return;
}
- if (ExportObjects (filePath, exportType: exportType) != null) {
+ if (ExportObjects (filePath, exportType: exportType, lodExportType: ExportSettings.instance.lodExportType) != null) {
// refresh the asset database so that the file appears in the
// asset folder view.
AssetDatabase.Refresh ();
@@ -3556,7 +3599,12 @@ private static void OnExport (AnimationExportType exportType = AnimationExportTy
/// Export a list of (Game) objects to FBX file.
/// Use the SaveFile panel to allow user to enter a file name.
///
- public static string ExportObjects (string filePath, UnityEngine.Object[] objects = null, AnimationExportType exportType = AnimationExportType.all, TransformExportType transformExportType = TransformExportType.Global)
+ public static string ExportObjects (
+ string filePath,
+ UnityEngine.Object[] objects = null,
+ AnimationExportType exportType = AnimationExportType.all,
+ TransformExportType transformExportType = TransformExportType.Global,
+ ExportSettings.LODExportType lodExportType = ExportSettings.LODExportType.All)
{
LastFilePath = filePath;
@@ -3597,7 +3645,7 @@ public static string ExportObjects (string filePath, UnityEngine.Object[] object
break;
}
- if (fbxExporter.ExportAll (objects, animationExportData, transformExportType) > 0) {
+ if (fbxExporter.ExportAll (objects, animationExportData, transformExportType, lodExportType) > 0) {
string message = string.Format ("Successfully exported: {0}", filePath);
UnityEngine.Debug.Log (message);
@@ -3607,9 +3655,13 @@ public static string ExportObjects (string filePath, UnityEngine.Object[] object
return null;
}
- public static string ExportObject (string filePath, UnityEngine.Object root, AnimationExportType exportType = AnimationExportType.all, TransformExportType transformExportType = TransformExportType.Reset)
+ public static string ExportObject (
+ string filePath, UnityEngine.Object root,
+ AnimationExportType exportType = AnimationExportType.all,
+ TransformExportType transformExportType = TransformExportType.Reset,
+ ExportSettings.LODExportType lodExportType = ExportSettings.LODExportType.All)
{
- return ExportObjects(filePath, new Object[] { root }, exportType, transformExportType);
+ return ExportObjects(filePath, new Object[] { root }, exportType, transformExportType, lodExportType);
}
private static void EnsureDirectory (string path)
diff --git a/Assets/FbxExporters/Editor/UnitTests/ExporterTestBase.cs b/Assets/FbxExporters/Editor/UnitTests/ExporterTestBase.cs
index e83ea75ef..40a6521fd 100644
--- a/Assets/FbxExporters/Editor/UnitTests/ExporterTestBase.cs
+++ b/Assets/FbxExporters/Editor/UnitTests/ExporterTestBase.cs
@@ -261,10 +261,12 @@ protected virtual string ExportSelectedObjects(string filename, params Object[]
/// The exported fbx file path.
/// Hierarchy.
/// If set to true export animation only.
- protected string ExportToFbx (GameObject hierarchy, bool animOnly = false){
+ protected string ExportToFbx (GameObject hierarchy, bool animOnly = false, EditorTools.ExportSettings.LODExportType lodExportType = EditorTools.ExportSettings.LODExportType.All){
string filename = GetRandomFbxFilePath ();
var exportedFilePath = FbxExporters.Editor.ModelExporter.ExportObject (
- filename, hierarchy, animOnly? FbxExporters.Editor.ModelExporter.AnimationExportType.componentAnimation : FbxExporters.Editor.ModelExporter.AnimationExportType.all
+ filename, hierarchy,
+ animOnly? FbxExporters.Editor.ModelExporter.AnimationExportType.componentAnimation : FbxExporters.Editor.ModelExporter.AnimationExportType.all,
+ lodExportType: lodExportType
);
Assert.That (exportedFilePath, Is.EqualTo (filename));
return filename;
diff --git a/Assets/FbxExporters/Editor/UnitTests/ModelExporterTest.cs b/Assets/FbxExporters/Editor/UnitTests/ModelExporterTest.cs
index ea55813b0..b4583df7b 100644
--- a/Assets/FbxExporters/Editor/UnitTests/ModelExporterTest.cs
+++ b/Assets/FbxExporters/Editor/UnitTests/ModelExporterTest.cs
@@ -737,5 +737,105 @@ public void TestBlendShapeExport(string fbxPath)
}
}
}
+
+ [Test]
+ public void LODExportTest(){
+ // Create the following test hierarchy:
+ // LODGroup
+ // -- Sphere_LOD0
+ // -- Capsule_LOD0
+ // -- Cube_LOD2
+ // Cylinder_LOD1
+ //
+ // where sphere + capsule renderers are both in LOD0, and cylinder is in LOD1
+ // but not parented under the LOD group
+
+ var lodGroup = new GameObject ("LODGroup");
+ var sphereLOD0 = GameObject.CreatePrimitive (PrimitiveType.Sphere);
+ sphereLOD0.name = "Sphere_LOD0";
+ var capsuleLOD0 = GameObject.CreatePrimitive (PrimitiveType.Capsule);
+ capsuleLOD0.name = "Capsule_LOD0";
+ var cubeLOD2 = GameObject.CreatePrimitive (PrimitiveType.Cube);
+ cubeLOD2.name = "Cube_LOD2";
+ var cylinderLOD1 = GameObject.CreatePrimitive (PrimitiveType.Cylinder);
+ cylinderLOD1.name = "Cylinder_LOD1";
+
+ sphereLOD0.transform.SetParent (lodGroup.transform);
+ capsuleLOD0.transform.SetParent (lodGroup.transform);
+ cubeLOD2.transform.SetParent (lodGroup.transform);
+ cylinderLOD1.transform.SetParent (null);
+
+ // add LOD group
+ var lodGroupComp = lodGroup.AddComponent();
+ Assert.That (lodGroupComp, Is.Not.Null);
+
+ LOD[] lods = new LOD[3];
+ lods [0] = new LOD (1, new Renderer[]{ sphereLOD0.GetComponent(), capsuleLOD0.GetComponent() });
+ lods [1] = new LOD (0.75f, new Renderer[] { cylinderLOD1.GetComponent() });
+ lods [2] = new LOD (0.5f, new Renderer[] { cubeLOD2.GetComponent() });
+ lodGroupComp.SetLODs (lods);
+ lodGroupComp.RecalculateBounds ();
+
+ // test export all
+ // expected LODs exported: Sphere_LOD0, Capsule_LOD0, Cube_LOD2
+ string filename = ExportToFbx(lodGroup, lodExportType:EditorTools.ExportSettings.LODExportType.All);
+ GameObject fbxObj = AssetDatabase.LoadMainAssetAtPath (filename) as GameObject;
+ Assert.IsTrue (fbxObj);
+
+ HashSet expectedChildren = new HashSet () { sphereLOD0.name, capsuleLOD0.name, cubeLOD2.name };
+ CompareGameObjectChildren (fbxObj, expectedChildren);
+
+ // test export highest
+ // expected LODs exported: Sphere_LOD0, Capsule_LOD0
+ filename = ExportToFbx(lodGroup, lodExportType:EditorTools.ExportSettings.LODExportType.Highest);
+ fbxObj = AssetDatabase.LoadMainAssetAtPath (filename) as GameObject;
+ Assert.IsTrue (fbxObj);
+
+ expectedChildren = new HashSet () { sphereLOD0.name, capsuleLOD0.name };
+ CompareGameObjectChildren (fbxObj, expectedChildren);
+
+ // test export lowest
+ // expected LODs exported: Cube_LOD2
+ filename = ExportToFbx(lodGroup, lodExportType:EditorTools.ExportSettings.LODExportType.Lowest);
+ fbxObj = AssetDatabase.LoadMainAssetAtPath (filename) as GameObject;
+ Assert.IsTrue (fbxObj);
+
+ expectedChildren = new HashSet () { cubeLOD2.name };
+ CompareGameObjectChildren (fbxObj, expectedChildren);
+
+ // test convert to prefab
+ // this should have the same result as "export all"
+ // expected LODs exported: Sphere_LOD0, Capsule_LOD0, Cube_LOD2
+ // NOTE: Cylinder_LOD1 is not exported as it is not under the LODGroup hierarchy being exported
+ filename = GetRandomFbxFilePath();
+ var convertedHierarchy = ConvertToModel.Convert(lodGroup, fbxFullPath: filename);
+ Assert.That (convertedHierarchy, Is.Not.Null);
+
+ // check both converted hierarchy and fbx
+ expectedChildren = new HashSet () { sphereLOD0.name, capsuleLOD0.name, cubeLOD2.name };
+ CompareGameObjectChildren (convertedHierarchy, expectedChildren);
+
+ fbxObj = AssetDatabase.LoadMainAssetAtPath (filename) as GameObject;
+ Assert.IsTrue (fbxObj);
+
+ expectedChildren = new HashSet () { sphereLOD0.name, capsuleLOD0.name, cubeLOD2.name };
+ CompareGameObjectChildren (fbxObj, expectedChildren);
+ }
+
+
+ ///
+ /// Compares obj's children to the expected children in the hashset.
+ /// Doesn't recurse through the children.
+ ///
+ /// Object.
+ /// Expected children.
+ private void CompareGameObjectChildren(GameObject obj, HashSet expectedChildren){
+ Assert.That (obj.transform.childCount, Is.EqualTo (expectedChildren.Count));
+
+ foreach (Transform child in obj.transform) {
+ Assert.That (expectedChildren.Contains (child.name));
+ expectedChildren.Remove (child.name);
+ }
+ }
}
}