Exemple #1
0
        /// 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);
            }
        }
Exemple #2
0
        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);
        }
Exemple #9
0
        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);
        }