Skip to content

Commit 184be9a

Browse files
committed
Merge remote-tracking branch 'refs/remotes/origin/master' into UNI-25505-single-root-package
2 parents 8587529 + 8813032 commit 184be9a

File tree

9 files changed

+414
-261
lines changed

9 files changed

+414
-261
lines changed

Assets/FbxExporters/Editor/ConvertToModel.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,12 @@ public static GameObject Convert (
173173
SetupImportedGameObject (toConvert, unityGO);
174174

175175
// Set up the FbxPrefab component so it will auto-update.
176-
var fbxPrefab = unityGO.AddComponent<FbxPrefab>();
176+
// Make sure to delete whatever FbxPrefab history we had.
177+
var fbxPrefab = unityGO.GetComponent<FbxPrefab>();
178+
if (fbxPrefab) {
179+
Object.DestroyImmediate(fbxPrefab);
180+
}
181+
fbxPrefab = unityGO.AddComponent<FbxPrefab>();
177182
fbxPrefab.SetSourceModel(unityMainAsset);
178183

179184
// Disconnect from the FBX file.

Assets/FbxExporters/Editor/FbxExporter.cs

Lines changed: 210 additions & 191 deletions
Large diffs are not rendered by default.

Assets/FbxExporters/Editor/UnitTests/ConvertToModelTest.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,11 @@ public void BasicTest()
165165
var assetFullPath = Path.GetFullPath(Path.Combine(Application.dataPath,
166166
"../" + assetRelativePath));
167167
Assert.AreEqual(Path.GetFullPath(path), Path.GetDirectoryName(assetFullPath));
168+
169+
// Convert it again, make sure there's only one FbxPrefab (see UNI-25528).
170+
var cubePrefabInstance2 = ConvertToModel.Convert(cubePrefabInstance,
171+
directoryFullPath: path, keepOriginal: false);
172+
Assert.That(cubePrefabInstance2.GetComponents<FbxPrefab>().Length, Is.EqualTo(1));
168173
}
169174
}
170175
}

Assets/FbxExporters/Editor/UnitTests/ModelExporterTest.cs

Lines changed: 88 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,93 @@
1010
using UnityEngine.TestTools;
1111
using NUnit.Framework;
1212
using System.Collections.Generic;
13+
using Unity.FbxSdk;
14+
using FbxExporters.Editor;
1315

1416
namespace FbxExporters.UnitTests
1517
{
1618
public class ModelExporterTest : ExporterTestBase
1719
{
20+
[Test]
21+
public void TestBasics ()
22+
{
23+
Assert.That(!string.IsNullOrEmpty(ModelExporter.GetVersionFromReadme()));
24+
25+
// Test GetOrCreateLayer
26+
using (var fbxManager = FbxManager.Create()) {
27+
var fbxMesh = FbxMesh.Create(fbxManager, "name");
28+
var layer0 = ModelExporter.GetOrCreateLayer(fbxMesh);
29+
Assert.That(layer0, Is.Not.Null);
30+
Assert.That(ModelExporter.GetOrCreateLayer(fbxMesh), Is.EqualTo(layer0));
31+
var layer5 = ModelExporter.GetOrCreateLayer(fbxMesh, layer: 5);
32+
Assert.That(layer5, Is.Not.Null);
33+
Assert.That(layer5, Is.Not.EqualTo(layer0));
34+
}
35+
36+
// Test axis conversion: a x b in left-handed is the same as b x a
37+
// in right-handed (that's why we need to flip the winding order).
38+
var a = new Vector3(1,0,0);
39+
var b = new Vector3(0,0,1);
40+
var crossLeft = Vector3.Cross(a,b);
41+
42+
var afbx = ModelExporter.ConvertNormalToRightHanded(a);
43+
var bfbx = ModelExporter.ConvertNormalToRightHanded(b);
44+
Assert.AreEqual(ModelExporter.ConvertNormalToRightHanded(crossLeft), bfbx.CrossProduct(afbx));
45+
46+
// Test scale conversion. Nothing complicated here...
47+
var afbxPosition = ModelExporter.ConvertPositionToRightHanded(a);
48+
Assert.AreEqual(100, afbxPosition.Length());
49+
50+
// Test rotation conversion.
51+
var q = Quaternion.Euler(new Vector3(0, 90, 0));
52+
var fbxAngles = ModelExporter.ConvertQuaternionToXYZEuler(q);
53+
Assert.AreEqual(fbxAngles.X, 0);
54+
Assert.That(fbxAngles.Y, Is.InRange(-90.001, -89.999));
55+
Assert.AreEqual(fbxAngles.Z, 0);
56+
57+
Assert.That(ModelExporter.DefaultMaterial);
58+
59+
// Test non-static functions.
60+
using (var fbxManager = FbxManager.Create()) {
61+
var fbxScene = FbxScene.Create(fbxManager, "scene");
62+
var exporter = new ModelExporter();
63+
64+
// Test ExportMaterial: it exports and it re-exports
65+
var fbxMaterial = exporter.ExportMaterial(ModelExporter.DefaultMaterial, fbxScene)
66+
as FbxSurfaceLambert;
67+
Assert.That(fbxMaterial, Is.Not.Null);
68+
var fbxMaterial2 = exporter.ExportMaterial(ModelExporter.DefaultMaterial, fbxScene);
69+
Assert.AreEqual(fbxMaterial, fbxMaterial2);
70+
71+
// Test ExportTexture: it finds the same texture for the default-material (it doesn't create a new one)
72+
var fbxMaterialNew = FbxSurfaceLambert.Create(fbxScene, "lambert");
73+
exporter.ExportTexture(ModelExporter.DefaultMaterial, "_MainTex",
74+
fbxMaterialNew, FbxSurfaceLambert.sBump);
75+
Assert.AreEqual(
76+
fbxMaterial.FindProperty(FbxSurfaceLambert.sDiffuse).GetSrcObject(),
77+
fbxMaterialNew.FindProperty(FbxSurfaceLambert.sBump).GetSrcObject()
78+
);
79+
80+
// Test ExportMesh: make sure we exported a mesh with welded vertices.
81+
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
82+
var cubeNode = FbxNode.Create(fbxScene, "cube");
83+
exporter.ExportMesh(cube.GetComponent<MeshFilter>().sharedMesh, cubeNode);
84+
Assert.That(cubeNode.GetMesh(), Is.Not.Null);
85+
Assert.That(cubeNode.GetMesh().GetControlPointsCount(), Is.EqualTo(8));
86+
}
87+
88+
// Test exporting a skinned-mesh. Make sure it doesn't leak (it did at one point)
89+
{
90+
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
91+
var character = new GameObject();
92+
var smr = character.AddComponent<SkinnedMeshRenderer>();
93+
smr.sharedMesh = cube.GetComponent<MeshFilter>().sharedMesh;
94+
var meshCount = Object.FindObjectsOfType<Mesh>().Length;
95+
ModelExporter.ExportObject(GetRandomFbxFilePath(), character);
96+
Assert.AreEqual(meshCount, Object.FindObjectsOfType<Mesh>().Length);
97+
}
98+
}
99+
18100
[Test]
19101
public void TestFindCenter ()
20102
{
@@ -115,15 +197,13 @@ public CallbackTester(Transform t, string f) {
115197
tree = t;
116198
}
117199

118-
public bool CallbackForFbxPrefab(FbxPrefab component, out Mesh mesh) {
200+
public bool CallbackForFbxPrefab(ModelExporter exporter, FbxPrefab component, FbxNode fbxNode) {
119201
componentCalls++;
120-
mesh = null;
121202
return true;
122203
}
123204

124-
public bool CallbackForObject(GameObject go, out Mesh mesh) {
205+
public bool CallbackForObject(ModelExporter exporter, GameObject go, FbxNode fbxNode) {
125206
objectCalls++;
126-
mesh = null;
127207
return objectResult;
128208
}
129209

@@ -205,8 +285,8 @@ public void TestExporterCallbacks()
205285
Mesh assetMesh;
206286

207287
FbxExporters.Editor.ModelExporter.GetMeshForComponent<FbxPrefab> prefabCallback =
208-
(FbxPrefab component, out Mesh mesh) => {
209-
mesh = sphereMesh;
288+
(ModelExporter exporter, FbxPrefab component, FbxNode node) => {
289+
exporter.ExportMesh(sphereMesh, node);
210290
return true;
211291
};
212292
FbxExporters.Editor.ModelExporter.RegisterMeshCallback(prefabCallback);
@@ -225,12 +305,11 @@ public void TestExporterCallbacks()
225305
// actually unregister).
226306
filename = GetRandomFbxFilePath();
227307
FbxExporters.Editor.ModelExporter.GetMeshForObject callback =
228-
(GameObject gameObject, out Mesh mesh) => {
308+
(ModelExporter exporter, GameObject gameObject, FbxNode node) => {
229309
if (gameObject.name == "Parent2") {
230-
mesh = sphereMesh;
310+
exporter.ExportMesh(sphereMesh, node);
231311
return true;
232312
} else {
233-
mesh = null;
234313
return false;
235314
}
236315
};

Assets/FbxExporters/FbxPrefab.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -907,21 +907,18 @@ void CompareAndUpdate()
907907
// First write down what we want to do.
908908
var updates = new UpdateList(GetFbxHistory(), m_fbxModel.transform, this);
909909

910-
// If we don't need to do anything, jump out now.
911-
if (!updates.NeedsUpdates()) {
912-
Log("{0}: no updates needed", transform.name);
913-
return;
914-
}
915-
916-
// We want to do something, so instantiate the prefab, work on the instance, then copy back.
910+
// Instantiate the prefab, work on the instance, then copy back.
911+
// We could optimize this out if we had nothing to do, but then the
912+
// OnUpdate handler wouldn't always get called, and that makes for
913+
// confusing API.
917914
var prefabInstance = UnityEditor.PrefabUtility.InstantiatePrefab(this.gameObject) as GameObject;
918915
if (!prefabInstance) {
919916
throw new System.Exception(string.Format("Failed to instantiate {0}; is it really a prefab?",
920917
this.gameObject));
921918
}
922919
var fbxPrefabInstance = prefabInstance.GetComponent<FbxPrefab>();
923920

924-
// Do ALL the things!
921+
// Do ALL the things (potentially nothing).
925922
var updatedObjects = updates.ImplementUpdates(fbxPrefabInstance);
926923

927924
// Tell listeners about it. They're free to make adjustments now.

Assets/FbxExporters/Integrations/Autodesk/maya/scripts/unityOneClick/commands.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class BaseCommand(OpenMayaMPx.MPxCommand, LoggerMixin):
3939
Base class for UnityOneClick Plugin Commands.
4040
"""
4141
kDefaultIcon = 'unity_100.png'
42+
kFamilyLabel = "The UnityOneClick plugin allows you to reliably exchange and review your work between Maya and Unity."
4243

4344
def __init__(self):
4445
OpenMayaMPx.MPxCommand.__init__(self)
@@ -279,6 +280,7 @@ def doIt(self, args):
279280

280281
# select the export set for export, if it exists,
281282
# otherwise take what is currently selected
283+
origSelection = maya.cmds.ls(sl=True)
282284
if self.setExists(self._exportSet):
283285
maya.cmds.select(self._exportSet, r=True, ne=True)
284286

@@ -310,6 +312,10 @@ def doIt(self, args):
310312
self.displayDebug('doIt({0})'.format(melCommand))
311313

312314
maya.mel.eval(melCommand)
315+
316+
if origSelection:
317+
maya.cmds.select(cl=True)
318+
maya.cmds.select(origSelection, add=True, ne=True)
313319

314320
@classmethod
315321
def invoke(cls):
@@ -359,6 +365,7 @@ def doIt(self, args):
359365

360366
# select the export set for export, if it exists,
361367
# otherwise take what is currently selected
368+
origSelection = maya.cmds.ls(sl=True)
362369
if self.setExists(self._exportSet):
363370
maya.cmds.select(self._exportSet, r=True, ne=True)
364371

@@ -372,6 +379,10 @@ def doIt(self, args):
372379
self.displayDebug('doIt {0}'.format(strCmd))
373380
maya.mel.eval(strCmd)
374381

382+
if origSelection:
383+
maya.cmds.select(cl=True)
384+
maya.cmds.select(origSelection, add=True, ne=True)
385+
375386
@classmethod
376387
def invoke(cls):
377388
"""

Assets/FbxExporters/Integrations/Autodesk/maya/scripts/unityOneClick/ui.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
# User Interface
3030
# ======================================================================'
3131

32-
kMayaVersionAdded = '2017'
3332
kMenuName = 'UnityOneClick'
3433
kMenuDivider = 'UnityOneClickDivider'
3534
kMenuLabel = 'UNITY'
@@ -54,10 +53,19 @@ def unregister(pluginFn):
5453
return
5554

5655
def getParentMenu():
56+
"""
57+
Return the name of the parent menu for the Unity menu
58+
"""
5759
result = maya.mel.eval('$tempVar = $gMainFileMenu;')
5860
maya.mel.eval("buildFileMenu")
5961
return result
6062

63+
def whatsNewVersion():
64+
"""
65+
Return the name of Maya version to be considered 'new' e.g. "2018"
66+
"""
67+
return maya.cmds.about(q=True, version=True)
68+
6169
def installMenu():
6270
"""
6371
install menu into main window
@@ -70,34 +78,35 @@ def installMenu():
7078
longDivider=False,
7179
insertAfter=kMenuInsertAfter,
7280
parent=parentMenu,
73-
version=kMayaVersionAdded)
81+
version=whatsNewVersion())
7482
maya.cmds.menuItem(kMenuName,
7583
parent=parentMenu,
7684
insertAfter=kMenuDivider,
7785
image=commands.importCmd.familyIconPath(),
7886
subMenu=True,
7987
label=kMenuLabel,
88+
annotation=commands.importCmd.kFamilyLabel,
8089
tearOff=True,
81-
version=kMayaVersionAdded)
90+
version=whatsNewVersion())
8291

8392
maya.cmds.menuItem(parent=kMenuName,
8493
label=commands.importCmd.kShortLabel,
8594
annotation=commands.importCmd.kLabel,
8695
command=commands.importCmd.kScriptCommand,
8796
image=commands.importCmd.iconPath(),
88-
version=kMayaVersionAdded)
97+
version=whatsNewVersion())
8998
maya.cmds.menuItem(parent=kMenuName,
9099
label=commands.reviewCmd.kShortLabel,
91100
annotation=commands.reviewCmd.kLabel,
92101
command=commands.reviewCmd.kScriptCommand,
93102
image=commands.importCmd.iconPath(),
94-
version=kMayaVersionAdded)
103+
version=whatsNewVersion())
95104
maya.cmds.menuItem(parent=kMenuName,
96105
label=commands.publishCmd.kShortLabel,
97106
annotation=commands.publishCmd.kLabel,
98107
command=commands.publishCmd.kScriptCommand,
99108
image=commands.importCmd.iconPath(),
100-
version=kMayaVersionAdded)
109+
version=whatsNewVersion())
101110

102111
def uninstallMenu():
103112
"""

Assets/FbxExporters/README.txt

Lines changed: 7 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,53 +14,14 @@ Requirements
1414
Installing Maya Integration
1515
--------------------------------------------
1616

17-
The easy way to install the Maya integration is with the
18-
FbxExporters -> Install Maya Integration
19-
menu option in Unity.
17+
The easiest way to install the Maya integration is from the menu option in Unity.
2018

21-
It uses the most recent version of Maya it can find. Set your MAYA_LOCATION
22-
environment before running Unity if you want to specify a particular version of Maya.
19+
FbxExporters -> Install Maya Integration
2320

21+
This menu item locates and uses the most recent version of Maya installed. If you want
22+
to specify a custom version or location then set your MAYA_LOCATION environment
23+
before running Unity.
2424

2525
Alternately, you can install the package and integrations from the command-line
26-
using the following script:
27-
28-
29-
MacOS:
30-
31-
# Configure where Unity is installed
32-
if [ ! -d "${UNITY3D_PATH}" ]; then
33-
UNITY3D_PATH="/Applications/Unity/Unity.app"
34-
fi
35-
36-
# Configure which Unity project to install package
37-
if [ ! -d "${PROJECT_PATH}" ]; then
38-
PROJECT_PATH=~/Development/FbxExporters
39-
fi
40-
41-
# Configure where unitypackage is located
42-
if [ ! -f "${PACKAGE_PATH}" ]; then
43-
PACKAGE_PATH=`ls -t ${PROJECT_PATH}/FbxExporters_*.unitypackage | head -1`
44-
fi
45-
46-
# Configuring Maya2017 to auto-load integration
47-
if [ ! -d "${MAYA_LOCATION}" ] ; then
48-
MAYA_LOCATION=/Applications/Autodesk/maya2017/Maya.app
49-
fi
50-
export MAYA_LOCATION
51-
52-
if [ ! -d "${UNITY3D_PATH}" ]; then
53-
echo "Unity is not installed"
54-
elif [ ! -d "${MAYA_LOCATION}" ] ; then
55-
echo "Maya is not installed"
56-
else
57-
# Install FbxExporters package
58-
"${UNITY3D_PATH}/Contents/MacOS/Unity" -projectPath "${PROJECT_PATH}" -importPackage ${PACKAGE_PATH} -quit
59-
60-
# Install Maya Integration. Requires MAYA_LOCATION.
61-
"${UNITY3D_PATH}/Contents/MacOS/Unity" -batchMode -projectPath "${PROJECT_PATH}" -executeMethod FbxExporters.Integrations.InstallMaya -quit
62-
63-
# To configure without user interface change the last argument to 1 instead of 0
64-
"${MAYA_LOCATION}/Contents/MacOS/Maya" -command "configureUnityOneClick \"${PROJECT_PATH}\" \"${UNITY3D_PATH}\" 0; scriptJob -idleEvent quit;"
65-
fi
66-
26+
using a script, an example of which can be found in the scripts folder of the
27+
Maya integration. The version for OSX is called install_maya_plugin.sh.

0 commit comments

Comments
 (0)