public virtual void TestSetConstrainedObject() { if (ConstraintType == FbxConstraint.EType.eUnknown) { return; } using (var constraint = CreateObject("constraint")) { Assert.That(() => SetConstrainedObject(constraint, null), Throws.Exception.TypeOf <System.ArgumentNullException> ()); var fbxNode = FbxNode.Create(Manager, "rootnode"); SetConstrainedObject(constraint, fbxNode); Assert.That(constraint.GetConstrainedObject(), Is.EqualTo(fbxNode)); } }
// Returns the root, or a node right under the root. // Either way, the transform stack is guaranteed to be identity. static FbxNode GetGroupNode(FbxManager manager, FbxScene scene, UInt32 group) { FbxNode root = scene.GetRootNode(); if (group == 0) { return(root); } string childName = $"group_{group}"; FbxNode child = root.FindChild(childName, false); if (child == null) { child = FbxNode.Create(manager, childName); root.AddChild(child); } return(child); }
public virtual void TestAddConstraintSource() { using (var constraint = CreateObject("constraint")) { Assert.That(() => AddConstraintSource(constraint, null), Throws.Exception.TypeOf <System.ArgumentNullException> ()); Assert.That(constraint.GetConstraintSourceCount(), Is.EqualTo(0)); var fbxNode = FbxNode.Create(Manager, "rootnode"); AddConstraintSource(constraint, fbxNode); Assert.That(constraint.GetConstraintSource(0), Is.EqualTo(fbxNode)); Assert.That(constraint.GetConstraintSourceCount(), Is.EqualTo(1)); fbxNode = FbxNode.Create(Manager, "node2"); AddConstraintSourceDouble(constraint, fbxNode, 2.0); Assert.That(constraint.GetConstraintSource(1), Is.EqualTo(fbxNode)); Assert.That(constraint.GetConstraintSourceCount(), Is.EqualTo(2)); } }
public FbxNode CreateSkeleton(List <FMeshBoneInfo> boneInfos, ref List <FbxNode> BoneNodes) { if (boneInfos == null || boneInfos.Count == 0) { return(null); } for (int BoneIndex = 0; BoneIndex < boneInfos.Count; BoneIndex++) { FMeshBoneInfo CurrentBone = boneInfos[BoneIndex]; FbxSkeleton SkeletonAttribute = FbxSkeleton.Create(Scene, CurrentBone.Name); if (BoneIndex != 0) { SkeletonAttribute.SetSkeletonType(FbxSkeleton.EType.eLimbNode); //SkeletonAttribute.Size.Set(1.0); } else { SkeletonAttribute.SetSkeletonType(FbxSkeleton.EType.eRoot); //SkeletonAttribute.Size.Set(1.0); } // Create the node FbxNode BoneNode = FbxNode.Create(Scene, CurrentBone.Name); BoneNode.SetNodeAttribute(SkeletonAttribute); FbxDouble3 LocalPos = FbxDataConverter.ConvertToFbxPos(CurrentBone.BoneTransform.position); FbxDouble3 LocalRot = FbxDataConverter.ConvertToFbxRot(CurrentBone.BoneTransform.rotation); FbxDouble3 LocalScale = FbxDataConverter.ConvertToFbxScale(CurrentBone.BoneTransform.scale); BoneNode.LclTranslation.Set(LocalPos); BoneNode.LclRotation.Set(LocalRot); BoneNode.LclScaling.Set(LocalScale); if (BoneIndex != 0) { BoneNodes[CurrentBone.ParentIndex].AddChild(BoneNode); } BoneNodes.Add(BoneNode); } return(BoneNodes[0]); }
/// <summary> /// Exports the game object has a light component /// </summary> protected void ExportComponents(GameObject unityGo, FbxScene fbxScene, FbxNode fbxNodeParent) { // create an node and add it as a child of parent FbxNode fbxNode = FbxNode.Create(fbxScene, unityGo.name); NumNodes++; ExportTransform(unityGo.transform, fbxNode); var fbxMesh = ExportMesh(unityGo, fbxScene); if (fbxMesh != null) { // set the fbxNode containing the mesh fbxNode.SetNodeAttribute(fbxMesh); fbxNode.SetShadingMode(FbxNode.EShadingMode.eWireFrame); } FbxLight fbxLight = ExportLight(unityGo, fbxScene, fbxNode); if (fbxLight != null) { fbxNode.SetNodeAttribute(fbxLight); } if (Verbose) { Debug.Log(string.Format("exporting {0}", fbxNode.GetName())); } fbxNodeParent.AddChild(fbxNode); // add mapping between fbxnode for light // and unity game object for animation export MapUnityObjectToFbxNode [unityGo] = fbxNode; // now unityGo through our children and recurse foreach (Transform childT in unityGo.transform) { ExportComponents(childT.gameObject, fbxScene, fbxNode); } return; }
protected override FbxScene CreateScene(FbxManager manager) { // Create a cube as a static mesh FbxScene scene = FbxScene.Create(manager, "myScene"); FbxNode meshNode = FbxNode.Create(scene, "MeshNode"); FbxMesh cubeMesh = FbxMesh.Create(scene, "cube"); meshNode.SetNodeAttribute(cubeMesh); scene.GetRootNode().AddChild(meshNode); cubeMesh.InitControlPoints(24); for (int i = 0; i < cubeMesh.GetControlPointsCount(); i++) { cubeMesh.SetControlPointAt(m_controlPoints [i], i); } // A cube: 6 polygons with 4 vertices each int[] vertices = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; for (int i = 0; i < 6; i++) { cubeMesh.BeginPolygon(pGroup: -1); for (int j = 0; j < 4; j++) { cubeMesh.AddPolygon(vertices[i * 4 + j]); } cubeMesh.EndPolygon(); } return(scene); }
/// <summary> /// Exports the game object has a camera component /// </summary> protected void ExportComponents(GameObject unityGo, FbxScene fbxScene, FbxNode fbxNodeParent) { Camera unityCamera = unityGo.GetComponent <Camera> (); if (unityCamera == null) { return; } // create an node and add it as a child of parent FbxNode fbxNode = FbxNode.Create(fbxScene, unityGo.name); NumNodes++; FbxNodeAttribute fbxNodeAttr = ExportCamera(unityCamera, fbxScene, fbxNode); if (fbxNodeAttr != null) { fbxNode.SetNodeAttribute(fbxNodeAttr); // make the last camera exported the default camera DefaultCamera = fbxNode.GetName(); } if (Verbose) { Debug.Log(string.Format("exporting {0}", fbxNode.GetName())); } fbxNodeParent.AddChild(fbxNode); // add mapping between fbxnode for light // and unity game object for animation export MapUnityObjectToFbxNode [unityGo] = fbxNode; // now unityGo through our children and recurse foreach (Transform childT in unityGo.transform) { ExportComponents(childT.gameObject, fbxScene, fbxNode); } return; }
protected void ExportComponents(GameObject unityGo, FbxScene fbxScene, FbxNode fbxParentNode) { // create an sketelon root FbxNode fbxRootNode = FbxNode.Create(fbxScene, unityGo.name); // create node hierarchy ExportNodeHierarchy(unityGo, fbxRootNode); // create skeleton bones if (ExportSkeleton(unityGo, fbxScene)) { fbxParentNode.AddChild(fbxRootNode); } // create animation takes ExportAnimationClips(unityGo, fbxScene); return; }
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); }
/// <summary> /// Unconditionally export components on this game object /// </summary> protected void ExportComponents(GameObject unityGo, FbxScene fbxScene, FbxNode fbxNodeParent) { // create an node and add it as a child of parent FbxNode fbxNode = FbxNode.Create(fbxScene, unityGo.name); NumNodes++; if (Verbose) { Debug.Log(string.Format("exporting {0}", fbxNode.GetName())); } fbxNodeParent.AddChild(fbxNode); // now unityGo through our children and recurse foreach (Transform childT in unityGo.transform) { ExportComponents(childT.gameObject, fbxScene, fbxNode); } return; }
protected override FbxScene CreateScene(FbxManager manager) { // Create a cube as a static mesh FbxScene scene = FbxScene.Create(manager, "myScene"); FbxNode meshNode = FbxNode.Create(scene, "MeshNode"); FbxMesh cubeMesh = FbxMesh.Create(scene, "cube"); meshNode.SetNodeAttribute(cubeMesh); scene.GetRootNode().AddChild(meshNode); cubeMesh.InitControlPoints(24); for (int i = 0; i < cubeMesh.GetControlPointsCount(); i++) { cubeMesh.SetControlPointAt(m_controlPoints [i], i); } return(scene); }
protected override FbxScene CreateScene(FbxManager manager) { // create the following node hierarchy to test: // Root // / \ // Child0 Child1 // | // Child2 // / | \ // Child3 Child4 Child5 FbxScene scene = FbxScene.Create(manager, "myScene"); FbxNode root = FbxNode.Create(scene, "Root"); // set the root invisible root.SetVisibility(false); // don't let children inherit visibility of invisible root node root.VisibilityInheritance.Set(false); FbxNode[] children = new FbxNode[6]; for (int i = 0; i < children.Length; i++) { children [i] = FbxNode.Create(scene, "Child" + i); // set even nodes visible, and odd nodes invisible children [i].SetVisibility(i % 2 == 0); } scene.GetRootNode().AddChild(root); root.AddChild(children [0]); root.AddChild(children [1]); children [1].AddChild(children [2]); children [2].AddChild(children [3]); children [2].AddChild(children [4]); children [2].AddChild(children [5]); return(scene); }
static FbxScene BuildScene(FbxManager fbxManager) { // Create a scene var fbxScene = FbxScene.Create(fbxManager, "Scene"); // Create 5000 nulls. Show progress on this task from [0,0.5] EditorUtility.DisplayProgressBar(ProgressBarTitle, "Creating the scene", 0); int percent = 1 + NumNulls / 100; for (int i = 0; i < NumNulls; ++i) { FbxNode.Create(fbxScene, "node_" + i); if (i % percent == 0) { if (EditorUtility.DisplayCancelableProgressBar(ProgressBarTitle, "Creating the scene", 0.5f * (float)i / (float)NumNulls)) { // cancel silently return(null); } } } return(fbxScene); }
/// <summary> /// Unconditionally export components on this game object /// </summary> protected void ExportComponents(GameObject unityGo, FbxScene fbxScene, FbxNode fbxParentNode) { // create an FbxNode and add it as a child of fbxParentNode FbxNode fbxNode = FbxNode.Create(fbxScene, unityGo.name); NumNodes++; ExportTransform(unityGo.transform, fbxNode); ExportMesh(GetMeshInfo(unityGo), fbxNode, fbxScene); #if UNI_16194 // if this GameObject is at the root of the scene, // make it invisible, but leave all its children as is // set the node visibility fbxNode.SetVisibility(unityGo.transform.parent ? unityGo.activeSelf : false); // don't inherit visibility of invisible root node if (unityGo.transform.parent == null) { fbxNode.VisibilityInheritance.Set(false); } #endif if (Verbose) { Debug.Log(string.Format("exporting {0}", fbxNode.GetName())); } fbxParentNode.AddChild(fbxNode); // now unityGo through our children and recurse foreach (Transform uniChildT in unityGo.transform) { ExportComponents(uniChildT.gameObject, fbxScene, fbxNode); } return; }
public void TestBasics() { Assert.That(!string.IsNullOrEmpty(ModelExporter.GetVersionFromReadme())); // Test GetOrCreateLayer using (var fbxManager = FbxManager.Create()) { var fbxMesh = FbxMesh.Create(fbxManager, "name"); var layer0 = ModelExporter.GetOrCreateLayer(fbxMesh); Assert.That(layer0, Is.Not.Null); Assert.That(ModelExporter.GetOrCreateLayer(fbxMesh), Is.EqualTo(layer0)); var layer5 = ModelExporter.GetOrCreateLayer(fbxMesh, layer: 5); Assert.That(layer5, Is.Not.Null); Assert.That(layer5, Is.Not.EqualTo(layer0)); } // Test axis conversion: a x b in left-handed is the same as b x a // in right-handed (that's why we need to flip the winding order). var a = new Vector3(1, 0, 0); var b = new Vector3(0, 0, 1); var crossLeft = Vector3.Cross(a, b); var afbx = ModelExporter.ConvertToRightHanded(a); var bfbx = ModelExporter.ConvertToRightHanded(b); Assert.AreEqual(ModelExporter.ConvertToRightHanded(crossLeft), bfbx.CrossProduct(afbx)); // Test scale conversion. Nothing complicated here... var afbxPosition = ModelExporter.ConvertToRightHanded(a, ModelExporter.UnitScaleFactor); Assert.AreEqual(100, afbxPosition.Length()); // Test rotation conversion. var q = Quaternion.Euler(new Vector3(0, 90, 0)); var fbxAngles = ModelExporter.ConvertQuaternionToXYZEuler(q); Assert.AreEqual(fbxAngles.X, 0); Assert.That(fbxAngles.Y, Is.InRange(-90.001, -89.999)); Assert.AreEqual(fbxAngles.Z, 0); Assert.That(ModelExporter.DefaultMaterial); // Test non-static functions. using (var fbxManager = FbxManager.Create()) { var fbxScene = FbxScene.Create(fbxManager, "scene"); var fbxNode = FbxNode.Create(fbxScene, "node"); var exporter = new ModelExporter(); // Test ExportMaterial: it exports and it re-exports bool result = exporter.ExportMaterial(ModelExporter.DefaultMaterial, fbxScene, fbxNode); Assert.IsTrue(result); var fbxMaterial = fbxNode.GetMaterial(0); Assert.That(fbxMaterial, Is.Not.Null); result = exporter.ExportMaterial(ModelExporter.DefaultMaterial, fbxScene, fbxNode); var fbxMaterial2 = fbxNode.GetMaterial(1); Assert.AreEqual(fbxMaterial, fbxMaterial2); // Test ExportTexture: it finds the same texture for the default-material (it doesn't create a new one) var fbxMaterialNew = FbxSurfaceLambert.Create(fbxScene, "lambert"); exporter.ExportTexture(ModelExporter.DefaultMaterial, "_MainTex", fbxMaterialNew, FbxSurfaceLambert.sBump); Assert.AreEqual( fbxMaterial.FindProperty(FbxSurfaceLambert.sDiffuse).GetSrcObject(), fbxMaterialNew.FindProperty(FbxSurfaceLambert.sBump).GetSrcObject() ); // Test ExportMesh: make sure we exported a mesh with welded vertices. var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); var cubeNode = FbxNode.Create(fbxScene, "cube"); exporter.ExportMesh(cube.GetComponent <MeshFilter>().sharedMesh, cubeNode); Assert.That(cubeNode.GetMesh(), Is.Not.Null); Assert.That(cubeNode.GetMesh().GetControlPointsCount(), Is.EqualTo(8)); } // Test exporting a skinned-mesh. Make sure it doesn't leak (it did at one point) { var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); var character = new GameObject(); var smr = character.AddComponent <SkinnedMeshRenderer>(); smr.sharedMesh = cube.GetComponent <MeshFilter>().sharedMesh; var meshCount = Object.FindObjectsOfType <Mesh>().Length; ModelExporter.ExportObject(GetRandomFbxFilePath(), character); Assert.AreEqual(meshCount, Object.FindObjectsOfType <Mesh>().Length); } }
protected override FbxScene CreateScene(FbxManager manager) { FbxScene scene = FbxScene.Create(manager, "myScene"); // Create the following node hierarchy with transforms: // Root // (t: 0,10,4) // (r: 0,0,0) // (s: 1,1,1) // / \ // child0 child1 // (t: 1,1,1) (t: 0,0,0) // (r: 0,0,90) (r: 180,5,0) // (s: 2,2,2) (s: 3,2,1) // | // child2 // (t: 5,6,20) // (r: 0,10,0) // (s: 1,0.5,1) FbxNode root = FbxNode.Create(scene, "Root"); root.SetNodeAttribute(ExportNull(scene)); root.SetShadingMode(FbxNode.EShadingMode.eWireFrame); // Set the transform values root.LclTranslation.Set(new FbxDouble3(0, 10, 4)); root.LclRotation.Set(new FbxDouble3(0, 0, 0)); root.LclScaling.Set(new FbxDouble3(1, 1, 1)); // Set the pre/post rotation, pivots and offsets // NOTE: For some reason when using PreRotation.Set() instead of SetPreRotation(), // the PreRotation does not get imported properly. Same is true for the other properties. // Also only works if EPivot set is SourcePivot. // TODO: figure out why the other ways don't work. root.SetPreRotation(FbxNode.EPivotSet.eSourcePivot, new FbxVector4(30, 10, 45)); root.SetPostRotation(FbxNode.EPivotSet.eSourcePivot, new FbxVector4(9, 10, 5)); root.SetRotationPivot(FbxNode.EPivotSet.eSourcePivot, new FbxVector4(5, 6, 7)); root.SetScalingPivot(FbxNode.EPivotSet.eSourcePivot, new FbxVector4(1, 2, 1)); root.SetRotationOffset(FbxNode.EPivotSet.eSourcePivot, new FbxVector4(0.6, 8, 0.3)); root.SetScalingOffset(FbxNode.EPivotSet.eSourcePivot, new FbxVector4(10, 4, 3)); FbxNode[] children = new FbxNode[3]; FbxDouble3[][] transforms = { new FbxDouble3[] { new FbxDouble3(1, 1, 1), new FbxDouble3(0, 0, 90), new FbxDouble3(2, 2, 2) }, new FbxDouble3[] { new FbxDouble3(0, 0, 0), new FbxDouble3(180, 5, 0), new FbxDouble3(3, 2, 1) }, new FbxDouble3[] { new FbxDouble3(5, 6, 20), new FbxDouble3(0, 10, 0), new FbxDouble3(1, 0.5, 1) } }; for (int i = 0; i < children.Length; i++) { children [i] = FbxNode.Create(scene, "Child" + i); // set the fbxNode's node attribute children[i].SetNodeAttribute(ExportNull(scene)); children[i].SetShadingMode(FbxNode.EShadingMode.eWireFrame); // set the transform children [i].LclTranslation.Set(transforms [i] [0]); children [i].LclRotation.Set(transforms [i] [1]); children [i].LclScaling.Set(transforms [i] [2]); // set some values to check against later (doesn't really matter what the values are) children [i].SetPreRotation(FbxNode.EPivotSet.eSourcePivot, new FbxVector4(i, i * 2, i % 3)); children [i].SetPostRotation(FbxNode.EPivotSet.eSourcePivot, new FbxVector4(i - 1, i + 5, i)); children [i].SetRotationPivot(FbxNode.EPivotSet.eSourcePivot, new FbxVector4(i / 2, i, i + 3)); children [i].SetScalingPivot(FbxNode.EPivotSet.eSourcePivot, new FbxVector4(i * 5, i - 1, i / 4)); children [i].SetRotationOffset(FbxNode.EPivotSet.eSourcePivot, new FbxVector4(0.6 * i, 8, i / 2.0f)); children [i].SetScalingOffset(FbxNode.EPivotSet.eSourcePivot, new FbxVector4(i, i, i)); } // Create the hierarchy scene.GetRootNode().AddChild(root); root.AddChild(children [0]); root.AddChild(children [1]); children [1].AddChild(children [2]); return(scene); }
// outputFile must be a full path. static void WriteObjectsAndConnections2(FbxExportGlobals G) { var payload = ExportCollector.GetExportPayload( AxisConvention.kFbxAccordingToUnity, includeLocalMediaContent: true); // Write out each brush entry's geometry. foreach (var brushMeshPayload in payload.groups.SelectMany(g => g.brushMeshes)) { // This code used to not set the transform; check that it didn't cause issues Debug.Assert(brushMeshPayload.xform.isIdentity); FbxNode parentNode = GetGroupNode(G.m_manager, G.m_scene, brushMeshPayload.group); ExportMeshPayload_Global(G, brushMeshPayload, parentNode); } // Models with exportable meshes. foreach (var sameInstance in payload.modelMeshes.GroupBy(m => (m.model, m.modelId))) { var modelMeshPayloads = sameInstance.ToList(); if (modelMeshPayloads.Count == 0) { continue; } // All of these pieces will come from the same Widget and therefore will have // the same group id, root transform, etc var first = modelMeshPayloads[0]; FbxNode parentParentNode = GetGroupNode(G.m_manager, G.m_scene, first.group); string rootNodeName = $"model_{first.model.GetExportName()}_{first.modelId}"; if (modelMeshPayloads.Count == 1 && first.localXform.isIdentity) { // Condense the two nodes into one; give the top-level node the same name // it would have had had it been multi-level. FbxNode newNode = ExportMeshPayload_Global(G, first, parentParentNode); newNode.SetName(rootNodeName); } else { FbxNode parentNode = FbxNode.Create(G.m_manager, rootNodeName); parentNode.SetLocalTransform(first.parentXform); parentParentNode.AddChild(parentNode); foreach (var modelMeshPayload in modelMeshPayloads) { ExportMeshPayload_Local(G, modelMeshPayload, parentNode); } } } foreach (ImageQuadPayload meshPayload in payload.imageQuads) { FbxNode groupNode = GetGroupNode(G.m_manager, G.m_scene, meshPayload.group); ExportMeshPayload_Global(G, meshPayload, groupNode); } // Things that can only be exported as transforms (videos, images, models, ...) foreach (var referenceThing in payload.referenceThings) { FbxNode node = FbxNode.Create(G.m_manager, "reference_" + referenceThing.name); node.SetLocalTransform(referenceThing.xform); GetGroupNode(G.m_manager, G.m_scene, referenceThing.group).AddChild(node); } }
/// <summary> /// Export GameObject's as a skinned mesh with bones /// </summary> protected void ExportSkinnedMesh(Animator unityAnimator, FbxScene fbxScene, FbxNode fbxParentNode) { GameObject unityGo = unityAnimator.gameObject; SkinnedMeshRenderer unitySkin = unityGo.GetComponentInChildren <SkinnedMeshRenderer> (); if (unitySkin == null) { Debug.LogError("could not find skinned mesh"); return; } var meshInfo = GetSkinnedMeshInfo(unityGo); if (meshInfo.renderer == null) { Debug.LogError("mesh has no renderer"); return; } // create an FbxNode and add it as a child of fbxParentNode FbxNode fbxNode = FbxNode.Create(fbxScene, unityAnimator.name); Dictionary <Transform, FbxNode> boneNodes = new Dictionary <Transform, FbxNode> (); // export skeleton if (ExportSkeleton(meshInfo, fbxScene, fbxNode, ref boneNodes)) { // export skin FbxNode fbxMeshNode = ExportMesh(meshInfo, fbxScene, fbxNode); FbxMesh fbxMesh = fbxMeshNode.GetMesh(); if (fbxMesh == null) { Debug.LogError("Could not find mesh"); return; } // bind mesh to skeleton ExportSkin(meshInfo, fbxScene, fbxMesh, fbxMeshNode, boneNodes); // add bind pose ExportBindPose(fbxNode, fbxMeshNode, fbxScene, boneNodes); fbxParentNode.AddChild(fbxNode); NumNodes++; if (Verbose) { Debug.Log(string.Format("exporting {0} {1}", "Skin", fbxNode.GetName())); } } else { Debug.LogError("failed to export skeleton"); } }
public void BasicTests() { using (var manager = FbxManager.Create()) { // FbxPropertyT<FbxBool> example: VisibilityInheritance on a node var node = FbxNode.Create(manager, "node"); GenericPropertyTests <FbxPropertyBool> (node.VisibilityInheritance, node, "Visibility Inheritance", Globals.FbxVisibilityInheritanceDT); var property = node.VisibilityInheritance; property.Set(false); Assert.AreEqual(false, property.Get()); Assert.AreEqual(false, property.EvaluateValue()); Assert.AreEqual(false, property.EvaluateValue(FbxTime.FromSecondDouble(5))); Assert.AreEqual(false, property.EvaluateValue(FbxTime.FromSecondDouble(5), true)); } using (var manager = FbxManager.Create()) { // FbxPropertyT<FbxDouble> example: several of them on a Lambert shader var obj = FbxSurfaceLambert.Create(manager, "lambert"); GenericPropertyTests <FbxPropertyDouble> (obj.EmissiveFactor, obj, "EmissiveFactor", Globals.FbxDoubleDT); var property = obj.EmissiveFactor; property.Set(5.0); // bool Set<float> is not accessible here! Assert.AreEqual(5.0, property.Get()); Assert.AreEqual(5.0, property.EvaluateValue()); Assert.AreEqual(5.0, property.EvaluateValue(FbxTime.FromSecondDouble(5))); Assert.AreEqual(5.0, property.EvaluateValue(FbxTime.FromSecondDouble(5), true)); } using (var manager = FbxManager.Create()) { // FbxPropertyT<Double3> example: the LclTranslation on a node var node = FbxNode.Create(manager, "node"); GenericPropertyTests <FbxPropertyDouble3> (node.LclTranslation, node, "Lcl Translation", Globals.FbxLocalTranslationDT); var property = node.LclTranslation; property.Set(new FbxDouble3(1, 2, 3)); Assert.AreEqual(new FbxDouble3(1, 2, 3), property.Get()); Assert.AreEqual(new FbxDouble3(1, 2, 3), property.EvaluateValue()); Assert.AreEqual(new FbxDouble3(1, 2, 3), property.EvaluateValue(FbxTime.FromSecondDouble(5))); Assert.AreEqual(new FbxDouble3(1, 2, 3), property.EvaluateValue(FbxTime.FromSecondDouble(5), true)); } using (var manager = FbxManager.Create()) { // FbxPropertyT<float> example: the LeftBarnDoor on a light var light = FbxLight.Create(manager, "light"); GenericPropertyTests(light.LeftBarnDoor, light, "LeftBarnDoor", Globals.FbxFloatDT); var property = light.LeftBarnDoor; light.LeftBarnDoor.Set(5.0f); Assert.AreEqual(5.0f, light.LeftBarnDoor.Get()); Assert.AreEqual(5.0f, property.EvaluateValue()); Assert.AreEqual(5.0f, property.EvaluateValue(FbxTime.FromSecondDouble(5))); Assert.AreEqual(5.0f, property.EvaluateValue(FbxTime.FromSecondDouble(5), true)); } using (var manager = FbxManager.Create()) { // FbxPropertyT<int> example: the WorldUpType on an aim constraint var constraint = FbxConstraintAim.Create(manager, "constraint"); GenericPropertyTests(constraint.WorldUpType, constraint, "WorldUpType", Globals.FbxEnumDT); var property = constraint.WorldUpType; int value = (int)FbxConstraintAim.EWorldUp.eAimAtObjectUp; constraint.WorldUpType.Set(value); Assert.That(constraint.WorldUpType.Get(), Is.EqualTo(value)); Assert.That(property.EvaluateValue(), Is.EqualTo(value)); Assert.That(property.EvaluateValue(FbxTime.FromSecondDouble(5)), Is.EqualTo(value)); Assert.That(property.EvaluateValue(FbxTime.FromSecondDouble(5), true), Is.EqualTo(value)); } using (var manager = FbxManager.Create()) { // FbxPropertyT<FbxString> example: the description of a shader implementation var impl = FbxImplementation.Create(manager, "name"); GenericPropertyTests <FbxPropertyString> (impl.RenderAPI, impl, "RenderAPI", Globals.FbxStringDT); var property = impl.RenderAPI; property.Set("a value"); Assert.AreEqual("a value", property.Get()); // animated strings come out as empty-string Assert.AreEqual("", property.EvaluateValue()); Assert.AreEqual("", property.EvaluateValue(FbxTime.FromSecondDouble(5))); Assert.AreEqual("", property.EvaluateValue(FbxTime.FromSecondDouble(5), true)); } using (var manager = FbxManager.Create()) { // FbxPropertyT for FbxTexture enums EBlendMode and EWrapMode var tex = FbxTexture.Create(manager, "tex"); FbxPropertyTest.GenericPropertyTests(tex.CurrentTextureBlendMode, tex, "CurrentTextureBlendMode", Globals.FbxEnumDT); tex.CurrentTextureBlendMode.Set(FbxTexture.EBlendMode.eAdditive); Assert.AreEqual(FbxTexture.EBlendMode.eAdditive, tex.CurrentTextureBlendMode.Get()); Assert.AreEqual(FbxTexture.EBlendMode.eAdditive, tex.CurrentTextureBlendMode.EvaluateValue()); Assert.AreEqual(FbxTexture.EBlendMode.eAdditive, tex.CurrentTextureBlendMode.EvaluateValue(FbxTime.FromSecondDouble(5))); Assert.AreEqual(FbxTexture.EBlendMode.eAdditive, tex.CurrentTextureBlendMode.EvaluateValue(FbxTime.FromSecondDouble(5), true)); FbxPropertyTest.GenericPropertyTests(tex.WrapModeU, tex, "WrapModeU", Globals.FbxEnumDT); tex.WrapModeU.Set(FbxTexture.EWrapMode.eClamp); Assert.AreEqual(FbxTexture.EWrapMode.eClamp, tex.WrapModeU.Get()); Assert.AreEqual(FbxTexture.EWrapMode.eClamp, tex.WrapModeU.EvaluateValue()); Assert.AreEqual(FbxTexture.EWrapMode.eClamp, tex.WrapModeU.EvaluateValue(FbxTime.FromSecondDouble(5))); Assert.AreEqual(FbxTexture.EWrapMode.eClamp, tex.WrapModeU.EvaluateValue(FbxTime.FromSecondDouble(5), true)); } using (var manager = FbxManager.Create()) { // FbxPropertyT<FbxNull.ELook> var null1 = FbxNull.Create(manager, "null1"); FbxPropertyTest.GenericPropertyTests(null1.Look, null1, "Look", Globals.FbxEnumDT); null1.Look.Set(FbxNull.ELook.eCross); Assert.AreEqual(FbxNull.ELook.eCross, null1.Look.Get()); Assert.AreEqual(FbxNull.ELook.eCross, null1.Look.EvaluateValue()); Assert.AreEqual(FbxNull.ELook.eCross, null1.Look.EvaluateValue(FbxTime.FromSecondDouble(5))); Assert.AreEqual(FbxNull.ELook.eCross, null1.Look.EvaluateValue(FbxTime.FromSecondDouble(5), true)); } using (var manager = FbxManager.Create()) { // FbxPropertyT<FbxMarker.ELook> var marker1 = FbxMarker.Create(manager, "marker1"); FbxPropertyTest.GenericPropertyTests(marker1.Look, marker1, "Look", Globals.FbxEnumDT); marker1.Look.Set(FbxMarker.ELook.eCapsule); Assert.AreEqual(FbxMarker.ELook.eCapsule, marker1.Look.Get()); Assert.AreEqual(FbxMarker.ELook.eCapsule, marker1.Look.EvaluateValue()); Assert.AreEqual(FbxMarker.ELook.eCapsule, marker1.Look.EvaluateValue(FbxTime.FromSecondDouble(5))); Assert.AreEqual(FbxMarker.ELook.eCapsule, marker1.Look.EvaluateValue(FbxTime.FromSecondDouble(5), true)); } using (var manager = FbxManager.Create()) { // FbxPropertyT for FbxCamera enum EProjectionType var camera = FbxCamera.Create(manager, "camera"); FbxPropertyTest.GenericPropertyTests(camera.ProjectionType, camera, "CameraProjectionType", Globals.FbxEnumDT); camera.ProjectionType.Set(FbxCamera.EProjectionType.ePerspective); Assert.AreEqual(FbxCamera.EProjectionType.ePerspective, camera.ProjectionType.Get()); Assert.AreEqual(FbxCamera.EProjectionType.ePerspective, camera.ProjectionType.EvaluateValue()); Assert.AreEqual(FbxCamera.EProjectionType.ePerspective, camera.ProjectionType.EvaluateValue(FbxTime.FromSecondDouble(5))); Assert.AreEqual(FbxCamera.EProjectionType.ePerspective, camera.ProjectionType.EvaluateValue(FbxTime.FromSecondDouble(5), true)); } using (var manager = FbxManager.Create()) { // FbxPropertyT for FbxCamera enum EGateFit var camera = FbxCamera.Create(manager, "camera"); FbxPropertyTest.GenericPropertyTests(camera.GateFit, camera, "GateFit", Globals.FbxEnumDT); camera.GateFit.Set(FbxCamera.EGateFit.eFitHorizontal); Assert.AreEqual(FbxCamera.EGateFit.eFitHorizontal, camera.GateFit.Get()); Assert.AreEqual(FbxCamera.EGateFit.eFitHorizontal, camera.GateFit.EvaluateValue()); Assert.AreEqual(FbxCamera.EGateFit.eFitHorizontal, camera.GateFit.EvaluateValue(FbxTime.FromSecondDouble(5))); Assert.AreEqual(FbxCamera.EGateFit.eFitHorizontal, camera.GateFit.EvaluateValue(FbxTime.FromSecondDouble(5), true)); } using (var manager = FbxManager.Create()) { // FbxPropertyT<EInheritType> var node = FbxNode.Create(manager, "node"); FbxPropertyTest.GenericPropertyTests(node.InheritType, node, "InheritType", Globals.FbxEnumDT); node.InheritType.Set(FbxTransform.EInheritType.eInheritRSrs); Assert.AreEqual(FbxTransform.EInheritType.eInheritRSrs, node.InheritType.Get()); Assert.AreEqual(FbxTransform.EInheritType.eInheritRSrs, node.InheritType.EvaluateValue()); Assert.AreEqual(FbxTransform.EInheritType.eInheritRSrs, node.InheritType.EvaluateValue(FbxTime.FromSecondDouble(5))); Assert.AreEqual(FbxTransform.EInheritType.eInheritRSrs, node.InheritType.EvaluateValue(FbxTime.FromSecondDouble(5), true)); } using (var manager = FbxManager.Create()) { // FbxPropertyT for FbxLight enums var light = FbxLight.Create(manager, "light"); FbxPropertyTest.GenericPropertyTests(light.LightType, light, "LightType", Globals.FbxEnumDT); light.LightType.Set(FbxLight.EType.eSpot); Assert.AreEqual(FbxLight.EType.eSpot, light.LightType.Get()); Assert.AreEqual(FbxLight.EType.eSpot, light.LightType.EvaluateValue()); Assert.AreEqual(FbxLight.EType.eSpot, light.LightType.EvaluateValue(FbxTime.FromSecondDouble(5))); Assert.AreEqual(FbxLight.EType.eSpot, light.LightType.EvaluateValue(FbxTime.FromSecondDouble(5), true)); FbxPropertyTest.GenericPropertyTests(light.AreaLightShape, light, "AreaLightShape", Globals.FbxEnumDT); light.AreaLightShape.Set(FbxLight.EAreaLightShape.eSphere); Assert.AreEqual(FbxLight.EAreaLightShape.eSphere, light.AreaLightShape.Get()); Assert.AreEqual(FbxLight.EAreaLightShape.eSphere, light.AreaLightShape.EvaluateValue()); Assert.AreEqual(FbxLight.EAreaLightShape.eSphere, light.AreaLightShape.EvaluateValue(FbxTime.FromSecondDouble(5))); Assert.AreEqual(FbxLight.EAreaLightShape.eSphere, light.AreaLightShape.EvaluateValue(FbxTime.FromSecondDouble(5), true)); FbxPropertyTest.GenericPropertyTests(light.DecayType, light, "DecayType", Globals.FbxEnumDT); light.DecayType.Set(FbxLight.EDecayType.eCubic); Assert.AreEqual(FbxLight.EDecayType.eCubic, light.DecayType.Get()); Assert.AreEqual(FbxLight.EDecayType.eCubic, light.DecayType.EvaluateValue()); Assert.AreEqual(FbxLight.EDecayType.eCubic, light.DecayType.EvaluateValue(FbxTime.FromSecondDouble(5))); Assert.AreEqual(FbxLight.EDecayType.eCubic, light.DecayType.EvaluateValue(FbxTime.FromSecondDouble(5), true)); } using (var manager = FbxManager.Create()) { // Test all the create and destroy operations FbxProperty root, child; var obj = FbxObject.Create(manager, "obj"); Assert.IsNotNull(FbxProperty.Create(obj, Globals.FbxStringDT, "a")); Assert.IsNotNull(FbxProperty.Create(obj, Globals.FbxStringDT, "b", "label")); Assert.IsNotNull(FbxProperty.Create(obj, Globals.FbxStringDT, "c", "label", false)); bool didFind; Assert.IsNotNull(FbxProperty.Create(obj, Globals.FbxStringDT, "c", "label", true, out didFind)); Assert.IsTrue(didFind); root = FbxProperty.Create(obj, Globals.FbxCompoundDT, "root"); child = FbxProperty.Create(root, Globals.FbxStringDT, "a"); Assert.IsNotNull(child); Assert.IsNotNull(FbxProperty.Create(root, Globals.FbxStringDT, "b", "label")); Assert.IsNotNull(FbxProperty.Create(root, Globals.FbxStringDT, "c", "label", false)); Assert.IsNotNull(FbxProperty.Create(root, Globals.FbxStringDT, "c", "label", true, out didFind)); Assert.IsTrue(didFind); child.Destroy(); root.DestroyChildren(); Assert.IsNotNull(FbxProperty.Create(root, Globals.FbxStringDT, "c", "label", true, out didFind)); Assert.IsFalse(didFind); root.DestroyRecursively(); } }
public void TestBasics() { // create a curve we can unroll. var fbxScene = FbxScene.Create(Manager, "scene"); var fbxNode = FbxNode.Create(fbxScene, "node"); var fbxAnimNode = FbxAnimCurveNode.CreateTypedCurveNode(fbxNode.LclRotation, fbxScene); FbxAnimCurve[] fbxAnimCurves = { fbxAnimNode.CreateCurve(fbxAnimNode.GetName(), Globals.FBXSDK_CURVENODE_COMPONENT_X), fbxAnimNode.CreateCurve(fbxAnimNode.GetName(), Globals.FBXSDK_CURVENODE_COMPONENT_Y), fbxAnimNode.CreateCurve(fbxAnimNode.GetName(), Globals.FBXSDK_CURVENODE_COMPONENT_Z) }; FbxAnimCurveFilterUnroll filter = new FbxAnimCurveFilterUnroll(); Assert.That(filter.NeedApply(fbxAnimNode), Is.False, "expected not to need to unroll curves"); Assert.That(filter.Apply(fbxAnimNode), Is.False, "expected to have nothing to do"); // ensure coverage for function that takes an FbxStatus Assert.That(filter.NeedApply(fbxAnimNode, new FbxStatus()), Is.False); Assert.That(filter.Apply(fbxAnimNode, new FbxStatus()), Is.False); // configure the unroll condition foreach (float[] keydata in KeyTimeValues) { double seconds = keydata[0]; foreach (var fbxAnimCurve in fbxAnimCurves) { fbxAnimCurve.KeyModifyBegin(); } using (var fbxTime = FbxTime.FromSecondDouble(seconds)) { for (int ci = 0; ci < fbxAnimCurves.Length; ci++) { int ki = fbxAnimCurves[ci].KeyAdd(fbxTime); fbxAnimCurves[ci].KeySet(ki, fbxTime, keydata[ci + 1]); } } foreach (var fbxAnimCurve in fbxAnimCurves) { fbxAnimCurve.KeyModifyEnd(); } } Assert.That(filter.NeedApply(fbxAnimNode), Is.True, "expected to need to unroll curves"); Assert.That(filter.Apply(fbxAnimNode), Is.True, "expected to have unroll"); IEnumerator origKeydata = KeyTimeValues.GetEnumerator(); for (int ki = 0; ki < fbxAnimCurves[0].KeyGetCount(); ki++) { List <float> result = new List <float>() { (float)fbxAnimCurves[0].KeyGetTime(ki).GetSecondDouble() }; result = result.Concat((from ac in fbxAnimCurves select ac.KeyGetValue(ki))).ToList(); origKeydata.MoveNext(); if (ki == 0 || ki == 3 || ki == 4) { Assert.That(result, Is.EqualTo(origKeydata.Current)); } else { Assert.That(result, Is.Not.EqualTo(origKeydata.Current)); } } filter.Reset(); filter.Dispose(); }
public void TestAdd() { using (var fbxPose = CreateObject("pose")){ using (var fbxNode = FbxNode.Create(Manager, "node")) using (var fbxMatrix = new FbxMatrix()){ Assert.AreEqual(0, fbxPose.GetCount()); // test basic use int index = fbxPose.Add(fbxNode, fbxMatrix); // returns -1 if it fails Assert.Greater(index, -1); Assert.AreEqual(fbxPose.GetNode(index), fbxNode); Assert.AreEqual(fbxPose.GetMatrix(index), fbxMatrix); Assert.AreEqual(1, fbxPose.GetCount()); // test adding null Assert.That(() => { fbxPose.Add(null, null); }, Throws.Exception.TypeOf <System.ArgumentNullException> ()); fbxPose.Add(FbxNode.Create(Manager, "node1"), fbxMatrix); Assert.AreEqual(2, fbxPose.GetCount()); } var node = FbxNode.Create(Manager, "node1"); using (var fbxMatrix = new FbxMatrix()) { // test adding invalid node node.Destroy(); Assert.That(() => { fbxPose.Add(node, fbxMatrix); }, Throws.Exception.TypeOf <System.ArgumentNullException> ()); } using (var fbxNode = FbxNode.Create(Manager, "node2")){ var fbxMatrix = new FbxMatrix(); // test adding invalid matrix fbxMatrix.Dispose(); Assert.That(() => { fbxPose.Add(fbxNode, fbxMatrix); }, Throws.Exception.TypeOf <System.ArgumentNullException> ()); } using (var fbxNode = FbxNode.Create(Manager, "node3")) using (var fbxMatrix = new FbxMatrix()) { // test with local matrix arg int index = fbxPose.Add(fbxNode, fbxMatrix, true); // false is default Assert.Greater(index, -1); Assert.AreEqual(fbxPose.GetNode(index), fbxNode); Assert.AreEqual(fbxPose.GetMatrix(index), fbxMatrix); } using (var fbxNode = FbxNode.Create(Manager, "node4")) using (var fbxMatrix = new FbxMatrix()) { // test with multiple bind pose arg int index = fbxPose.Add(fbxNode, fbxMatrix, false, false); // true is default Assert.Greater(index, -1); Assert.AreEqual(fbxPose.GetNode(index), fbxNode); Assert.AreEqual(fbxPose.GetMatrix(index), fbxMatrix); } } }
public static void ExportMesh(Mesh mesh, string directory, string fileName) { var filePath = Path.Combine(directory, fileName); // Make a temporary copy of the mesh to modify it Mesh tempMesh = Object.Instantiate(mesh); tempMesh.name = mesh.name; // If meters, divide by 100 since default is cm. Assume centered at origin. if (fbxUnit == FbxSystemUnit.m) { Vector3[] vertices = tempMesh.vertices; for (int i = 0; i < vertices.Length; ++i) { vertices[i] /= 100.0f; } tempMesh.vertices = vertices; } // You could handle other SystemUnits here // FBX Manager FbxManager manager = FbxManager.Create(); manager.SetIOSettings(FbxIOSettings.Create(manager, Globals.IOSROOT)); // FBX Exporter FbxExporter fbxExporter = FbxExporter.Create(manager, "Exporter"); // Binary int fileFormat = -1; // Ascii if (saveFbxAsAscii) { fileFormat = manager.GetIOPluginRegistry().FindWriterIDByDescription("FBX ascii (*.fbx)"); } fbxExporter.Initialize(filePath, fileFormat, manager.GetIOSettings()); fbxExporter.SetFileExportVersion("FBX201400"); // FBX Scene FbxScene fbxScene = FbxScene.Create(manager, "Scene"); FbxDocumentInfo sceneInfo = FbxDocumentInfo.Create(manager, "SceneInfo"); // Set up scene info sceneInfo.mTitle = fbxFileTitle; sceneInfo.mSubject = fbxFileSubject; sceneInfo.mComment = fbxFileComment; sceneInfo.mAuthor = fbxFileAuthor; sceneInfo.mRevision = fbxFileRevision; sceneInfo.mKeywords = fbxFileKeywords; sceneInfo.Original_ApplicationName.Set(fbxFileApplication); sceneInfo.LastSaved_ApplicationName.Set(fbxFileApplication); fbxScene.SetSceneInfo(sceneInfo); // Set up Global settings FbxGlobalSettings globalSettings = fbxScene.GetGlobalSettings(); globalSettings.SetSystemUnit(fbxUnit); globalSettings.SetAxisSystem(fbxAxisSystem); FbxNode modelNode = FbxNode.Create(fbxScene, tempMesh.name); // Add mesh to a node in the scene // TODO Wat??? // using (ModelExporter modelExporter = new ModelExporter()) // { // if (!modelExporter.ExportMesh(tempMesh, modelNode)) // Debug.LogError("Problem Exporting Mesh"); // } // add the model to the scene fbxScene.GetRootNode().AddChild(modelNode); // Finally actually save the scene bool sceneSuccess = fbxExporter.Export(fbxScene); AssetDatabase.Refresh(); // clean up temporary model if (Application.isPlaying) { Object.Destroy(tempMesh); } else { Object.DestroyImmediate(tempMesh); } }
/// <summary> /// Export bones of skinned mesh, if this is a skinned mesh with /// bones and bind poses. /// </summary> private bool ExportSkeleton(GameObject unityGo, FbxScene fbxScene) { var unitySkinnedMeshRenderer = unityGo.GetComponentInChildren <SkinnedMeshRenderer> (); if (!unitySkinnedMeshRenderer) { return(false); } var bones = unitySkinnedMeshRenderer.bones; if (bones == null || bones.Length == 0) { return(false); } var mesh = unitySkinnedMeshRenderer.sharedMesh; if (!mesh) { return(false); } var bindPoses = mesh.bindposes; if (bindPoses == null || bindPoses.Length != bones.Length) { return(false); } // Three steps: // 0. Set up the map from bone to index. // 1. Create the bones, in arbitrary order. // 2. Connect up the hierarchy. // 3. Set the transforms. // Step 0 supports step 1 (finding which is the root bone) and step 3 // (setting up transforms; the complication is the use of pivots). // Step 0: map transform to index so we can look up index by bone. Dictionary <Transform, int> index = new Dictionary <Transform, int>(); for (int boneIndex = 0, n = bones.Length; boneIndex < n; boneIndex++) { Transform unityBoneTransform = bones [boneIndex]; index[unityBoneTransform] = boneIndex; } // Step 1: create the bones. for (int boneIndex = 0, n = bones.Length; boneIndex < n; boneIndex++) { Transform unityBoneTransform = bones [boneIndex]; // Create the bone node if we haven't already. Parent it to // its corresponding parent, or to the scene if there is none. FbxNode fbxBoneNode; if (!MapUnityObjectToFbxNode.TryGetValue(unityBoneTransform.gameObject, out fbxBoneNode)) { var unityParent = unityBoneTransform.parent; FbxNode fbxParent; if (MapUnityObjectToFbxNode.TryGetValue(unityParent.gameObject, out fbxParent)) { fbxBoneNode = FbxNode.Create(fbxParent, unityBoneTransform.name); } else { fbxBoneNode = FbxNode.Create(fbxScene, unityBoneTransform.name); } MapUnityObjectToFbxNode.Add(unityBoneTransform.gameObject, fbxBoneNode); } // Set it up as a skeleton node if we haven't already. if (fbxBoneNode.GetSkeleton() == null) { FbxSkeleton fbxSkeleton = FbxSkeleton.Create(fbxScene, unityBoneTransform.name + "_Skel"); var fbxSkeletonType = index.ContainsKey(unityBoneTransform.parent) ? FbxSkeleton.EType.eLimbNode : FbxSkeleton.EType.eRoot; fbxSkeleton.SetSkeletonType(fbxSkeletonType); fbxSkeleton.Size.Set(1.0f); fbxBoneNode.SetNodeAttribute(fbxSkeleton); if (Verbose) { Debug.Log("Converted " + unityBoneTransform.name + " to a " + fbxSkeletonType + " bone"); } } } // Step 2: connect up the hierarchy. foreach (var unityBone in bones) { var fbxBone = MapUnityObjectToFbxNode[unityBone.gameObject]; var fbxParent = MapUnityObjectToFbxNode[unityBone.parent.gameObject]; fbxParent.AddChild(fbxBone); } // Step 3: set up the transforms. for (int boneIndex = 0, n = bones.Length; boneIndex < n; boneIndex++) { var unityBone = bones[boneIndex]; var fbxBone = MapUnityObjectToFbxNode[unityBone.gameObject]; Matrix4x4 pose; if (fbxBone.GetSkeleton().GetSkeletonType() == FbxSkeleton.EType.eRoot) { // bind pose is local -> root. We want root -> local, so invert. pose = bindPoses[boneIndex].inverse; // assuming parent is identity matrix } else { // Bind pose is local -> parent -> ... -> root. // We want parent -> local. // Invert our bind pose to get root -> local. // The apply parent -> root to leave just parent -> local. pose = bindPoses[index[unityBone.parent]] * bindPoses[boneIndex].inverse; } // FBX is transposed relative to Unity: transpose as we convert. FbxMatrix matrix = new FbxMatrix(); matrix.SetColumn(0, new FbxVector4(pose.GetRow(0).x, pose.GetRow(0).y, pose.GetRow(0).z, pose.GetRow(0).w)); matrix.SetColumn(1, new FbxVector4(pose.GetRow(1).x, pose.GetRow(1).y, pose.GetRow(1).z, pose.GetRow(1).w)); matrix.SetColumn(2, new FbxVector4(pose.GetRow(2).x, pose.GetRow(2).y, pose.GetRow(2).z, pose.GetRow(2).w)); matrix.SetColumn(3, new FbxVector4(pose.GetRow(3).x, pose.GetRow(3).y, pose.GetRow(3).z, pose.GetRow(3).w)); // FBX wants translation, rotation (in euler angles) and scale. // We assume there's no real shear, just rounding error. FbxVector4 translation, rotation, shear, scale; double sign; matrix.GetElements(out translation, out rotation, out shear, out scale, out sign); // Bones should have zero rotation, and use a pivot instead. fbxBone.LclTranslation.Set(new FbxDouble3(translation.X, translation.Y, translation.Z)); fbxBone.LclRotation.Set(new FbxDouble3(0, 0, 0)); fbxBone.LclScaling.Set(new FbxDouble3(scale.X, scale.Y, scale.Z)); fbxBone.SetRotationActive(true); fbxBone.SetPivotState(FbxNode.EPivotSet.eSourcePivot, FbxNode.EPivotState.ePivotReference); fbxBone.SetPreRotation(FbxNode.EPivotSet.eSourcePivot, new FbxVector4(rotation.X, rotation.Y, rotation.Z)); } return(true); }
public void TestBasics() { Assert.That(!string.IsNullOrEmpty(ModelExporter.GetVersionFromReadme())); // Test GetOrCreateLayer using (var fbxManager = FbxManager.Create()) { var fbxMesh = FbxMesh.Create(fbxManager, "name"); var layer0 = ModelExporter.GetOrCreateLayer(fbxMesh); Assert.That(layer0, Is.Not.Null); Assert.That(ModelExporter.GetOrCreateLayer(fbxMesh), Is.EqualTo(layer0)); var layer5 = ModelExporter.GetOrCreateLayer(fbxMesh, layer: 5); Assert.That(layer5, Is.Not.Null); Assert.That(layer5, Is.Not.EqualTo(layer0)); } // Test axis conversion: a x b in left-handed is the same as b x a // in right-handed (that's why we need to flip the winding order). var a = new Vector3(1, 0, 0); var b = new Vector3(0, 0, 1); var crossLeft = Vector3.Cross(a, b); Assert.That(ModelExporter.DefaultMaterial); // Test non-static functions. using (var fbxManager = FbxManager.Create()) { var fbxScene = FbxScene.Create(fbxManager, "scene"); var fbxNode = FbxNode.Create(fbxScene, "node"); var exporter = new ModelExporter(); // Test ExportMaterial: it exports and it re-exports bool result = exporter.ExportMaterial(ModelExporter.DefaultMaterial, fbxScene, fbxNode); Assert.IsTrue(result); var fbxMaterial = fbxNode.GetMaterial(0); Assert.That(fbxMaterial, Is.Not.Null); result = exporter.ExportMaterial(ModelExporter.DefaultMaterial, fbxScene, fbxNode); var fbxMaterial2 = fbxNode.GetMaterial(1); Assert.AreEqual(fbxMaterial, fbxMaterial2); // Test ExportTexture: it finds the same texture for the default-material (it doesn't create a new one) var fbxMaterialNew = FbxSurfaceLambert.Create(fbxScene, "lambert"); exporter.ExportTexture(ModelExporter.DefaultMaterial, "_MainTex", fbxMaterialNew, FbxSurfaceLambert.sBump); Assert.AreEqual( fbxMaterial.FindProperty(FbxSurfaceLambert.sDiffuse).GetSrcObject(), fbxMaterialNew.FindProperty(FbxSurfaceLambert.sBump).GetSrcObject() ); // Test ExportMesh: make sure we exported a mesh with welded vertices. var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); var cubeNode = FbxNode.Create(fbxScene, "cube"); exporter.ExportMesh(cube.GetComponent <MeshFilter>().sharedMesh, cubeNode); Assert.That(cubeNode.GetMesh(), Is.Not.Null); Assert.That(cubeNode.GetMesh().GetControlPointsCount(), Is.EqualTo(8)); } // Test exporting a skinned-mesh. Make sure it doesn't leak (it did at one point) { var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); var character = new GameObject(); var smr = character.AddComponent <SkinnedMeshRenderer>(); smr.sharedMesh = cube.GetComponent <MeshFilter>().sharedMesh; var meshCount = Object.FindObjectsOfType <Mesh>().Length; ModelExporter.ExportObject(GetRandomFbxFilePath(), character); Assert.AreEqual(meshCount, Object.FindObjectsOfType <Mesh>().Length); } // Test euler to quaternion conversion { // EulerToQuaternionZXY var v = new Vector3(50, 45, 190); var quat = ModelExporter.EulerToQuaternionZXY(v); var unityQuat = Quaternion.Euler(v); Assert.That((float)quat.X, Is.EqualTo(unityQuat.x)); Assert.That((float)quat.Y, Is.EqualTo(unityQuat.y)); Assert.That((float)quat.Z, Is.EqualTo(unityQuat.z)); Assert.That((float)quat.W, Is.EqualTo(unityQuat.w)); // EulerToQuaternionXYZ var fbxV = new FbxVector4(v.x, v.y, v.z); var xyzQuat = ModelExporter.EulerToQuaternionXYZ(fbxV); // get the vector from the quaternion FbxAMatrix m = new FbxAMatrix(); m.SetR(fbxV); var actualQuat = m.GetQ(); // since this quaternion is XYZ instead of ZXY, it should not match the quaternion // created with EulerToQuaternionZXY Assert.That(xyzQuat, Is.Not.EqualTo(quat)); Assert.That(xyzQuat, Is.EqualTo(actualQuat)); } }
public static bool ExportToFBX(Component_Mesh sourceMesh, string realFileName, out string error) { //!!!!как для Vegetation. оверрайдить в Component_Mesh? //get mesh data var operations = new List <Component_RenderingPipeline.RenderSceneData.MeshDataRenderOperation>(); foreach (var geometry in sourceMesh.GetComponents <Component_MeshGeometry>()) { if (geometry.Enabled) { geometry.CompileDataOfThisObject(out var operation); if (operation != null) { operations.Add(operation); } } } //foreach( var geometry in mesh.Result.MeshData.RenderOperations ) //{ //} FbxManager manager = null; FbxIOSettings setting = null; FbxExporter exporter = null; FbxScene scene = null; try { //init FBX manager manager = FbxManager.Create(); setting = FbxIOSettings.Create(manager, "IOSRoot"); manager.SetIOSettings(setting); scene = FbxScene.Create(manager, "scene"); scene.GetGlobalSettings().SetAxisSystem(new FbxAxisSystem(FbxAxisSystem.EPreDefinedAxisSystem.eMax)); scene.GetGlobalSettings().SetSystemUnit(new FbxSystemUnit(100)); //init FBX scene for (int nOper = 0; nOper < operations.Count; nOper++) { var oper = operations[nOper]; //get data Vector3F[] positions = null; Vector3F[] normals = null; var texCoords = new List <Vector2F[]>(); ColorValue[] colors = null; Vector3F[] tangents = null; Vector3F[] binormals = null; //Position { if (oper.VertexStructure.GetElementBySemantic(VertexElementSemantic.Position, out VertexElement element) && element.Type == VertexElementType.Float3) { var buffer = oper.VertexBuffers[element.Source]; positions = buffer.ExtractChannel <Vector3F>(element.Offset); } } //Normal { if (oper.VertexStructure.GetElementBySemantic(VertexElementSemantic.Normal, out VertexElement element) && element.Type == VertexElementType.Float3) { var buffer = oper.VertexBuffers[element.Source]; normals = buffer.ExtractChannel <Vector3F>(element.Offset); } } //TexCoord for (var channel = VertexElementSemantic.TextureCoordinate0; channel <= VertexElementSemantic.TextureCoordinate3; channel++) { if (oper.VertexStructure.GetElementBySemantic(channel, out VertexElement element) && element.Type == VertexElementType.Float2) { var buffer = oper.VertexBuffers[element.Source]; texCoords.Add(buffer.ExtractChannel <Vector2F>(element.Offset)); } } //Color { if (oper.VertexStructure.GetElementBySemantic(VertexElementSemantic.Color0, out VertexElement element)) { if (element.Type == VertexElementType.Float4) { var buffer = oper.VertexBuffers[element.Source]; var values = buffer.ExtractChannel <Vector4F>(element.Offset); colors = new ColorValue[positions.Length]; int destIndex = 0; foreach (var p in values) { colors[destIndex++] = p.ToColorValue(); } } else if (element.Type == VertexElementType.ColorABGR) { //!!!!check var buffer = oper.VertexBuffers[element.Source]; var values = buffer.ExtractChannel <uint>(element.Offset); colors = new ColorValue[positions.Length]; int destIndex = 0; foreach (var p in values) { colors[destIndex++] = new ColorValue(ColorByte.FromABGR(p)); } } else if (element.Type == VertexElementType.ColorARGB) { //!!!!check var buffer = oper.VertexBuffers[element.Source]; var values = buffer.ExtractChannel <uint>(element.Offset); colors = new ColorValue[positions.Length]; int destIndex = 0; foreach (var p in values) { colors[destIndex++] = new ColorValue(ColorByte.FromARGB(p)); } } } } //Tangent, Binormal if (normals != null) { if (oper.VertexStructure.GetElementBySemantic(VertexElementSemantic.Tangent, out VertexElement element) && element.Type == VertexElementType.Float4) { var buffer = oper.VertexBuffers[element.Source]; var tangents4 = buffer.ExtractChannel <Vector4F>(element.Offset); tangents = new Vector3F[tangents4.Length]; binormals = new Vector3F[tangents4.Length]; int destIndex = 0; foreach (var p in tangents4) { tangents[destIndex] = p.ToVector3F(); binormals[destIndex] = Vector3F.Cross(p.ToVector3F(), normals[destIndex]) * p.W; destIndex++; } } } //indices int[] indices = null; if (oper.IndexBuffer != null) { indices = oper.IndexBuffer.Indices; } //create geometry var geometryName = "Geometry " + nOper.ToString(); var mesh = FbxMesh.Create(scene, geometryName); mesh.InitControlPoints(positions.Length); FbxLayerElementNormal elementNormals = null; if (normals != null) { elementNormals = mesh.CreateElementNormal(); elementNormals.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); elementNormals.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); } FbxLayerElementVertexColor elementColors = null; if (colors != null) { elementColors = mesh.CreateElementVertexColor(); elementColors.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); elementColors.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); } FbxLayerElementTangent elementTangents = null; if (tangents != null) { elementTangents = mesh.CreateElementTangent(); elementTangents.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); elementTangents.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); } FbxLayerElementBinormal elementBinormals = null; if (binormals != null) { elementBinormals = mesh.CreateElementBinormal(); elementBinormals.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); elementBinormals.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); } var uvElements = new List <FbxLayerElementUV>(); for (int uvIndex = 0; uvIndex < texCoords.Count; uvIndex++) { var pUVElement = mesh.CreateElementUV("texcoord" + uvIndex.ToString()); pUVElement.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); pUVElement.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); uvElements.Add(pUVElement); } for (int n = 0; n < positions.Length; n++) { mesh.SetControlPointAt(ToFbxVector4(positions[n]), n); if (normals != null) { elementNormals.GetDirectArray().Add(ToFbxVector4(normals[n])); } for (int uvIndex = 0; uvIndex < texCoords.Count; uvIndex++) { var texCoord = texCoords[uvIndex][n]; texCoord.Y = 1.0f - texCoord.Y; uvElements[uvIndex].GetDirectArray().Add(ToFbxVector2(texCoord)); } if (colors != null) { elementColors.GetDirectArray().Add(ToFbxColor(colors[n])); } if (tangents != null) { elementTangents.GetDirectArray().Add(ToFbxVector4(tangents[n])); } if (binormals != null) { elementBinormals.GetDirectArray().Add(ToFbxVector4(binormals[n])); } } if (normals != null) { mesh.GetLayer(0).SetNormals(elementNormals); } if (colors != null) { mesh.GetLayer(0).SetVertexColors(elementColors); } if (tangents != null) { mesh.GetLayer(0).SetTangents(elementTangents); } if (binormals != null) { mesh.GetLayer(0).SetBinormals(elementBinormals); } int polygonCount = indices.Length / 3; for (int i = 0; i < polygonCount; i++) { mesh.BeginPolygon(-1, -1, -1, false); for (int j = 0; j < 3; j++) { int currentIndex = i * 3 + j; int vertexIndex = indices[currentIndex]; mesh.AddPolygon(vertexIndex); } mesh.EndPolygon(); } var node = FbxNode.Create(scene, geometryName); node.SetNodeAttribute(mesh); scene.GetRootNode().AddChild(mesh.GetNode()); } //save exporter = FbxExporter.Create(manager, ""); if (!exporter.Initialize(realFileName, -1, manager.GetIOSettings())) { error = "Can't initialize FBX exporter."; return(false); } if (!exporter.Export(scene)) { error = "Export to FBX failed."; return(false); } } finally { try { scene?.Destroy(); } catch { } try { exporter?.Destroy(); } catch { } try { setting?.Destroy(); } catch { } try { manager?.Destroy(); } catch { } } foreach (var op in operations) { op.DisposeBuffers(); } error = ""; return(true); }
public void TestEquality() { using (var manager = FbxManager.Create()) { // FbxProperty var node = FbxNode.Create(manager, "node"); var prop1 = FbxProperty.Create(node, Globals.FbxBoolDT, "bool1"); var prop2 = FbxProperty.Create(node, Globals.FbxBoolDT, "bool2"); var prop1copy = node.FindProperty("bool1"); EqualityTester <FbxProperty> .TestEquality(prop1, prop2, prop1copy); // FbxPropertyT<bool> var vis1 = node.VisibilityInheritance; var vis2 = FbxNode.Create(manager, "node2").VisibilityInheritance; var vis1copy = vis1; // TODO: node.FindProperty("Visibility Inheritance"); -- but that has a different proxy type EqualityTester <FbxPropertyBool> .TestEquality(vis1, vis2, vis1copy); // FbxPropertyT<EInheritType> var inhType1 = node.InheritType; var inhType2 = FbxNode.Create(manager, "node3").InheritType; var inhType1Copy = inhType1; // TODO: node.FindProperty("InheritType"); EqualityTester <FbxPropertyEInheritType> .TestEquality(inhType1, inhType2, inhType1Copy); // FbxPropertyT<double> var lambert = FbxSurfaceLambert.Create(manager, "lambert"); var emissiveCopy = lambert.EmissiveFactor; // TODO: lambert.FindProperty("EmissiveFactor"); EqualityTester <FbxPropertyDouble> .TestEquality(lambert.EmissiveFactor, lambert.AmbientFactor, emissiveCopy); // FbxPropertyT<FbxDouble3> var lclTranslationCopy = node.LclTranslation; // TODO: node.FindProperty("Lcl Translation"); EqualityTester <FbxPropertyDouble3> .TestEquality(node.LclTranslation, node.LclRotation, lclTranslationCopy); // FbxPropertyT<float> var light = FbxLight.Create(manager, "light"); EqualityTester <FbxPropertyFloat> .TestEquality(light.LeftBarnDoor, light.RightBarnDoor, light.LeftBarnDoor); // FbxPropertyT<int> var constraint = FbxConstraintAim.Create(manager, "constraint"); var constraint2 = FbxConstraintAim.Create(manager, "constraint2"); var worldUpTypeCopy = constraint.WorldUpType; // TODO: constraint.FindProperty("WorldUpType"); EqualityTester <FbxPropertyInt> .TestEquality(constraint.WorldUpType, constraint2.WorldUpType, worldUpTypeCopy); // FbxPropertyT<> for FbxTexture enums var tex1 = FbxTexture.Create(manager, "tex1"); var tex2 = FbxTexture.Create(manager, "tex2"); var blendCopy = tex1.CurrentTextureBlendMode; // TODO: tex1.FindProperty(...) EqualityTester <FbxPropertyEBlendMode> .TestEquality(tex1.CurrentTextureBlendMode, tex2.CurrentTextureBlendMode, blendCopy); var wrapCopy = tex1.WrapModeU; // TODO: tex1.FindProperty(...) EqualityTester <FbxPropertyEWrapMode> .TestEquality(tex1.WrapModeU, tex2.WrapModeU, wrapCopy); // FbxPropertyT<FbxNull.ELook> var null1 = FbxNull.Create(manager, "null1"); var null2 = FbxNull.Create(manager, "null2"); EqualityTester <FbxPropertyNullELook> .TestEquality(null1.Look, null2.Look, null1.Look); // FbxPropertyT<FbxMarker.ELook> var marker1 = FbxMarker.Create(manager, "marker1"); var marker2 = FbxMarker.Create(manager, "marker2"); EqualityTester <FbxPropertyMarkerELook> .TestEquality(marker1.Look, marker2.Look, marker1.Look); // FbxPropertyT<string> var impl = FbxImplementation.Create(manager, "impl"); var renderAPIcopy = impl.RenderAPI; // TODO: impl.FindProperty("RenderAPI"); EqualityTester <FbxPropertyString> .TestEquality(impl.RenderAPI, impl.RenderAPIVersion, renderAPIcopy); // FbxPropertyT<> for FbxCamera enum EProjectionType var cam1 = FbxCamera.Create(manager, "cam1"); var cam2 = FbxCamera.Create(manager, "cam2"); var projectionCopy = cam1.ProjectionType; EqualityTester <FbxPropertyEProjectionType> .TestEquality(cam1.ProjectionType, cam2.ProjectionType, projectionCopy); // FbxPropertyT<> for FbxLight enum EType var light1 = FbxLight.Create(manager, "light1"); var light2 = FbxLight.Create(manager, "light2"); var typeCopy = light1.LightType; EqualityTester <FbxPropertyELightType> .TestEquality(light1.LightType, light2.LightType, typeCopy); var lightShapeCopy = light1.AreaLightShape; EqualityTester <FbxPropertyEAreaLightShape> .TestEquality(light1.AreaLightShape, light2.AreaLightShape, lightShapeCopy); var decayCopy = light1.DecayType; EqualityTester <FbxPropertyEDecayType> .TestEquality(light1.DecayType, light2.DecayType, decayCopy); var floatCopy = light1.LeftBarnDoor; EqualityTester <FbxPropertyFloat> .TestEquality(light1.LeftBarnDoor, light2.LeftBarnDoor, floatCopy); } }
/// <summary> /// Export bones of skinned mesh /// </summary> protected bool ExportSkeleton(MeshInfo meshInfo, FbxScene fbxScene, FbxNode fbxParentNode, ref Dictionary <Transform, FbxNode> boneNodes) { SkinnedMeshRenderer unitySkinnedMeshRenderer = meshInfo.renderer as SkinnedMeshRenderer; if (unitySkinnedMeshRenderer.bones.Length <= 0) { return(false); } Dictionary <Transform, Matrix4x4> boneBindPose = new Dictionary <Transform, Matrix4x4>(); for (int boneIndex = 0; boneIndex < unitySkinnedMeshRenderer.bones.Length; boneIndex++) { Transform unityBoneTransform = unitySkinnedMeshRenderer.bones [boneIndex]; FbxNode fbxBoneNode = FbxNode.Create(fbxScene, unityBoneTransform.name); // Create the node's attributes FbxSkeleton fbxSkeleton = FbxSkeleton.Create(fbxScene, unityBoneTransform.name + "_Skel"); var fbxSkeletonType = FbxSkeleton.EType.eLimbNode; if (unityBoneTransform == unityBoneTransform.root || fbxParentNode.GetName().Equals(unityBoneTransform.parent.name)) { fbxSkeletonType = FbxSkeleton.EType.eRoot; } fbxSkeleton.SetSkeletonType(fbxSkeletonType); fbxSkeleton.Size.Set(1.0f); // Set the node's attribute fbxBoneNode.SetNodeAttribute(fbxSkeleton); boneBindPose.Add(unityBoneTransform, meshInfo.BindPoses [boneIndex]); // save relatation between unity transform and fbx bone node for skinning boneNodes [unityBoneTransform] = fbxBoneNode; } // set the hierarchy for the FbxNodes foreach (KeyValuePair <Transform, FbxNode> t in boneNodes) { Matrix4x4 pose; // if this is a root node then don't need to do anything if (t.Key == t.Key.root || !boneNodes.ContainsKey(t.Key.parent)) { fbxParentNode.AddChild(t.Value); pose = boneBindPose[t.Key].inverse; // assuming parent is identity matrix } else { boneNodes [t.Key.parent].AddChild(t.Value); // inverse of my bind pose times parent bind pose pose = boneBindPose[t.Key.parent] * boneBindPose[t.Key].inverse; } // use FbxMatrix to get translation and rotation relative to parent FbxMatrix matrix = new FbxMatrix(); matrix.SetColumn(0, new FbxVector4(pose.GetRow(0).x, pose.GetRow(0).y, pose.GetRow(0).z, pose.GetRow(0).w)); matrix.SetColumn(1, new FbxVector4(pose.GetRow(1).x, pose.GetRow(1).y, pose.GetRow(1).z, pose.GetRow(1).w)); matrix.SetColumn(2, new FbxVector4(pose.GetRow(2).x, pose.GetRow(2).y, pose.GetRow(2).z, pose.GetRow(2).w)); matrix.SetColumn(3, new FbxVector4(pose.GetRow(3).x, pose.GetRow(3).y, pose.GetRow(3).z, pose.GetRow(3).w)); FbxVector4 translation, rotation, shear, scale; double sign; matrix.GetElements(out translation, out rotation, out shear, out scale, out sign); // Negating the x value of the translation, and the y and z values of the prerotation // to convert from Unity to Maya coordinates (left to righthanded) t.Value.LclTranslation.Set(new FbxDouble3(-translation.X, translation.Y, translation.Z)); t.Value.LclRotation.Set(new FbxDouble3(0, 0, 0)); t.Value.LclScaling.Set(new FbxDouble3(scale.X, scale.Y, scale.Z)); t.Value.SetRotationActive(true); t.Value.SetPivotState(FbxNode.EPivotSet.eSourcePivot, FbxNode.EPivotState.ePivotReference); t.Value.SetPreRotation(FbxNode.EPivotSet.eSourcePivot, new FbxVector4(rotation.X, -rotation.Y, -rotation.Z)); } return(true); }