protected void ExportBindPose(FbxNode meshNode, FbxScene fbxScene, List <FbxNode> boneNodes) { FbxPose fbxPose = FbxPose.Create(fbxScene, "Pose"); // set as bind pose fbxPose.SetIsBindPose(true); // assume each bone node has one weighted vertex cluster foreach (FbxNode fbxNode in boneNodes) { // EvaluateGlobalTransform returns an FbxAMatrix (affine matrix) // which has to be converted to an FbxMatrix so that it can be passed to fbxPose.Add(). // The hierarchy for FbxMatrix and FbxAMatrix is as follows: // // FbxDouble4x4 // / \ // FbxMatrix FbxAMatrix // // Therefore we can't convert directly from FbxAMatrix to FbxMatrix, // however FbxMatrix has a constructor that takes an FbxAMatrix. FbxMatrix fbxBindMatrix = new FbxMatrix(fbxNode.EvaluateGlobalTransform()); fbxPose.Add(fbxNode, fbxBindMatrix); } FbxMatrix bindMatrix = new FbxMatrix(meshNode.EvaluateGlobalTransform()); fbxPose.Add(meshNode, bindMatrix); // add the pose to the scene fbxScene.AddPose(fbxPose); }
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); }
public static FbxAMatrix EvaluateGlobalTransform(FbxNode node) { return(node.EvaluateGlobalTransform()); //Warning: Эквивалент node.EvaluateGlobalTransform(). Но обнаружилось отличие на модели BaseMesh_Anim.fbx, эта модель в MaxAxisSystem не происходит конверсия. // На этой модели в контексте использования в Skeleton работает корректно. А в контексте использования координат Mesh не корректно: модель повернута на 90 градусов. // Видимо еще что-то надо учитывать кроме AxisSystem. Либо в CalculateGlobalTransform AxisSystem учитывается не полностью. // Сейчас в этой функции нет необходимости, достаточно node.EvaluateGlobalTransform() т.к. только в момент импорта все вычисляется. //return CalculateGlobalTransform(node); }
public void NodesInHierarchy_CalcGlobalTransformWithTranslationAndWithRotation_ReturnsRotatedThenTranslated() { // given: var node1 = new FbxNode("node1"); var node2 = new FbxNode("node2"); node1.AddChild(node2); var t = new FbxVector4(2, 3, 4); var r = new FbxVector4(45, 0, 0); node1.LclTranslation.Set(t); node2.LclRotation.Set(r); // when: var actual = node1.EvaluateGlobalTransform(); // then: Assert.AreEqual(1.000000f, actual.Get(0, 0), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(0, 1), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(0, 2), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(0, 3), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(1, 0), 0.000001f); Assert.AreEqual(1.000000f, actual.Get(1, 1), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(1, 2), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(1, 3), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(2, 0), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(2, 1), 0.000001f); Assert.AreEqual(1.000000f, actual.Get(2, 2), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(2, 3), 0.000001f); Assert.AreEqual(2.000000f, actual.Get(3, 0), 0.000001f); Assert.AreEqual(3.000000f, actual.Get(3, 1), 0.000001f); Assert.AreEqual(4.000000f, actual.Get(3, 2), 0.000001f); Assert.AreEqual(1.000000f, actual.Get(3, 3), 0.000001f); // when: actual = node2.EvaluateGlobalTransform(); // then: Assert.AreEqual(1.000000f, actual.Get(0, 0), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(0, 1), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(0, 2), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(0, 3), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(1, 0), 0.000001f); Assert.AreEqual(0.707107f, actual.Get(1, 1), 0.000001f); Assert.AreEqual(0.707107f, actual.Get(1, 2), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(1, 3), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(2, 0), 0.000001f); Assert.AreEqual(-0.707107f, actual.Get(2, 1), 0.000001f); Assert.AreEqual(0.707107f, actual.Get(2, 2), 0.000001f); Assert.AreEqual(0.000000f, actual.Get(2, 3), 0.000001f); Assert.AreEqual(2.000000f, actual.Get(3, 0), 0.000001f); Assert.AreEqual(3.000000f, actual.Get(3, 1), 0.000001f); Assert.AreEqual(4.000000f, actual.Get(3, 2), 0.000001f); Assert.AreEqual(1.000000f, actual.Get(3, 3), 0.000001f); }
public void NodesInHierarchy_CalcGlobalTransform_ChildsIsTimesParent() { // given: var node1 = new FbxNode("node1"); var node2 = new FbxNode("node2"); node1.AddChild(node2); var r1 = new FbxVector4(45, 0, 0); var r2 = new FbxVector4(0, 60, 0); node1.LclRotation.Set(r1); node2.LclRotation.Set(r2); // when: var g1 = node1.EvaluateGlobalTransform(); var g2 = node2.EvaluateGlobalTransform(); var l1 = node1.EvaluateLocalTransform(); var l2 = node2.EvaluateLocalTransform(); Assert.AreEqual(l1.Get(0, 0), g1.Get(0, 0), 0.000001f); Assert.AreEqual(l1.Get(0, 1), g1.Get(0, 1), 0.000001f); Assert.AreEqual(l1.Get(0, 2), g1.Get(0, 2), 0.000001f); Assert.AreEqual(l1.Get(0, 3), g1.Get(0, 3), 0.000001f); Assert.AreEqual(l1.Get(1, 0), g1.Get(1, 0), 0.000001f); Assert.AreEqual(l1.Get(1, 1), g1.Get(1, 1), 0.000001f); Assert.AreEqual(l1.Get(1, 2), g1.Get(1, 2), 0.000001f); Assert.AreEqual(l1.Get(1, 3), g1.Get(1, 3), 0.000001f); Assert.AreEqual(l1.Get(2, 0), g1.Get(2, 0), 0.000001f); Assert.AreEqual(l1.Get(2, 1), g1.Get(2, 1), 0.000001f); Assert.AreEqual(l1.Get(2, 2), g1.Get(2, 2), 0.000001f); Assert.AreEqual(l1.Get(2, 3), g1.Get(2, 3), 0.000001f); Assert.AreEqual(l1.Get(3, 0), g1.Get(3, 0), 0.000001f); Assert.AreEqual(l1.Get(3, 1), g1.Get(3, 1), 0.000001f); Assert.AreEqual(l1.Get(3, 2), g1.Get(3, 2), 0.000001f); Assert.AreEqual(l1.Get(3, 3), g1.Get(3, 3), 0.000001f); var m = l1 * l2; Assert.AreEqual(m.Get(0, 0), g2.Get(0, 0), 0.000001f); Assert.AreEqual(m.Get(0, 1), g2.Get(0, 1), 0.000001f); Assert.AreEqual(m.Get(0, 2), g2.Get(0, 2), 0.000001f); Assert.AreEqual(m.Get(0, 3), g2.Get(0, 3), 0.000001f); Assert.AreEqual(m.Get(1, 0), g2.Get(1, 0), 0.000001f); Assert.AreEqual(m.Get(1, 1), g2.Get(1, 1), 0.000001f); Assert.AreEqual(m.Get(1, 2), g2.Get(1, 2), 0.000001f); Assert.AreEqual(m.Get(1, 3), g2.Get(1, 3), 0.000001f); Assert.AreEqual(m.Get(2, 0), g2.Get(2, 0), 0.000001f); Assert.AreEqual(m.Get(2, 1), g2.Get(2, 1), 0.000001f); Assert.AreEqual(m.Get(2, 2), g2.Get(2, 2), 0.000001f); Assert.AreEqual(m.Get(2, 3), g2.Get(2, 3), 0.000001f); Assert.AreEqual(m.Get(3, 0), g2.Get(3, 0), 0.000001f); Assert.AreEqual(m.Get(3, 1), g2.Get(3, 1), 0.000001f); Assert.AreEqual(m.Get(3, 2), g2.Get(3, 2), 0.000001f); Assert.AreEqual(m.Get(3, 3), g2.Get(3, 3), 0.000001f); }
public void Node_CalcGlobalTransformFromCreatedState_ReturnsIdentity() { // given: var node = new FbxNode(""); var t = new FbxVector4(0, 0, 0); var r = new FbxVector4(0, 0, 0); var s = new FbxVector4(1, 1, 1); var expected = new FbxMatrix(t, r, s); // when: var actual = node.EvaluateGlobalTransform(); // then: Assert.AreEqual(expected, actual); }
public void Node_CalcGlobalTransformWithScale_ReturnsScale() { // given: var node = new FbxNode(""); var t = new FbxVector4(0, 0, 0); var r = new FbxVector4(0, 0, 0); var s = new FbxVector4(5, 6, 7); var expected = new FbxMatrix(t, r, s); node.LclScaling.Set(s); // when: var actual = node.EvaluateGlobalTransform(); // then: Assert.AreEqual(expected, actual); }
public void Node_CalcGlobalTransformWithRotation_ReturnsRotation() { // given: var node = new FbxNode(""); var t = new FbxVector4(0, 0, 0); var r = new FbxVector4(22, 33, 44); var s = new FbxVector4(1, 1, 1); var expected = new FbxMatrix(t, r, s); node.LclRotation.Set(r); // when: var actual = node.EvaluateGlobalTransform(); // then: Assert.AreEqual(expected, actual); }
/// <summary> /// Export binding of mesh to skeleton /// </summary> protected void ExportSkin(MeshInfo meshInfo, FbxScene fbxScene, FbxMesh fbxMesh, FbxNode fbxRootNode, Dictionary <Transform, FbxNode> boneNodes) { SkinnedMeshRenderer unitySkinnedMeshRenderer = meshInfo.renderer as SkinnedMeshRenderer; FbxSkin fbxSkin = FbxSkin.Create(fbxScene, (meshInfo.unityObject.name + "_Skin")); FbxAMatrix fbxMeshMatrix = fbxRootNode.EvaluateGlobalTransform(); // keep track of the bone index -> fbx cluster mapping, so that we can add the bone weights afterwards Dictionary <int, FbxCluster> boneCluster = new Dictionary <int, FbxCluster> (); for (int i = 0; i < unitySkinnedMeshRenderer.bones.Length; i++) { FbxNode fbxBoneNode = boneNodes [unitySkinnedMeshRenderer.bones[i]]; // Create the deforming cluster FbxCluster fbxCluster = FbxCluster.Create(fbxScene, "BoneWeightCluster"); fbxCluster.SetLink(fbxBoneNode); fbxCluster.SetLinkMode(FbxCluster.ELinkMode.eTotalOne); boneCluster.Add(i, fbxCluster); // set the Transform and TransformLink matrix fbxCluster.SetTransformMatrix(fbxMeshMatrix); FbxAMatrix fbxLinkMatrix = fbxBoneNode.EvaluateGlobalTransform(); fbxCluster.SetTransformLinkMatrix(fbxLinkMatrix); // add the cluster to the skin fbxSkin.AddCluster(fbxCluster); } // set the vertex weights for each bone SetVertexWeights(meshInfo, boneCluster); // Add the skin to the mesh after the clusters have been added fbxMesh.AddDeformer(fbxSkin); }
public SkeletonBone(FbxNode boneNode, SkeletonBone parentBone, FbxSkin[] skins, SceneLoader scene) { //this.scene = scene; this.scene = scene; Node = boneNode; ParentBone = parentBone; //animationTrackKeyFrames = new List<HashSet<double>>(); cluster = Skeleton.FindCluster(Node, skins, out skin); //Поиск по всем skins во всех mesh. Можно было бы сделать эффективнее. globalMeshTransform = new FbxAMatrix(); globalMeshTransform.SetIdentity(); geometryOffset = new FbxAMatrix(); geometryOffset.SetIdentity(); if (cluster != null) { FbxNode meshNode = skin.GetGeometry()?.GetNode(); if (meshNode != null) { globalMeshTransform = meshNode.EvaluateGlobalTransform(FbxExtensions.ToFbxTime(-1)); // FbxMath.GetGlobalPosition( meshNode, FbxExtensions.ToFbxTime( -1 ), null ); geometryOffset = FbxMath.GetGeometryOffset(meshNode); } } InitialTransform = GetInitialTransform().ToMatrix4(); //Во внешнем коде надо использовать это значение, т.к. результат GetInitialTransform() может зависеть от установленного AnimationTrack }