protected FbxNode CreateSkeleton(FbxScene scene) { FbxSkeleton skelRoot = FbxSkeleton.Create(scene, "SkelRoot"); skelRoot.SetSkeletonType(FbxSkeleton.EType.eRoot); FbxNode skelRootNode = FbxNode.Create(scene, "SkelRootNode"); skelRootNode.SetNodeAttribute(skelRoot); skelRootNode.LclTranslation.Set(new FbxDouble3(0.0, -40.0, 0.0)); // create skeleton limb nodes FbxSkeleton skelLimb1 = FbxSkeleton.Create(scene, "SkelLimb1"); skelLimb1.SetSkeletonType(FbxSkeleton.EType.eLimbNode); skelLimb1.Size.Set(1.5); FbxNode skelLimbNode1 = FbxNode.Create(scene, "SkelLimbNode1"); skelLimbNode1.SetNodeAttribute(skelLimb1); skelLimbNode1.LclTranslation.Set(new FbxDouble3(0.0, 40.0, 0.0)); FbxSkeleton skelLimb2 = FbxSkeleton.Create(scene, "SkelLimb2"); skelLimb2.SetSkeletonType(FbxSkeleton.EType.eLimbNode); skelLimb2.Size.Set(1.5); FbxNode skelLimbNode2 = FbxNode.Create(scene, "SkelLimbNode2"); skelLimbNode2.SetNodeAttribute(skelLimb2); skelLimbNode2.LclTranslation.Set(new FbxDouble3(0.0, 40.0, 0.0)); // build skeleton hierarchy skelRootNode.AddChild(skelLimbNode1); skelLimbNode1.AddChild(skelLimbNode2); return(skelRootNode); }
public DsBoneData(DsBone bone, FLVER.Bone flverBone, FbxScene scene) { FbxSkeleton fbxBone = FbxSkeleton.Create(scene, bone.Name + "Bone"); fbxBone.SetSkeletonType(flverBone.ChildIndex >= 0 ? FbxSkeleton.EType.eLimbNode : FbxSkeleton.EType.eEffector); fbxBone.Size.Set(flverBone.Translation.Length()); exportData = fbxBone.CreateExportDataWithScene(bone, scene); this.flverBone = flverBone; }
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> /// 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); }
/// <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); }