/// Main entry point public static bool Export(string outputFile, string format, string fbxVersion = null) { using (var G = new FbxExportGlobals(outputFile)) { int fmt = G.m_manager.GetIOPluginRegistry().FindWriterIDByDescription(format); if (!G.m_exporter.Initialize(outputFile, fmt, G.m_ioSettings)) { OutputWindowScript.Error("FBX export failed", "Could not initialize exporter"); return(false); } if (!String.IsNullOrEmpty(fbxVersion)) { G.m_exporter.SetFileExportVersion(new FbxString(fbxVersion)); } G.m_scene = FbxScene.Create(G.m_manager, "scene"); if (G.m_scene == null) { OutputWindowScript.Error("FBX export failed", "Could not initialize scene"); return(false); } String version = string.Format("{0}.{1}", App.Config.m_VersionNumber, App.Config.m_BuildStamp); FbxDocumentInfo info = FbxDocumentInfo.Create(G.m_manager, "DocInfo"); info.Original_ApplicationVendor.Set(new FbxString(App.kDisplayVendorName)); info.Original_ApplicationName.Set(new FbxString(App.kAppDisplayName)); info.Original_ApplicationVersion.Set(new FbxString(version)); info.LastSaved_ApplicationVendor.Set(new FbxString(App.kDisplayVendorName)); info.LastSaved_ApplicationName.Set(new FbxString(App.kAppDisplayName)); info.LastSaved_ApplicationVersion.Set(new FbxString(version)); // The toolkit's FBX parser is too simple to be able to read anything but // the UserData/Properties70 node, so add the extra info as a custom property var stringType = info.Original_ApplicationVersion.GetPropertyDataType(); var prop = FbxProperty.Create(info.Original, stringType, "RequiredToolkitVersion"); prop.SetString(FbxUtils.kRequiredToolkitVersion); G.m_scene.SetDocumentInfo(info); G.m_scene.GetGlobalSettings().SetSystemUnit(FbxSystemUnit.m); try { WriteObjectsAndConnections2(G); G.m_exporter.Export(G.m_scene); } catch (InvalidOperationException e) { OutputWindowScript.Error("FBX export failed", e.Message); return(false); } catch (IOException e) { OutputWindowScript.Error("FBX export failed", e.Message); return(false); } return(true); } }
protected FbxProperty ExportFloatProperty(FbxObject fbxObject, float value, string name) { var fbxProperty = FbxProperty.Create(fbxObject, Globals.FbxDoubleDT, name); Assert.IsTrue(fbxProperty.IsValid()); fbxProperty.Set(value); // Must be marked user-defined or it won't be shown in most DCCs fbxProperty.ModifyFlag(FbxPropertyFlags.EFlags.eUserDefined, true); fbxProperty.ModifyFlag(FbxPropertyFlags.EFlags.eAnimatable, true); return(fbxProperty); }
private void AddCustomProperties(FbxNode fbxNode, string propName, int propValue) { var fbxProperty = FbxProperty.Create(fbxNode, Globals.FbxIntDT, propName); Assert.IsTrue(fbxProperty.IsValid()); fbxProperty.Set(propValue); // Must be marked user-defined or it won't be shown in most DCCs fbxProperty.ModifyFlag(FbxPropertyFlags.EFlags.eUserDefined, true); fbxProperty.ModifyFlag(FbxPropertyFlags.EFlags.eAnimatable, true); for (int i = 0; i < fbxNode.GetChildCount(); i++) { AddCustomProperties(fbxNode.GetChild(i), propName, propValue + 1); } }
/// <summary> /// Export Component's int property /// </summary> FbxProperty ExportIntProperty(FbxObject fbxObject, int value, string name, string label) { // create a custom property for component value var fbxProperty = FbxProperty.Create(fbxObject, Globals.FbxIntDT, name, label); if (!fbxProperty.IsValid()) { throw new System.NullReferenceException(); } fbxProperty.Set(value); // Must be marked user-defined or it won't be shown in most DCCs fbxProperty.ModifyFlag(FbxPropertyFlags.EFlags.eUserDefined, true); fbxProperty.ModifyFlag(FbxPropertyFlags.EFlags.eAnimatable, true); return(fbxProperty); }
/// <summary> /// Export Unity Property as a Float Property /// </summary> FbxProperty ExportFloatProperty(FbxObject fbxObject, float value, string name, string label) { // add (not particularly useful) custom data: how many Unity // components does the unity object have? var fbxProperty = FbxProperty.Create(fbxObject, Globals.FbxDoubleDT, name, label); if (!fbxProperty.IsValid()) { throw new System.NullReferenceException(); } fbxProperty.Set(value); // Must be marked user-defined or it won't be shown in most DCCs fbxProperty.ModifyFlag(FbxPropertyFlags.EFlags.eUserDefined, true); fbxProperty.ModifyFlag(FbxPropertyFlags.EFlags.eAnimatable, true); return(fbxProperty); }
/// <summary> /// Export GameObject's Transform component /// </summary> FbxProperty ExportCustomData(Transform unityTransform, FbxNode fbxNode) { // add (not particularly useful) custom data: how many Unity // components does the unity object have? var fbxProperty = FbxProperty.Create(fbxNode, Globals.FbxIntDT, "unity_component_count", "Number of Unity Components"); if (!fbxProperty.IsValid()) { throw new System.NullReferenceException(); } var numComponents = unityTransform.GetComponents <UnityEngine.Component>().Length; fbxProperty.Set(numComponents); // Must be marked user-defined or it won't be shown in most DCCs fbxProperty.ModifyFlag(FbxPropertyFlags.EFlags.eUserDefined, true); fbxProperty.ModifyFlag(FbxPropertyFlags.EFlags.eAnimatable, true); return(fbxProperty); }
public void TestVarious() { FbxObject obj; /************************************************************ * Test selection ************************************************************/ obj = CreateObject(); Assert.IsFalse(obj.GetSelected()); obj.SetSelected(true); Assert.IsTrue(obj.GetSelected()); /************************************************************ * Test name-related functions. ************************************************************/ /* * We use this also for testing that string handling works. * Make sure we can pass const char*, FbxString, and const * FbxString&. * Make sure we can return those too (though I'm not actually * seeing a return of a const-ref anywhere). */ // Test a function that takes const char*. obj = FbxObject.Create(Manager, "MyObject"); Assert.IsNotNull(obj); // Test a function that returns const char*. Assert.AreEqual("MyObject", obj.GetName()); // Test a function that takes an FbxString with an accent in it. obj.SetNameSpace("Accentué"); // Test a function that returns FbxString. Assert.AreEqual("MyObject", obj.GetNameWithoutNameSpacePrefix()); // Test a function that returns FbxString with an accent in it. Assert.AreEqual("Accentué", obj.GetNameSpaceOnly()); // Test a function that takes a const char* and returns an FbxString. // We don't want to convert the other StripPrefix functions, which // modify their argument in-place. Assert.AreEqual("MyObject", FbxObject.StripPrefix("NameSpace::MyObject")); obj.SetName("new name"); Assert.AreEqual("new name", obj.GetName()); obj.SetInitialName("init"); Assert.AreEqual("init", obj.GetInitialName()); /************************************************************ * Test shader implementations ************************************************************/ using (obj = FbxObject.Create(Manager, "MyObject")) { var impl = FbxImplementation.Create(obj, "impl"); Assert.IsTrue(obj.AddImplementation(impl)); Assert.IsTrue(obj.RemoveImplementation(impl)); Assert.IsTrue(obj.AddImplementation(impl)); Assert.IsTrue(obj.SetDefaultImplementation(impl)); Assert.AreEqual(impl, obj.GetDefaultImplementation()); Assert.IsTrue(obj.HasDefaultImplementation()); } /************************************************************ * Test property functions ************************************************************/ using (obj = CreateObject("theobj")) { using (var obj2 = CreateObject("otherobj")) { // Make a property and connect it from obj to obj2. var prop = FbxProperty.Create(obj, Globals.FbxBoolDT, "maybe"); var prop2 = FbxProperty.Create(obj, Globals.FbxFloatDT, "probability"); Assert.IsTrue(obj.ConnectSrcProperty(prop)); Assert.IsTrue(obj.ConnectSrcProperty(prop2)); Assert.IsTrue(obj2.ConnectDstProperty(prop)); Assert.IsTrue(obj.IsConnectedSrcProperty(prop)); Assert.IsTrue(obj2.IsConnectedDstProperty(prop)); Assert.AreEqual(2, obj.GetSrcPropertyCount()); Assert.AreEqual(1, obj2.GetDstPropertyCount()); Assert.AreEqual(prop, obj.GetSrcProperty()); Assert.AreEqual(prop, obj.GetSrcProperty(0)); Assert.AreEqual(prop2, obj.GetSrcProperty(1)); Assert.AreEqual(prop, obj2.GetDstProperty()); Assert.AreEqual(prop, obj2.GetDstProperty(0)); Assert.AreEqual(prop, obj.FindSrcProperty("maybe")); Assert.AreEqual(prop, obj2.FindDstProperty("maybe")); Assert.IsFalse(obj.FindSrcProperty("maybe", 1).IsValid()); Assert.IsFalse(obj2.FindDstProperty("maybe", 1).IsValid()); // Iterating over properties Assert.IsTrue(obj.GetFirstProperty().IsValid()); Assert.IsTrue(obj.GetNextProperty(obj.GetFirstProperty()).IsValid()); Assert.IsTrue(obj.GetClassRootProperty().IsValid()); // FindProperty Assert.AreEqual(prop, obj.FindProperty("maybe")); Assert.AreEqual(prop, obj.FindProperty("mayBE", false)); Assert.IsFalse(obj.FindProperty("mayBE", true).IsValid()); Assert.AreEqual(prop, obj.FindProperty("maybe", Globals.FbxBoolDT)); Assert.AreEqual(prop, obj.FindProperty("mayBE", Globals.FbxBoolDT, false)); // FindPropertyHierarchical Assert.AreEqual(prop, obj.FindPropertyHierarchical("maybe")); Assert.AreEqual(prop, obj.FindPropertyHierarchical("mayBE", false)); Assert.IsFalse(obj.FindPropertyHierarchical("mayBE", true).IsValid()); Assert.AreEqual(prop, obj.FindPropertyHierarchical("maybe", Globals.FbxBoolDT)); Assert.AreEqual(prop, obj.FindPropertyHierarchical("mayBE", Globals.FbxBoolDT, false)); // Disconnecting int nSrc = obj.GetSrcPropertyCount(); int nDst = obj2.GetDstPropertyCount(); Assert.IsTrue(obj.DisconnectSrcProperty(prop)); Assert.IsTrue(obj2.DisconnectDstProperty(prop)); Assert.AreEqual(nSrc - 1, obj.GetSrcPropertyCount()); Assert.AreEqual(nDst - 1, obj2.GetDstPropertyCount()); } } /************************************************************ * Test object connection functions ************************************************************/ // need to order them this way for FbxScene, which deletes obj if Source Object is destroyed using (var ownerObj = CreateObject("ownerObj")) { using (obj = CreateObject("obj")) { // Test ConnectSrcObject functions int origCount = ownerObj.GetSrcObjectCount(); bool result = ownerObj.ConnectSrcObject(obj); Assert.IsTrue(result); Assert.IsTrue(ownerObj.IsConnectedSrcObject(obj)); Assert.AreEqual(origCount + 1, ownerObj.GetSrcObjectCount()); if (origCount == 0) { Assert.AreEqual(obj, ownerObj.GetSrcObject()); } else { // FbxScene has more than one object set as source Assert.AreNotEqual(obj, ownerObj.GetSrcObject()); } Assert.AreEqual(obj, ownerObj.GetSrcObject(origCount)); Assert.AreEqual(obj, ownerObj.FindSrcObject("obj")); Assert.IsNull(ownerObj.FindSrcObject("obj", origCount + 1)); // TODO: Fix so this doesn't crash /*Assert.That (() => { * ownerObj.FindSrcObject (null); * }, Throws.Exception.TypeOf<System.ArgumentNullException> ());*/ result = ownerObj.DisconnectSrcObject(obj); Assert.IsTrue(result); Assert.IsFalse(ownerObj.IsConnectedSrcObject(obj)); Assert.That(() => { ownerObj.ConnectSrcObject(null); }, Throws.Exception.TypeOf <System.ArgumentNullException> ()); result = ownerObj.ConnectSrcObject(obj, FbxConnection.EType.eData); Assert.IsTrue(result); } } // need to order them this way for FbxScene, which deletes ownerObj if Destination Object is destroyed using (obj = CreateObject("obj")) { using (var ownerObj = CreateObject("ownerObj")) { // Test ConnectDstObject functions int origCount = ownerObj.GetDstObjectCount(); bool result = ownerObj.ConnectDstObject(obj); Assert.IsTrue(result); Assert.IsTrue(ownerObj.IsConnectedDstObject(obj)); Assert.AreEqual(origCount + 1, ownerObj.GetDstObjectCount()); if (origCount == 0) { Assert.AreEqual(obj, ownerObj.GetDstObject()); } else { // FbxAnimCurve has the scene as a DstObject Assert.AreNotEqual(obj, ownerObj.GetDstObject()); } Assert.AreEqual(obj, ownerObj.GetDstObject(origCount)); Assert.AreEqual(obj, ownerObj.FindDstObject("obj")); Assert.IsNull(ownerObj.FindDstObject("obj", origCount + 1)); // TODO: Fix so this doesn't crash /*Assert.That (() => { * ownerObj.FindDstObject (null); * }, Throws.Exception.TypeOf<System.ArgumentNullException> ());*/ result = ownerObj.DisconnectDstObject(obj); Assert.IsTrue(result); Assert.IsFalse(ownerObj.IsConnectedDstObject(obj)); Assert.That(() => { ownerObj.ConnectDstObject(null); }, Throws.Exception.TypeOf <System.ArgumentNullException> ()); result = ownerObj.ConnectDstObject(obj, FbxConnection.EType.eData); Assert.IsTrue(result); } } }
protected override FbxScene CreateScene(FbxManager manager) { FbxScene scene = base.CreateScene(manager); FbxNode cameraNode = scene.GetRootNode().GetChild(0); FbxCamera camera = FbxCamera.Create(scene, "camera"); camera.ProjectionType.Set(FbxCamera.EProjectionType.ePerspective); camera.SetAspect(FbxCamera.EAspectRatioMode.eFixedRatio, 300, 400); camera.FilmAspectRatio.Set(240); camera.SetApertureWidth(4); camera.SetApertureHeight(2); camera.SetApertureMode(FbxCamera.EApertureMode.eFocalLength); camera.FocalLength.Set(32); camera.SetNearPlane(1); camera.SetFarPlane(100); // create custom property (background color) var bgColorProperty = FbxProperty.Create(cameraNode, Globals.FbxColor4DT, "backgroundColor"); Assert.IsTrue(bgColorProperty.IsValid()); bgColorProperty.Set(new FbxColor(0.5, 0.4, 0.1, 1)); // Must be marked user-defined or it won't be shown in most DCCs bgColorProperty.ModifyFlag(FbxPropertyFlags.EFlags.eUserDefined, true); bgColorProperty.ModifyFlag(FbxPropertyFlags.EFlags.eAnimatable, true); Assert.IsTrue(bgColorProperty.GetFlag(FbxPropertyFlags.EFlags.eUserDefined)); Assert.IsTrue(bgColorProperty.GetFlag(FbxPropertyFlags.EFlags.eAnimatable)); // create custom property (clear flags) var clearFlagsProperty = FbxProperty.Create(cameraNode, Globals.FbxIntDT, "clearFlags"); Assert.IsTrue(clearFlagsProperty.IsValid()); clearFlagsProperty.Set(4); // Must be marked user-defined or it won't be shown in most DCCs clearFlagsProperty.ModifyFlag(FbxPropertyFlags.EFlags.eUserDefined, true); clearFlagsProperty.ModifyFlag(FbxPropertyFlags.EFlags.eAnimatable, true); Assert.IsTrue(clearFlagsProperty.GetFlag(FbxPropertyFlags.EFlags.eUserDefined)); Assert.IsTrue(clearFlagsProperty.GetFlag(FbxPropertyFlags.EFlags.eAnimatable)); // Add camera properties to animation clip FbxAnimStack animStack = scene.GetCurrentAnimationStack(); FbxAnimLayer animLayer = animStack.GetAnimLayerMember(); // TODO: (UNI-19438) Figure out why trying to do GetCurve for NearPlane always returns null CreateAnimCurves(cameraNode, animLayer, new List <PropertyComponentPair> () { new PropertyComponentPair("backgroundColor", new string[] { Globals.FBXSDK_CURVENODE_COLOR_RED, Globals.FBXSDK_CURVENODE_COLOR_GREEN, Globals.FBXSDK_CURVENODE_COLOR_BLUE, "W" }), new PropertyComponentPair("FocalLength", new string[] { null }), new PropertyComponentPair("clearFlags", new string[] { null }) }, (index) => { return(index); }, (index) => { return(index / 5.0f); }, camera); cameraNode.SetNodeAttribute(camera); // set the default camera scene.GetGlobalSettings().SetDefaultCamera(cameraNode.GetName()); return(scene); }
internal static FbxSurfaceMaterial CreateFbxMaterial( FbxExportGlobals G, string meshNamespace, IExportableMaterial exportableMaterial, HashSet <string> createdMaterialNames) { string materialName; if (exportableMaterial is BrushDescriptor) { // Toolkit uses this guid (in "N" format) to look up a BrushDescriptor. // See Toolkit's ModelImportSettings.GetDescriptorForStroke materialName = $"{exportableMaterial.UniqueName:N}_{meshNamespace}_{exportableMaterial.DurableName}"; } else if (exportableMaterial is DynamicExportableMaterial dem) { // Comes from {fbx,obj,gltf,...} import from {Poly, Media Library} // This is a customized version of a BrushDescriptor -- almost certainly // Pbr{Blend,Opaque}{Double,Single}Sided with maybe an added texture and // some of its params customized. // TBT will merge the material created by Unity for this FbxMaterial with // the premade material it has for the parent guid. materialName = $"{dem.Parent.m_Guid:N}_{meshNamespace}_{dem.DurableName}"; } else { Debug.LogWarning($"Unknown class {exportableMaterial.GetType().Name}"); materialName = $"{meshNamespace}_{exportableMaterial.DurableName}"; } // If only ExportFbx were a non-static class we could merge it with FbxExportGlobals materialName = ExportUtils.CreateUniqueName(materialName, createdMaterialNames); FbxSurfaceLambert material = FbxSurfaceLambert.Create(G.m_scene, materialName); material.Ambient.Set(new FbxDouble3(0, 0, 0)); material.Diffuse.Set(new FbxDouble3(1.0, 1.0, 1.0)); if (exportableMaterial.EmissiveFactor > 0) { material.EmissiveFactor.Set(exportableMaterial.EmissiveFactor); material.Emissive.Set(new FbxDouble3(1.0, 1.0, 1.0)); } if (exportableMaterial.BlendMode != ExportableMaterialBlendMode.None) { var blendMode = FbxProperty.Create(material, Globals.FbxStringDT, "BlendMode"); switch (exportableMaterial.BlendMode) { case ExportableMaterialBlendMode.AlphaMask: blendMode.SetString(new FbxString("AlphaMask")); material.TransparencyFactor.Set(0.2); break; case ExportableMaterialBlendMode.AdditiveBlend: blendMode.SetString(new FbxString("AdditiveBlend")); break; } } // Export the texture if (exportableMaterial.HasExportTexture()) { // This is not perfectly unique, but it is good enough for fbx export // better would be to use <durable>_<guid> but that's ugly, and nobody uses // the textures anyway, so... let's leave well enough alone for now. string albedoTextureName = exportableMaterial.DurableName; var fullTextureDir = Path.Combine(G.m_outputDir, kRelativeTextureDir); if (!Directory.Exists(fullTextureDir)) { if (!FileUtils.InitializeDirectoryWithUserError(fullTextureDir)) { throw new IOException("Cannot write textures"); } } string src = exportableMaterial.GetExportTextureFilename(); var textureFileName = albedoTextureName + ".png"; var textureFilePath = Path.Combine(fullTextureDir, textureFileName); FileInfo srcInfo = new FileInfo(src); if (srcInfo.Exists && !new FileInfo(textureFilePath).Exists) { srcInfo.CopyTo(textureFilePath); } FbxFileTexture texture = FbxFileTexture.Create(G.m_scene, albedoTextureName + "_texture"); texture.SetFileName(textureFilePath); texture.SetTextureUse(FbxTexture.ETextureUse.eStandard); texture.SetMappingType(FbxTexture.EMappingType.eUV); texture.SetMaterialUse(FbxFileTexture.EMaterialUse.eModelMaterial); texture.UVSet.Set(new FbxString("uv0")); material.Diffuse.ConnectSrcObject(texture); material.TransparentColor.ConnectSrcObject(texture); } else { foreach (var kvp in exportableMaterial.TextureUris) { string parameterName = kvp.Key; string textureUri = kvp.Value; if (ExportFileReference.IsHttp(textureUri)) { // fbx can't deal with http references to textures continue; } ExportFileReference fileRef = ExportFileReference.GetOrCreateSafeLocal( G.m_disambiguationContext, textureUri, exportableMaterial.UriBase, $"{meshNamespace}_{Path.GetFileName(textureUri)}"); AddTextureToMaterial(G, fileRef, material, parameterName); } } return(material); }