Skip to content

Commit

Permalink
Merge remote-tracking branch 'refs/remotes/origin/master' into UNI-29…
Browse files Browse the repository at this point in the history
…648-1.1.0b1-forum-release
  • Loading branch information
vkovec committed Nov 9, 2017
2 parents 7d9f676 + 3acb38b commit a33ab2e
Show file tree
Hide file tree
Showing 5 changed files with 261 additions and 33 deletions.
2 changes: 1 addition & 1 deletion Assets/FbxExporters/Editor/ConvertToModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ public static void UpdateFromSourceRecursive(GameObject dest, GameObject source)
/// <returns>Dictionary containing the name to source game object.</returns>
/// <param name="dest">Destination GameObject.</param>
/// <param name="source">Source GameObject.</param>
private static Dictionary<string,GameObject> MapNameToSourceRecursive(GameObject dest, GameObject source){
public static Dictionary<string,GameObject> MapNameToSourceRecursive(GameObject dest, GameObject source){
var nameToGO = new Dictionary<string,GameObject> ();

var q = new Queue<Transform> ();
Expand Down
190 changes: 163 additions & 27 deletions Assets/FbxExporters/Editor/FbxExportSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,9 @@ public override void OnInspectorGUI() {
var options = ExportSettings.GetDCCOptions();
// make sure we never initially have browse selected
if (exportSettings.selectedDCCApp == options.Length - 1) {
exportSettings.selectedDCCApp = 0;
exportSettings.selectedDCCApp = exportSettings.GetPreferredDCCApp();
}

int oldValue = exportSettings.selectedDCCApp;
exportSettings.selectedDCCApp = EditorGUILayout.Popup(exportSettings.selectedDCCApp, options);
if (exportSettings.selectedDCCApp == options.Length - 1) {
Expand Down Expand Up @@ -135,16 +136,10 @@ public override void OnInspectorGUI() {
ExportSettings.DCCType foundDCC = ExportSettings.DCCType.Maya;
var foundDCCPath = TryFindDCC (dccPath, ext, ExportSettings.DCCType.Maya);
if (foundDCCPath == null && Application.platform == RuntimePlatform.WindowsEditor) {
if (ExportSettings.IsEarlierThanMax2017 (dccPath)) {
Debug.LogError ("Earlier than 3ds Max 2017 is not supported");
UnityEditor.EditorUtility.DisplayDialog (
"Error adding 3D Application",
"Unity Integration only supports 3ds Max 2017 or later",
"Ok");
} else {
foundDCCPath = TryFindDCC (dccPath, ext, ExportSettings.DCCType.Max);
foundDCC = ExportSettings.DCCType.Max;
}

foundDCCPath = TryFindDCC (dccPath, ext, ExportSettings.DCCType.Max);
foundDCC = ExportSettings.DCCType.Max;

}
if (foundDCCPath == null) {
Debug.LogError (string.Format ("Could not find supported 3D application at: \"{0}\"", Path.GetDirectoryName (dccPath)));
Expand Down Expand Up @@ -225,6 +220,12 @@ private static string TryFindDCC(string dccPath, string ext, ExportSettings.DCCT
public class ExportSettings : ScriptableSingleton<ExportSettings>
{
public const string kDefaultSavePath = ".";
private static List<string> s_PreferenceList = new List<string>() {kMayaOptionName, kMayaLtOptionName, kMaxOptionName, kBlenderOptionName };
//Any additional names require a space after the name
public const string kMaxOptionName = "3ds Max ";
public const string kMayaOptionName = "Maya ";
public const string kMayaLtOptionName = "MayaLT ";
public const string kBlenderOptionName = "Blender ";

/// <summary>
/// The path where all the different versions of Maya are installed
Expand Down Expand Up @@ -264,7 +265,7 @@ public static string kDefaultAdskRoot {

// List of names in order that they appear in option list
[SerializeField]
private List<string> dccOptionNames;
private List<string> dccOptionNames = new List<string>();
// List of paths in order that they appear in the option list
[SerializeField]
private List<string> dccOptionPaths;
Expand All @@ -283,7 +284,12 @@ protected override void LoadDefaults()
/// </summary>
/// <returns>The unique name.</returns>
/// <param name="name">Name.</param>
private static string GetUniqueName(string name){
public static string GetUniqueDCCOptionName(string name){
Debug.Assert(instance != null);
if (name == null)
{
return null;
}
if (!instance.dccOptionNames.Contains(name)) {
return name;
}
Expand All @@ -305,11 +311,129 @@ private static string GetUniqueName(string name){
do {
uniqueName = string.Format (format, index, name);
index++;
} while (instance.dccOptionNames.Contains(name));
} while (instance.dccOptionNames.Contains(uniqueName));

return uniqueName;
}

public void SetDCCOptionNames(List<string> newList)
{
dccOptionNames = newList;
}

public void ClearDCCOptionNames()
{
dccOptionNames.Clear();
}

/// <summary>
///
/// Find the latest program available and make that the default choice.
/// Will always take any Maya version over any 3ds Max version.
///
/// Returns the index of the most recent program in the list of dccOptionNames
///
/// </summary>
public int GetPreferredDCCApp()
{
if (dccOptionNames == null)
{
return -1;
}

int newestDCCVersionIndex = -1;
int newestDCCVersionNumber = -1;

for (int i = 0; i < dccOptionNames.Count; i++)
{
int versionToCheck = FindDCCVersion(dccOptionNames[i]);
if (versionToCheck == -1)
{
continue;
}
if (versionToCheck > newestDCCVersionNumber)
{
newestDCCVersionIndex = i;
newestDCCVersionNumber = versionToCheck;
}
else if (versionToCheck == newestDCCVersionNumber)
{
int selection = ChoosePreferredDCCApp(newestDCCVersionIndex, i);
if (selection == i)
{
newestDCCVersionIndex = i;
newestDCCVersionNumber = FindDCCVersion(dccOptionNames[i]);
}
}
}
Debug.Assert(newestDCCVersionIndex >= -1 && newestDCCVersionIndex < dccOptionNames.Count);
return newestDCCVersionIndex;
}
/// <summary>
/// Takes the index of two program names from dccOptionNames and chooses our preferred one based on the preference list
/// This happens in case of a tie between two programs with the same release year / version
/// </summary>
/// <param name="optionA"></param>
/// <param name="optionB"></param>
/// <returns></returns>
private int ChoosePreferredDCCApp(int optionA, int optionB)
{
Debug.Assert(optionA >= 0 && optionB >= 0 && optionA < dccOptionNames.Count && optionB < dccOptionNames.Count);
if (dccOptionNames.Count == 0)
{
return -1;
}
var appA = dccOptionNames[optionA];
var appB = dccOptionNames[optionB];
if (appA == null || appB == null || appA.Length <= 0 || appB.Length <= 0)
{
return -1;
}

//We assume that the option names have a
int scoreA = s_PreferenceList.IndexOf(appA.Split(' ')[0]);
int scoreB = s_PreferenceList.IndexOf(appB.Split(' ')[0]);

return scoreA < scoreB ? optionA : optionB;
}

/// <summary>
/// Finds the version based off of the title of the application
/// </summary>
/// <param name="path"></param>
/// <returns> the year/version OR -1 if the year could not be parsed </returns>
private static int FindDCCVersion(string AppName)
{
if (AppName == null)
{
return -1;
}

int version;
string[] piecesArray = AppName.Split(' ');
if (piecesArray.Length == 0)
{
return -1;
}
//Get the number, which is always the last chunk separated by a space.
string number = piecesArray[piecesArray.Length - 1];

if (int.TryParse(number, out version))
{
return version;
}
else
{
float fVersion;
//In case we are looking at a Blender version- the int parse will fail so we'll need to parse it as a float.
if (float.TryParse(number, out fVersion))
{
return (int)fVersion;
}
return -1;
}
}

/// <summary>
/// Find Maya and 3DsMax installations at default install path.
/// Add results to given dictionary.
Expand Down Expand Up @@ -347,19 +471,24 @@ private static void FindDCCInstalls() {
}
string version = product.Substring ("maya".Length);
dccOptionPath.Add (GetMayaExePath (productDir.FullName.Replace ("\\", "/")));
dccOptionName.Add (GetUniqueName ("Maya " + version));
dccOptionName.Add (GetUniqueDCCOptionName(kMayaOptionName + version));
}

if (product.StartsWith ("3ds max", StringComparison.InvariantCultureIgnoreCase)) {
var exePath = string.Format ("{0}/{1}", productDir.FullName.Replace ("\\", "/"), "3dsmax.exe");
if (IsEarlierThanMax2017 (exePath)) {

string version = product.Substring("3ds max ".Length);
var maxOptionName = GetUniqueDCCOptionName(kMaxOptionName + version);

if (IsEarlierThanMax2017 (maxOptionName)) {
continue;
}
string version = product.Substring ("3ds max ".Length);

dccOptionPath.Add (exePath);
dccOptionName.Add (GetUniqueName ("3ds Max " + version));
dccOptionName.Add (maxOptionName);
}
}
instance.selectedDCCApp = instance.GetPreferredDCCApp();
}

/// <summary>
Expand Down Expand Up @@ -406,7 +535,7 @@ public static GUIContent[] GetDCCOptions(){
var dccPath = instance.dccOptionPaths [i];
if (!File.Exists (dccPath)) {
if (i == instance.selectedDCCApp) {
instance.selectedDCCApp = 0;
instance.selectedDCCApp = instance.GetPreferredDCCApp();
}
namesToDelete.Add (instance.dccOptionNames [i]);
pathsToDelete.Add (dccPath);
Expand Down Expand Up @@ -463,11 +592,20 @@ public static void AddDCCOption(string newOption, DCCType dcc){
Debug.LogError (string.Format("Unity Integration does not support Maya LT: \"{0}\"", newOption));
return;
}
optionName = GetUniqueName ("Maya " + version);
optionName = GetUniqueDCCOptionName("Maya " + version);
break;
case DCCType.Max:
optionName = GetMaxOptionName (newOption);
break;
if (ExportSettings.IsEarlierThanMax2017(optionName))
{
Debug.LogError("Earlier than 3ds Max 2017 is not supported");
UnityEditor.EditorUtility.DisplayDialog(
"Error adding 3D Application",
"Unity Integration only supports 3ds Max 2017 or later",
"Ok");
return;
}
break;
default:
throw new System.NotImplementedException();
}
Expand Down Expand Up @@ -506,14 +644,12 @@ static string AskMayaVersion(string exePath) {
/// <returns>The 3DsMax dropdown option label.</returns>
/// <param name="exePath">Exe path.</param>
public static string GetMaxOptionName(string exePath){
return GetUniqueName (Path.GetFileName(Path.GetDirectoryName (exePath)));
return GetUniqueDCCOptionName(Path.GetFileName(Path.GetDirectoryName (exePath)));
}

public static bool IsEarlierThanMax2017(string exePath){
var name = Path.GetFileName (Path.GetDirectoryName (exePath)).ToLower();
name = name.Replace ("3ds max", "").Trim();
int version;
return int.TryParse (name, out version) && version < 2017;
public static bool IsEarlierThanMax2017(string AppName){
int version = FindDCCVersion(AppName);
return version != -1 && version < 2017;
}

public static string GetSelectedDCCPath()
Expand Down
8 changes: 3 additions & 5 deletions Assets/FbxExporters/Editor/FbxExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -585,8 +585,7 @@ void ExportMesh (MeshInfo meshInfo, FbxNode fbxNode)
}
}

int[] unmergedPolygons = new int[meshInfo.Triangles.Length];
int current = 0;
var unmergedPolygons = new List<int> ();
var mesh = meshInfo.mesh;
for (int s = 0; s < mesh.subMeshCount; s++) {
var topology = mesh.GetTopology (s);
Expand Down Expand Up @@ -624,12 +623,11 @@ void ExportMesh (MeshInfo meshInfo, FbxNode fbxNode)

// Save the polygon order (without merging vertices) so we
// properly export UVs, normals, binormals, etc.
unmergedPolygons [current] = polyVert;
unmergedPolygons.Add(polyVert);

polyVert = ControlPointToIndex [meshInfo.Vertices [polyVert]];
fbxMesh.AddPolygon (polyVert);

current++;
}
fbxMesh.EndPolygon ();
}
Expand All @@ -643,7 +641,7 @@ void ExportMesh (MeshInfo meshInfo, FbxNode fbxNode)
AssignLayerElementMaterial (fbxMesh, meshInfo.mesh, meshInfo.Materials.Length);

// Set up normals, etc.
ExportComponentAttributes (meshInfo, fbxMesh, unmergedPolygons);
ExportComponentAttributes (meshInfo, fbxMesh, unmergedPolygons.ToArray());

// set the fbxNode containing the mesh
fbxNode.SetNodeAttribute (fbxMesh);
Expand Down
51 changes: 51 additions & 0 deletions Assets/FbxExporters/Editor/UnitTests/ConvertToModelTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,5 +182,56 @@ public void SkinnedMeshTest()
// In the future we'll want to assert the opposite!
Assert.That(cubeInstance.GetComponentsInChildren<SkinnedMeshRenderer>(), Is.Empty);
}

[Test]
public void MapNameToSourceTest()
{
//Create a cube with 3 children game objects
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
var capsule = GameObject.CreatePrimitive(PrimitiveType.Capsule);
var sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
var quad = GameObject.CreatePrimitive(PrimitiveType.Quad);

capsule.transform.parent = cube.transform;
sphere.transform.parent = cube.transform;
quad.transform.parent = cube.transform;
capsule.transform.SetSiblingIndex(0);

//Create a similar Heirarchy that we can use as our phony "exported" hierarchy.
var cube2 = GameObject.CreatePrimitive(PrimitiveType.Cube);
var capsule2 = GameObject.CreatePrimitive(PrimitiveType.Capsule);
var sphere2 = GameObject.CreatePrimitive(PrimitiveType.Sphere);
var quad2 = GameObject.CreatePrimitive(PrimitiveType.Quad);

capsule2.transform.parent = cube2.transform;
sphere2.transform.parent = cube2.transform;
quad2.transform.parent = cube2.transform;
capsule.transform.SetSiblingIndex(1);

var dictionary = ConvertToModel.MapNameToSourceRecursive(cube, cube2);

//We expect these to pass because we've given it an identical game object, as it would have after a normal export.
Assert.AreSame(capsule2, dictionary[capsule.name]);
Assert.AreSame(sphere2, dictionary[sphere.name]);
Assert.AreSame(quad2, dictionary[quad.name]);
Assert.True(dictionary.Count == 4);

//Create a broken hierarchy, one that is missing a primitive
var cube3 = GameObject.CreatePrimitive(PrimitiveType.Cube);
var capsule3 = GameObject.CreatePrimitive(PrimitiveType.Capsule);
var sphere3 = GameObject.CreatePrimitive(PrimitiveType.Sphere);

capsule3.transform.parent = cube3.transform;
sphere3.transform.parent = cube3.transform;

var dictionaryBroken = ConvertToModel.MapNameToSourceRecursive(cube, cube3);

//the dictionary size should be equal to the amount of children + the parent
Assert.True(dictionaryBroken.Count == 4);

Assert.IsNull(dictionaryBroken[quad.name]);
Assert.AreSame(capsule3, dictionaryBroken[capsule.name]);
Assert.AreSame(sphere3, dictionaryBroken[sphere.name]);
}
}
}
Loading

0 comments on commit a33ab2e

Please sign in to comment.