Skip to content

Commit

Permalink
Merge pull request #313 from Unity-Technologies/UNI-39477-select-LOD-…
Browse files Browse the repository at this point in the history
…to-export

Uni 39477 select lod to export
  • Loading branch information
vkovec authored Feb 23, 2018
2 parents b9355a0 + 6f717f4 commit ab5c025
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Assets/FbxExporters/Editor/ConvertToModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
14 changes: 14 additions & 0 deletions Assets/FbxExporters/Editor/FbxExportSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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:",
Expand Down Expand Up @@ -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
}

/// <summary>
/// The path where Convert To Model will save the new fbx and prefab.
///
Expand Down
70 changes: 61 additions & 9 deletions Assets/FbxExporters/Editor/FbxExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Linq;
using UnityEngine.Playables;
using UnityEngine.Timeline;
using FbxExporters.EditorTools;

namespace FbxExporters
{
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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<LODGroup>();
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;
Expand Down Expand Up @@ -2665,7 +2704,11 @@ public enum TransformExportType { Local, Global, Reset };
///
/// This refreshes the asset database.
/// </summary>
public int ExportAll (IEnumerable<UnityEngine.Object> unityExportSet, Dictionary<GameObject, AnimationOnlyExportData> animationExportData, TransformExportType exportType = TransformExportType.Global)
public int ExportAll (
IEnumerable<UnityEngine.Object> unityExportSet,
Dictionary<GameObject, AnimationOnlyExportData> animationExportData,
TransformExportType exportType = TransformExportType.Global,
ExportSettings.LODExportType lodExportType = ExportSettings.LODExportType.All)
{
exportCancelled = false;

Expand Down Expand Up @@ -2780,7 +2823,7 @@ public int ExportAll (IEnumerable<UnityEngine.Object> 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");
Expand Down Expand Up @@ -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 ();
Expand All @@ -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.
/// <summary>
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;

Expand Down Expand Up @@ -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);

Expand All @@ -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)
Expand Down
6 changes: 4 additions & 2 deletions Assets/FbxExporters/Editor/UnitTests/ExporterTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,12 @@ protected virtual string ExportSelectedObjects(string filename, params Object[]
/// <returns>The exported fbx file path.</returns>
/// <param name="hierarchy">Hierarchy.</param>
/// <param name="animOnly">If set to <c>true</c> export animation only.</param>
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;
Expand Down
100 changes: 100 additions & 0 deletions Assets/FbxExporters/Editor/UnitTests/ModelExporterTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<LODGroup>();
Assert.That (lodGroupComp, Is.Not.Null);

LOD[] lods = new LOD[3];
lods [0] = new LOD (1, new Renderer[]{ sphereLOD0.GetComponent<Renderer>(), capsuleLOD0.GetComponent<Renderer>() });
lods [1] = new LOD (0.75f, new Renderer[] { cylinderLOD1.GetComponent<Renderer>() });
lods [2] = new LOD (0.5f, new Renderer[] { cubeLOD2.GetComponent<Renderer>() });
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<string> expectedChildren = new HashSet<string> () { 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<string> () { 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<string> () { 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<string> () { sphereLOD0.name, capsuleLOD0.name, cubeLOD2.name };
CompareGameObjectChildren (convertedHierarchy, expectedChildren);

fbxObj = AssetDatabase.LoadMainAssetAtPath (filename) as GameObject;
Assert.IsTrue (fbxObj);

expectedChildren = new HashSet<string> () { sphereLOD0.name, capsuleLOD0.name, cubeLOD2.name };
CompareGameObjectChildren (fbxObj, expectedChildren);
}


/// <summary>
/// Compares obj's children to the expected children in the hashset.
/// Doesn't recurse through the children.
/// </summary>
/// <param name="obj">Object.</param>
/// <param name="expectedChildren">Expected children.</param>
private void CompareGameObjectChildren(GameObject obj, HashSet<string> 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);
}
}
}
}

0 comments on commit ab5c025

Please sign in to comment.