public static FbxDouble3 XYZEulerFromQuaternion(Quaternion rotation) { // Unity wrappers don't have FbxVector4::SetXYZ(FbxQuaternion) to convert quat -> xyz euler. // We can abuse FbxAMatrix to do the same thing. FbxQuaternion fbxQuaternion = new FbxQuaternion(rotation.x, rotation.y, rotation.z, rotation.w); // We're using the FBX API to do the conversion to XYZ eulers. var mat = new FbxAMatrix(); mat.SetIdentity(); mat.SetQ(fbxQuaternion); // "The returned rotation vector is in Euler angle and the rotation order is XYZ." FbxVector4 v4 = mat.GetR(); return(new FbxDouble3(v4.X, v4.Y, v4.Z)); }
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 }
//Calculates global transform of the node. //This function was taken from FBX SDK/Smaples/Transformations. Originaly it did not take into account AxisSystem, so the corrections to use AxisSystem was added. //Has the fbx sdk equivalent pNode.EvaluateGlobalTransform(); // //Note: FBX Documentation for ConvertScene states - "The adjustment will affect the translation animation curves and the objects pivots values //(the rotation transformation is applied as a pre-rotation transform therefore the rotation animation curves do not need to be transformed)" //But ConvertScene, does not realy change node.PreRotation, these changes are in the matrix : node.GetScene().GetGlobalSettings().GetAxisSystem().GetMatrix // /* * Terminology: * Suffix "M" means this is a matrix, suffix "V" means it is a vector. * T is translation. * R is rotation. * S is scaling. * SH is shear. * GlobalRM(x) means the Global Rotation Matrix of node "x". * GlobalRM(P(x)) means the Global Rotation Matrix of the parent node of node "x". * All other transforms are described in the similar way. * * The algorithm description: * To calculate global transform of a node x according to different InheritType, * we need to calculate GlobalTM(x) and [GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x))] separately. * GlobalM(x) = GlobalTM(x) * [GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x))]; * * InhereitType = RrSs: * GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x)) = GlobalRM(P(x)) * LocalRM(x) * [GlobalSHM(P(x)) * GlobalSM(P(x))] * LocalSM(x); * * InhereitType = RSrs: * GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x)) = GlobalRM(P(x)) * [GlobalSHM(P(x)) * GlobalSM(P(x))] * LocalRM(x) * LocalSM(x); * * InhereitType = Rrs: * GlobalRM(x) * (GlobalSHM(x) * GlobalSM(x)) = GlobalRM(P(x)) * LocalRM(x) * LocalSM(x); * * LocalM(x)= TM(x) * RoffsetM(x) * RpivotM(x) * RpreM(x) * RM(x) * RpostM(x) * RpivotM(x)^-1 * SoffsetM(x) *SpivotM(x) * SM(x) * SpivotM(x)^-1 * LocalTWithAllPivotAndOffsetInformationV(x) = Local(x).GetT(); * GlobalTV(x) = GlobalM(P(x)) * LocalTWithAllPivotAndOffsetInformationV(x); * * Notice: FBX SDK does not support shear yet, so all local transform won't have shear. * However, global transform might bring in shear by combine the global transform of node in higher hierarchy. * For example, if you scale the parent by a non-uniform scale and then rotate the child node, then a shear will * be generated on the child node's global transform. * In this case, we always compensates shear and store it in the scale matrix too according to following formula: * Shear*Scaling = RotationMatrix.Inverse * TranslationMatrix.Inverse * WholeTranformMatrix */ // ReSharper disable InconsistentNaming static FbxAMatrix CalculateGlobalTransform(FbxNode node) { if (node == null) { var ret = new FbxAMatrix(); ret.SetIdentity(); return(ret); } var lTranlationM = new FbxAMatrix(); var lScalingM = new FbxAMatrix(); var lScalingPivotM = new FbxAMatrix(); var lScalingOffsetM = new FbxAMatrix(); var lRotationOffsetM = new FbxAMatrix(); var lRotationPivotM = new FbxAMatrix(); var lPreRotationM = new FbxAMatrix(); var lRotationM = new FbxAMatrix(); var lPostRotationM = new FbxAMatrix(); FbxAMatrix lParentGX = new FbxAMatrix(); FbxAMatrix lGlobalT = new FbxAMatrix(); FbxAMatrix lGlobalRS = new FbxAMatrix(); // Construct translation matrix FbxVector4 lTranslation = new FbxVector4(node.LclTranslation.Get()); //The fourth component of this object is assigned 1. lTranlationM.SetT(lTranslation); // Construct rotation matrices FbxVector4 lRotation = new FbxVector4(node.LclRotation.Get()); FbxVector4 lPreRotation = new FbxVector4(node.PreRotation.Get()); FbxVector4 lPostRotation = new FbxVector4(node.PostRotation.Get()); lRotationM.SetR(lRotation); lPreRotationM.SetR(lPreRotation); lPostRotationM.SetR(lPostRotation); // Construct scaling matrix FbxVector4 lScaling = new FbxVector4(node.LclScaling.Get()); lScalingM.SetS(lScaling); // Construct offset and pivot matrices FbxVector4 lScalingOffset = new FbxVector4(node.ScalingOffset.Get()); FbxVector4 lScalingPivot = new FbxVector4(node.ScalingPivot.Get()); FbxVector4 lRotationOffset = new FbxVector4(node.RotationOffset.Get()); FbxVector4 lRotationPivot = new FbxVector4(node.RotationPivot.Get()); lScalingOffsetM.SetT(lScalingOffset); lScalingPivotM.SetT(lScalingPivot); lRotationOffsetM.SetT(lRotationOffset); lRotationPivotM.SetT(lRotationPivot); // Calculate the global transform matrix of the parent node FbxNode lParentNode = node.GetParent(); if (lParentNode != null) { //Children of the root node must take into account the axis matrix. //Warning: this function CalculateGlobalTransform was taken from FBX SDK/Smaples/Transformations. Originaly it did not take into account AxisSystem if (lParentNode.GetParent() == null) { FbxAMatrix axisMarix = new FbxAMatrix(); node.GetScene().GetGlobalSettings().GetAxisSystem().GetMatrix(axisMarix); lPreRotationM = axisMarix.mul(lPreRotationM); } lParentGX = CalculateGlobalTransform(lParentNode); } else { lParentGX.SetIdentity(); } //Construct Global Rotation FbxAMatrix lParentGRM = new FbxAMatrix(); FbxVector4 lParentGR = lParentGX.GetR(); lParentGRM.SetR(lParentGR); var lLRM = lPreRotationM.mul(lRotationM).mul(lPostRotationM); //Construct Global Shear*Scaling //FBX SDK does not support shear, to patch this, we use: //Shear*Scaling = RotationMatrix.Inverse * TranslationMatrix.Inverse * WholeTranformMatrix FbxAMatrix lParentTM = new FbxAMatrix(); FbxVector4 lParentGT = lParentGX.GetT(); lParentTM.SetT(lParentGT); var lParentGRSM = lParentTM.Inverse().mul(lParentGX); var lParentGSM = lParentGRM.Inverse().mul(lParentGRSM); var lLSM = lScalingM; //Do not consider translation now FbxTransform.EInheritType lInheritType = node.InheritType.Get(); if (lInheritType == FbxTransform.EInheritType.eInheritRrSs) { lGlobalRS = lParentGRM.mul(lLRM).mul(lParentGSM).mul(lLSM); } else if (lInheritType == FbxTransform.EInheritType.eInheritRSrs) { lGlobalRS = lParentGRM.mul(lParentGSM).mul(lLRM).mul(lLSM); } else if (lInheritType == FbxTransform.EInheritType.eInheritRrs) { if (lParentNode != null) { FbxAMatrix lParentLSM = new FbxAMatrix(); FbxVector4 lParentLS = new FbxVector4(lParentNode.LclScaling.Get()); lParentLSM.SetS(lParentLS); FbxAMatrix lParentGSM_noLocal = lParentGSM.mul(lParentLSM.Inverse()); lGlobalRS = lParentGRM.mul(lLRM).mul(lParentGSM_noLocal).mul(lLSM); } else { lGlobalRS = lParentGRM.mul(lLRM).mul(lLSM); } } else { FbxImportLog.LogError(node, "error, unknown inherit type!"); } // Construct translation matrix // Calculate the local transform matrix var lTransform = lTranlationM.mul(lRotationOffsetM).mul(lRotationPivotM).mul(lPreRotationM).mul(lRotationM).mul(lPostRotationM) .mul(lRotationPivotM.Inverse()).mul(lScalingOffsetM).mul(lScalingPivotM).mul(lScalingM).mul(lScalingPivotM.Inverse()); FbxVector4 lLocalTWithAllPivotAndOffsetInfo = lTransform.GetT(); // Calculate global translation vector according to: // GlobalTranslation = ParentGlobalTransform * LocalTranslationWithPivotAndOffsetInfo FbxVector4 lGlobalTranslation = lParentGX.MultT(lLocalTWithAllPivotAndOffsetInfo); lGlobalT.SetT(lGlobalTranslation); //Construct the whole global transform lTransform = lGlobalT.mul(lGlobalRS); return(lTransform); }