protected override void CheckScene(FbxScene scene) { base.CheckScene(scene); FbxScene origScene = CreateScene(FbxManager); Assert.AreEqual(origScene.GetRootNode().GetChildCount(), origScene.GetRootNode().GetChildCount()); FbxNode origMeshNode = origScene.GetRootNode().GetChild(0); FbxNode importMeshNode = scene.GetRootNode().GetChild(0); FbxNode origSkelRootNode = origScene.GetRootNode().GetChild(1); FbxNode importSkelRootNode = scene.GetRootNode().GetChild(1); // Check that the skeletons match CheckSkeleton(origSkelRootNode, importSkelRootNode); // TODO: Fix so that calling GetDeformer either allows us to downcast // to FbxSkin, or so that it just returns the correct type. // Check that the mesh is correctly linked to the skeleton //CheckMeshLinkedToSkeleton(origMeshNode.GetMesh(), importMeshNode.GetMesh()); origMeshNode.GetMesh(); importMeshNode.GetMesh(); // Check that bind pose is set correctly CheckExportBindPose(origScene, scene); }
// Test for bug where exporting FbxShapes with empty names would fail to import all // blendshapes except the first in Maya (fixed by UT-3216) private void TestFbxShapeNamesNotEmpty(FbxNode node) { var mesh = node.GetMesh(); if (mesh != null) { for (int i = 0; i < mesh.GetDeformerCount(); i++) { var blendshape = mesh.GetBlendShapeDeformer(i); if (blendshape == null) { continue; } for (int j = 0; j < blendshape.GetBlendShapeChannelCount(); j++) { var blendShapeChannel = blendshape.GetBlendShapeChannel(j); for (int k = 0; k < blendShapeChannel.GetTargetShapeCount(); k++) { var shape = blendShapeChannel.GetTargetShape(k); Assert.That(string.IsNullOrEmpty(shape.GetName()), Is.False, string.Format("FbxShape missing name on blendshape {0}", blendshape.GetName())); } } } } for (int i = 0; i < node.GetChildCount(); i++) { TestFbxShapeNamesNotEmpty(node.GetChild(i)); } }
protected void LinkMeshToSkeleton(FbxScene scene, FbxNode meshNode, FbxNode skelRootNode) { FbxNode limb1 = skelRootNode.GetChild(0); FbxNode limb2 = limb1.GetChild(0); FbxCluster rootCluster = FbxCluster.Create(scene, "RootCluster"); rootCluster.SetLink(skelRootNode); rootCluster.SetLinkMode(FbxCluster.ELinkMode.eTotalOne); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { rootCluster.AddControlPointIndex(4 * i + j, 1.0 - 0.25 * i); } } FbxCluster limb1Cluster = FbxCluster.Create(scene, "Limb1Cluster"); limb1Cluster.SetLink(limb1); limb1Cluster.SetLinkMode(FbxCluster.ELinkMode.eTotalOne); for (int i = 1; i < 6; i++) { for (int j = 0; j < 4; j++) { limb1Cluster.AddControlPointIndex(4 * i + j, (i == 1 || i == 5 ? 0.25 : 0.5)); } } FbxCluster limb2Cluster = FbxCluster.Create(scene, "Limb2Cluster"); limb2Cluster.SetLink(limb2); limb2Cluster.SetLinkMode(FbxCluster.ELinkMode.eTotalOne); for (int i = 3; i < 7; i++) { for (int j = 0; j < 4; j++) { limb2Cluster.AddControlPointIndex(4 * i + j, 0.25 * (i - 2)); } } FbxAMatrix globalTransform = meshNode.EvaluateGlobalTransform(); rootCluster.SetTransformMatrix(globalTransform); limb1Cluster.SetTransformMatrix(globalTransform); limb2Cluster.SetTransformMatrix(globalTransform); rootCluster.SetTransformLinkMatrix(skelRootNode.EvaluateGlobalTransform()); limb1Cluster.SetTransformLinkMatrix(limb1.EvaluateGlobalTransform()); limb2Cluster.SetTransformLinkMatrix(limb2.EvaluateGlobalTransform()); FbxSkin skin = FbxSkin.Create(scene, "Skin"); skin.AddCluster(rootCluster); skin.AddCluster(limb1Cluster); skin.AddCluster(limb2Cluster); meshNode.GetMesh().AddDeformer(skin); }
/// <summary> /// Convert scene's system units but leave scaling unchanged /// </summary> public void ConvertScene(FbxScene fbxScene, FbxSystemUnit toUnits) { // Get scale factor. float scaleFactor = 1.0f; scaleFactor = (float)fbxScene.GetGlobalSettings().GetSystemUnit().GetConversionFactorTo(toUnits); if (scaleFactor.Equals(1.0f)) { return; } // Get root node. FbxNode fbxRootNode = fbxScene.GetRootNode(); // For all the nodes to convert the translations Queue <FbxNode> fbxNodes = new Queue <FbxNode> (); fbxNodes.Enqueue(fbxRootNode); while (fbxNodes.Count > 0) { FbxNode fbxNode = fbxNodes.Dequeue(); // Convert node's translation. FbxDouble3 lclTrs = fbxNode.LclTranslation.Get(); #if UNI_18844 lclTrs *= scaleFactor; lclTrs *= scaleFactor; lclTrs *= scaleFactor; #endif fbxNode.LclTranslation.Set(lclTrs); FbxMesh fbxMesh = fbxNode.GetMesh(); if (fbxMesh != null) { for (int i = 0; i < fbxMesh.GetControlPointsCount(); ++i) { FbxVector4 fbxVector4 = fbxMesh.GetControlPointAt(i); #if UNI_18844 fbxVector4 *= scaleFactor; #endif fbxMesh.SetControlPointAt(fbxVector4, i); } } for (int i = 0; i < fbxNode.GetChildCount(); ++i) { fbxNodes.Enqueue(fbxNode.GetChild(i)); } } }
private void CheckSceneHelper(FbxNode node, FbxMesh mesh, FbxSurfaceMaterial material) { if (node == null) { return; } Assert.AreEqual(mesh, node.GetMesh()); int matIndex = node.GetMaterialIndex(m_materialName); Assert.GreaterOrEqual(matIndex, 0); Assert.AreEqual(material, node.GetMaterial(matIndex)); for (int i = 0; i < node.GetChildCount(); i++) { // recurse through the hierarchy CheckSceneHelper(node.GetChild(i), mesh, material); } }
static void LoadSkinsFromNodeRecursive(FbxNode pNode, List <FbxSkin> skinsResult) { FbxNodeAttribute pNodeAttribute = pNode.GetNodeAttribute(); if (pNodeAttribute?.GetAttributeType() == FbxNodeAttribute.EType.eMesh) { FbxMesh pMesh = pNode.GetMesh(); int skinCount = pMesh.GetDeformerCount(FbxDeformer.EDeformerType.eSkin); for (int i = 0; i < skinCount; i++) { FbxSkin pSkin = FbxSkin.Cast(pMesh.GetDeformer(i, FbxDeformer.EDeformerType.eSkin)); skinsResult.Add(pSkin); } } for (int i = 0; i < pNode.GetChildCount(); i++) { LoadSkinsFromNodeRecursive(pNode.GetChild(i), skinsResult); } }
Transform CreateNode(Transform parent, FbxNode fbxNode) { var unityNode = new GameObject(fbxNode.GetName()); Transform unityTransform = unityNode.transform; unityTransform.parent = parent; // If there's a mesh attached, create it var fbxMesh = fbxNode.GetMesh(); if (fbxMesh != null) { var mesh = GetOrCreateInstance(fbxMesh); var meshFilter = unityNode.AddComponent <MeshFilter>(); var meshRender = unityNode.AddComponent <MeshRenderer>(); meshFilter.sharedMesh = mesh; meshRender.material = DefaultMaterial; } return(unityTransform); }
private static long GetTotalVerts(FbxNode node) { FbxNodeAttribute a = node.GetNodeAttribute(); int nChildren = node.GetChildCount(); long vertCount = 0; if (a != null) { var attrType = a.GetAttributeType(); if (attrType == FbxNodeAttribute.EType.eMesh) { FbxMesh fbxMesh = node.GetMesh(); fbxMesh.SplitPoints(); vertCount = fbxMesh.GetControlPointsCount(); } } for (int i = 0; i < nChildren; i++) { vertCount += GetTotalVerts(node.GetChild(i)); } return(vertCount); }
protected override void CheckScene(FbxScene scene) { base.CheckScene(scene); FbxNode rootNode = scene.GetRootNode().GetChild(0); Assert.IsNotNull(rootNode); FbxMesh sharedMesh = rootNode.GetMesh(); Assert.IsNotNull(sharedMesh); Assert.AreEqual(m_meshName, sharedMesh.GetName()); int matIndex = rootNode.GetMaterialIndex(m_materialName); Assert.GreaterOrEqual(matIndex, 0); FbxSurfaceMaterial sharedMat = rootNode.GetMaterial(matIndex); Assert.IsNotNull(sharedMat); // check that the mesh is the same for all children CheckSceneHelper(rootNode, sharedMesh, sharedMat); }
/// <summary> /// Process mesh data and setup MeshFilter component /// </summary> private void ProcessMesh(FbxNode fbxNode, GameObject unityGo) { FbxMesh fbxMesh = fbxNode.GetMesh(); if (fbxMesh == null) { return; } var unityMesh = new Mesh(); // create mesh var unityVertices = new List <Vector3> (); var unityTriangleIndices = new List <int> (); // transfer vertices for (int i = 0; i < fbxMesh.GetControlPointsCount(); ++i) { FbxVector4 fbxVector4 = fbxMesh.GetControlPointAt(i); Debug.Assert(fbxVector4.X <= float.MaxValue && fbxVector4.X >= float.MinValue); Debug.Assert(fbxVector4.Y <= float.MaxValue && fbxVector4.Y >= float.MinValue); Debug.Assert(fbxVector4.Z <= float.MaxValue && fbxVector4.Z >= float.MinValue); unityVertices.Add(new Vector3((float)fbxVector4.X, (float)fbxVector4.Y, (float)fbxVector4.Z)); } // transfer triangles for (int polyIndex = 0; polyIndex < fbxMesh.GetPolygonCount(); ++polyIndex) { int polySize = fbxMesh.GetPolygonSize(polyIndex); // only support triangles Debug.Assert(polySize == 3); for (int polyVertexIndex = 0; polyVertexIndex < polySize; ++polyVertexIndex) { int vertexIndex = fbxMesh.GetPolygonVertex(polyIndex, polyVertexIndex); unityTriangleIndices.Add(vertexIndex); } } unityMesh.vertices = unityVertices.ToArray(); // TODO: // - support Mesh.SetTriangles - multiple materials per mesh // - support Mesh.SetIndices - other topologies e.g. quads unityMesh.triangles = unityTriangleIndices.ToArray(); unityMesh.RecalculateNormals(); var unityMeshFilter = unityGo.AddComponent <MeshFilter> (); unityMeshFilter.sharedMesh = unityMesh; var unityRenderer = unityGo.AddComponent <MeshRenderer> (); { // Assign the default material (hack!) var unityPrimitive = GameObject.CreatePrimitive(PrimitiveType.Quad); var unityMat = unityPrimitive.GetComponent <MeshRenderer> ().sharedMaterial; unityRenderer.sharedMaterial = unityMat; UnityEngine.Object.DestroyImmediate(unityPrimitive); } }
/// <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"); } }