protected override FbxScene CreateScene(FbxManager manager) { // Create a scene with a single node that has an animation clip // attached to it FbxScene scene = FbxScene.Create(manager, "myScene"); FbxNode animNode = FbxNode.Create(scene, "animNode"); // setup anim stack FbxAnimStack fbxAnimStack = CreateAnimStack(scene); // add an animation layer FbxAnimLayer fbxAnimLayer = FbxAnimLayer.Create(scene, "animBaseLayer"); fbxAnimStack.AddMember(fbxAnimLayer); // set up the translation CreateAnimCurves( animNode, fbxAnimLayer, PropertyComponentList, (index) => { return(index * 2.0); }, (index) => { return(index * 3.0f - 1); } ); // TODO: avoid needing to this by creating typemaps for // FbxObject::GetSrcObjectCount and FbxCast. // Not trivial to do as both fbxobject.i and fbxemitter.i // have to be moved up before the ignore all statement // to allow use of templates. scene.SetCurrentAnimationStack(fbxAnimStack); scene.GetRootNode().AddChild(animNode); return(scene); }
/// <summary> /// Exports all animation /// </summary> private void ExportAnimationClip(AnimationClip unityAnimClip, GameObject unityRoot, FbxScene fbxScene) { if (unityAnimClip == null) { return; } // setup anim stack FbxAnimStack fbxAnimStack = FbxAnimStack.Create(fbxScene, unityAnimClip.name); fbxAnimStack.Description.Set("Animation Take: " + unityAnimClip.name); // add one mandatory animation layer FbxAnimLayer fbxAnimLayer = FbxAnimLayer.Create(fbxScene, "Animation Base Layer"); fbxAnimStack.AddMember(fbxAnimLayer); // Set up the FPS so our frame-relative math later works out // Custom frame rate isn't really supported in FBX SDK (there's // a bug), so try hard to find the nearest time mode. FbxTime.EMode timeMode = FbxTime.EMode.eCustom; double precision = 1e-6; while (timeMode == FbxTime.EMode.eCustom && precision < 1000) { timeMode = FbxTime.ConvertFrameRateToTimeMode(unityAnimClip.frameRate, precision); precision *= 10; } if (timeMode == FbxTime.EMode.eCustom) { timeMode = FbxTime.EMode.eFrames30; } FbxTime.SetGlobalTimeMode(timeMode); // set time correctly var fbxStartTime = FbxTime.FromSecondDouble(0); var fbxStopTime = FbxTime.FromSecondDouble(unityAnimClip.length); fbxAnimStack.SetLocalTimeSpan(new FbxTimeSpan(fbxStartTime, fbxStopTime)); foreach (EditorCurveBinding unityCurveBinding in AnimationUtility.GetCurveBindings(unityAnimClip)) { Object unityObj = AnimationUtility.GetAnimatedObject(unityRoot, unityCurveBinding); if (!unityObj) { continue; } AnimationCurve unityAnimCurve = AnimationUtility.GetEditorCurve(unityAnimClip, unityCurveBinding); if (unityAnimCurve == null) { continue; } ExportAnimCurve(unityObj, unityAnimCurve, unityCurveBinding.propertyName, fbxAnimLayer); } }
protected override FbxScene CreateScene(FbxManager manager) { // Create a scene with a single node that has an animation clip // attached to it FbxScene scene = FbxScene.Create(manager, "myScene"); FbxNode sourceNode = FbxNode.Create(scene, "source"); FbxNode constrainedNode = FbxNode.Create(scene, "constrained"); scene.GetRootNode().AddChild(sourceNode); scene.GetRootNode().AddChild(constrainedNode); FbxConstraint posConstraint = CreatePositionConstraint(scene, sourceNode, constrainedNode); Assert.That(posConstraint, Is.Not.Null); bool result = posConstraint.ConnectDstObject(scene); Assert.That(result, Is.True); // animate weight + active // setup anim stack FbxAnimStack fbxAnimStack = CreateAnimStack(scene); // add an animation layer FbxAnimLayer fbxAnimLayer = FbxAnimLayer.Create(scene, "animBaseLayer"); fbxAnimStack.AddMember(fbxAnimLayer); // set up the translation CreateAnimCurves( posConstraint, fbxAnimLayer, PropertyComponentList, (index) => { return(index * 2.0); }, (index) => { return(index * 3 - 2); } ); // TODO: avoid needing to do this by creating typemaps for // FbxObject::GetSrcObjectCount and FbxCast. // Not trivial to do as both fbxobject.i and fbxemitter.i // have to be moved up before the ignore all statement // to allow use of templates. scene.SetCurrentAnimationStack(fbxAnimStack); return(scene); }
public void CreateDocument() { Scene = FbxScene.Create(SdkManager, ""); FbxDocumentInfo SceneInfo = FbxDocumentInfo.Create(SdkManager, "SceneInfo"); SceneInfo.mTitle = new FbxString("Unreal FBX Exporter"); SceneInfo.mSubject = new FbxString("Export FBX meshes from Unreal"); SceneInfo.Original_ApplicationVendor.Set(new FbxString("Epic Games")); SceneInfo.Original_ApplicationName.Set(new FbxString("Unreal Engine")); SceneInfo.Original_ApplicationVersion.Set(new FbxString("4.18")); SceneInfo.LastSaved_ApplicationVendor.Set(new FbxString("Epic Games")); SceneInfo.LastSaved_ApplicationName.Set(new FbxString("Unreal Engine")); SceneInfo.LastSaved_ApplicationVersion.Set(new FbxString("4.18")); FbxAxisSystem.EFrontVector FrontVector = (FbxAxisSystem.EFrontVector)(0 - FbxAxisSystem.EFrontVector.eParityOdd); if (bForceFrontXAxis) { FrontVector = FbxAxisSystem.EFrontVector.eParityEven; } FbxAxisSystem UnrealZUp = new FbxAxisSystem(FbxAxisSystem.EUpVector.eZAxis, FrontVector, FbxAxisSystem.ECoordSystem.eRightHanded); //const FbxAxisSystem UnrealZUp(FbxAxisSystem.EUpVector, FrontVector, FbxAxisSystem::eRightHanded); Scene.GetGlobalSettings().SetAxisSystem(FbxAxisSystem.Max); Scene.GetGlobalSettings().SetOriginalUpAxis(FbxAxisSystem.Max); Scene.GetGlobalSettings().SetSystemUnit(FbxSystemUnit.cm); Scene.SetSceneInfo(SceneInfo); // setup anim stack AnimStack = FbxAnimStack.Create(Scene, "Unreal Take"); //KFbxSet<KTime>(AnimStack.LocalStart, KTIME_ONE_SECOND); AnimStack.Description.Set((new FbxString("Animation Take for Unreal."))); // this take contains one base layer. In fact having at least one layer is mandatory. AnimLayer = FbxAnimLayer.Create(Scene, "Base Layer"); AnimStack.AddMember(AnimLayer); //if(Mathf) }
/// <summary> /// Export an AnimationClip as a single take /// </summary> protected void ExportAnimationClip(AnimationClip unityAnimClip, GameObject unityRoot, FbxScene fbxScene) { if (Verbose) { Debug.Log(string.Format("exporting clip {1} for {0}", unityRoot.name, unityAnimClip.name)); } // setup anim stack FbxAnimStack fbxAnimStack = FbxAnimStack.Create(fbxScene, unityAnimClip.name); fbxAnimStack.Description.Set("Animation Take: " + unityAnimClip.name); // add one mandatory animation layer FbxAnimLayer fbxAnimLayer = FbxAnimLayer.Create(fbxScene, "Animation Base Layer"); fbxAnimStack.AddMember(fbxAnimLayer); // Set up the FPS so our frame-relative math later works out // Custom frame rate isn't really supported in FBX SDK (there's // a bug), so try hard to find the nearest time mode. FbxTime.EMode timeMode = FbxTime.EMode.eCustom; double precision = 1e-6; while (timeMode == FbxTime.EMode.eCustom && precision < 1000) { timeMode = FbxTime.ConvertFrameRateToTimeMode(unityAnimClip.frameRate, precision); precision *= 10; } if (timeMode == FbxTime.EMode.eCustom) { timeMode = FbxTime.EMode.eFrames30; } FbxTime.SetGlobalTimeMode(timeMode); // set time correctly var fbxStartTime = FbxTime.FromSecondDouble(0); var fbxStopTime = FbxTime.FromSecondDouble(unityAnimClip.length); fbxAnimStack.SetLocalTimeSpan(new FbxTimeSpan(fbxStartTime, fbxStopTime)); /* The major difficulty: Unity uses quaternions for rotation * (which is how it should be) but FBX uses euler angles. So we * need to gather up the list of transform curves per object. */ var quaternions = new Dictionary <UnityEngine.GameObject, QuaternionCurve> (); foreach (EditorCurveBinding unityCurveBinding in AnimationUtility.GetCurveBindings(unityAnimClip)) { Object unityObj = AnimationUtility.GetAnimatedObject(unityRoot, unityCurveBinding); if (!unityObj) { continue; } AnimationCurve unityAnimCurve = AnimationUtility.GetEditorCurve(unityAnimClip, unityCurveBinding); if (unityAnimCurve == null) { continue; } int index = QuaternionCurve.GetQuaternionIndex(unityCurveBinding.propertyName); if (index == -1) { if (Verbose) { Debug.Log(string.Format("export binding {1} for {0}", unityCurveBinding.propertyName, unityObj.ToString())); } /* Some normal property (e.g. translation), export right away */ ExportAnimCurve(unityObj, unityAnimCurve, unityCurveBinding.propertyName, fbxScene, fbxAnimLayer); } else { /* Rotation property; save it to convert quaternion -> euler later. */ var unityGo = GetGameObject(unityObj); if (!unityGo) { continue; } QuaternionCurve quat; if (!quaternions.TryGetValue(unityGo, out quat)) { quat = new QuaternionCurve(); quaternions.Add(unityGo, quat); } quat.SetCurve(index, unityAnimCurve); } } /* now export all the quaternion curves */ foreach (var kvp in quaternions) { var unityGo = kvp.Key; var quat = kvp.Value; FbxNode fbxNode; if (!MapUnityObjectToFbxNode.TryGetValue(unityGo, out fbxNode)) { Debug.LogError(string.Format("no fbxnode found for '0'", unityGo.name)); continue; } quat.Animate(unityGo.transform, fbxNode, fbxAnimLayer, Verbose); } }