public void ApplyExternalTransform(NVector4 transform) { // Find where loop start is relative to current location var deltaCurrentToLoopStart = (LoopStartTransform - CurrentTransform); // Rotate loop start such that the current location is pivoted var newTranslation = NVector3.Transform(deltaCurrentToLoopStart.XYZ(), NMatrix.CreateRotationY(transform.W)); deltaCurrentToLoopStart.X = CurrentTransform.X + newTranslation.X + transform.X; deltaCurrentToLoopStart.Y = CurrentTransform.Y + newTranslation.Y + transform.Y; deltaCurrentToLoopStart.Z = CurrentTransform.Z + newTranslation.Z + transform.Z; deltaCurrentToLoopStart.W = LoopStartTransform.W + transform.W; LoopStartTransform = deltaCurrentToLoopStart; var tr = CurrentTransform; tr += transform; CurrentTransform = tr; tr = PreviousFrameTransform; tr += transform; PreviousFrameTransform = tr; //tr = LoopStartTransform; //tr.W += rotation; //LoopStartTransform = tr; }
public override void Draw() { shader.Use(); //Console.WriteLine(transform); if (isRotating) { Parent.getMatrix4X4() *= Matrix4x4.CreateRotationY(Time.deltaTime); } shader.SetMatrix4("model", ref Parent.getMatrix4X4()); shader.SetMatrix4("view", ref Camera.main.view); shader.SetVector3("viewPos", Camera.main.view.ExtractTranslation()); shader.SetVector3("light.lightColor", ref LevelManager.activeScene.lightSources[0].color); shader.SetMatrix4("projection", ref Camera.main.projection); shader.SetVector3("light.lightPos", LevelManager.activeScene.lightSources[0].Parent.getMatrix4X4().Translation); //Console.WriteLine(Game.light.transform.ExtractTranslation()); shader.SetFloat("material.shininess", 2); foreach (var mesh in meshes) { mesh.Draw(ref shader); } }
public static NMatrix GetNMatrix(this FLVER.Bone b) { return(NMatrix.CreateScale(b.Scale) * NMatrix.CreateRotationX(b.Rotation.X) * NMatrix.CreateRotationZ(b.Rotation.Z) * NMatrix.CreateRotationY(b.Rotation.Y) * NMatrix.CreateTranslation(b.Translation)); }
private void SetTransformToTimeWithinCurrentLoop(float localTime) { // Get sample at specified time. var sampleAtTime = SampleRootMotionData(localTime); // Rotate sample translation to be relative to loop start transform rotation. var translation = NVector3.Transform(sampleAtTime.XYZ(), NMatrix.CreateRotationY(LoopStartTransform.W)); sampleAtTime.X = translation.X; sampleAtTime.Y = translation.Y; sampleAtTime.Z = translation.Z; CurrentTransform = LoopStartTransform + sampleAtTime; }
/// <summary> /// TODO: Check if this actually works. /// </summary> private NVector4 GetLoopStartFromLoopEnd(NVector4 loopEnd) { var angleAtStart = loopEnd.W + (Data.FirstFrame.W - Data.LastFrame.W); // Find the delta from end to start var deltaStartToEnd = (Data.LastFrame - Data.FirstFrame); // Rotate delta translation by the delta from end to start var translation = NVector3.Transform(deltaStartToEnd.XYZ(), NMatrix.CreateRotationY(angleAtStart)); deltaStartToEnd.X = loopEnd.X - translation.X; deltaStartToEnd.Y = loopEnd.Y - translation.Y; deltaStartToEnd.Z = loopEnd.Z - translation.Z; deltaStartToEnd.W = angleAtStart; return(deltaStartToEnd); }
public static Scene ExportToScene(HavokAnimationData anim) { var scene = new Scene(); scene.RootNode = new Node("scene_root"); scene.RootNode.Metadata["FrameRate"] = new Metadata.Entry(MetaDataType.Int32, 14); scene.RootNode.Metadata["TimeSpanStart"] = new Metadata.Entry(MetaDataType.UInt64, (ulong)0); scene.RootNode.Metadata["TimeSpanStop"] = new Metadata.Entry(MetaDataType.UInt64, (ulong)0); scene.RootNode.Metadata["CustomFrameRate"] = new Metadata.Entry(MetaDataType.Float, 1f / anim.FrameDuration); scene.RootNode.Metadata["FrontAxisSign"] = new Metadata.Entry(MetaDataType.Int32, -1); scene.RootNode.Metadata["OriginalUnitScaleFactor"] = new Metadata.Entry(MetaDataType.Int32, 100); scene.RootNode.Metadata["UnitScaleFactor"] = new Metadata.Entry(MetaDataType.Int32, 100); var a = new Assimp.Animation(); a.DurationInTicks = anim.Duration * 30; a.TicksPerSecond = 30; a.Name = anim.Name; List <Node> animTrackNodes = new List <Node>(); for (int i = 0; i < anim.TransformTrackIndexToHkxBoneMap.Length; i++) { int boneIndex = anim.TransformTrackIndexToHkxBoneMap[i]; if (boneIndex < 0 || boneIndex > anim.hkaSkeleton.Bones.Capacity) { continue; } string trackName = anim.hkaSkeleton.Bones[boneIndex].Name.GetString(); var animTrack = new NodeAnimationChannel(); animTrack.NodeName = trackName; for (int f = 0; f < anim.FrameCount; f++) { var t = anim.GetTransformOnFrame(i, f, enableLooping: false); animTrack.PositionKeys.Add(new VectorKey(1.0 * f * anim.FrameDuration, new Vector3D(t.Translation.X * -100, t.Translation.Y * 100, t.Translation.Z * 100))); animTrack.ScalingKeys.Add(new VectorKey(1.0 * f * anim.FrameDuration, new Vector3D(t.Scale.X, t.Scale.Y, t.Scale.Z))); var q = t.Rotation; //q.X *= -1; //q.Y *= -1; //q.Z *= -1; //q.W *= -1; q = SapMath.MirrorQuat(q); //q.X *= -1; //q.Y *= -1; //q.Z *= -1; //q.W *= -1; animTrack.RotationKeys.Add(new QuaternionKey(1.0 * f * anim.FrameDuration, new Quaternion(q.W, q.X, q.Y, q.Z))); } a.NodeAnimationChannels.Add(animTrack); var fakeNode = new Node(trackName); animTrackNodes.Add(fakeNode); } List <Node> topLevelTrackNodes = new List <Node>(); for (int i = 0; i < animTrackNodes.Count; i++) { var hkxBoneIndex = anim.TransformTrackIndexToHkxBoneMap[i]; var parentBoneIndex = anim.hkaSkeleton.ParentIndices[hkxBoneIndex].data; if (parentBoneIndex >= 0) { var parentTrackIndex = anim.HkxBoneIndexToTransformTrackMap[parentBoneIndex]; if (parentTrackIndex >= 0) { animTrackNodes[parentTrackIndex].Children.Add(animTrackNodes[i]); } } else { topLevelTrackNodes.Add(animTrackNodes[i]); } } var actualRootNode = new Node("root"); if (anim.RootMotion != null) { var animTrack = new NodeAnimationChannel(); animTrack.NodeName = actualRootNode.Name; for (int f = 0; f < anim.FrameCount; f++) { var rootMotionOnFrame = anim.RootMotion.GetSampleClamped(f * anim.FrameDuration); animTrack.PositionKeys.Add(new VectorKey(1.0 * f * anim.FrameDuration, new Vector3D(rootMotionOnFrame.X * -100, rootMotionOnFrame.Y * 100, rootMotionOnFrame.Z * 100))); var q = NQuaternion.CreateFromRotationMatrix(NMatrix.CreateRotationY(rootMotionOnFrame.W)); animTrack.RotationKeys.Add(new QuaternionKey(1.0 * f * anim.FrameDuration, new Quaternion(q.W, q.X, q.Y, q.Z))); } a.NodeAnimationChannels.Add(animTrack); } foreach (var t in topLevelTrackNodes) { actualRootNode.Children.Add(t); } scene.RootNode.Children.Add(actualRootNode); scene.Animations.Add(a); return(scene); }
public static ImportedAnimation ImportFromAssimpScene(Scene scene, AnimationImportSettings settings) { ImportedAnimation result = new ImportedAnimation(); var sceneMatrix = NMatrix.Identity; if (!settings.FlipQuaternionHandedness) { sceneMatrix *= NMatrix.CreateScale(-1, 1, 1); } if (settings.ExistingHavokAnimationTemplate == null) { throw new NotImplementedException("Reading skeleton/binding from assimp scene not supported yet. Please import using existing havok animation as template."); } else { result.hkaSkeleton = settings.ExistingHavokAnimationTemplate.hkaSkeleton; result.HkxBoneIndexToTransformTrackMap = settings.ExistingHavokAnimationTemplate.HkxBoneIndexToTransformTrackMap; result.TransformTrackIndexToHkxBoneMap = settings.ExistingHavokAnimationTemplate.TransformTrackIndexToHkxBoneMap; } if (settings.ConvertFromZUp) { sceneMatrix *= NMatrix.CreateRotationZ((float)(Math.PI)); sceneMatrix *= NMatrix.CreateRotationX((float)(-Math.PI / 2.0)); } var sceneMatrix_ForRootMotion = NMatrix.CreateScale(NVector3.One * settings.SceneScale) * sceneMatrix; if (settings.UseRootMotionScaleOverride) { sceneMatrix_ForRootMotion = NMatrix.CreateScale(NVector3.One * settings.RootMotionScaleOverride) * sceneMatrix; } sceneMatrix = NMatrix.CreateScale(NVector3.One * settings.SceneScale) * sceneMatrix; foreach (var anim in scene.Animations) { if (anim.HasNodeAnimations) { // Setup framerate. double tickScaler = (settings.ResampleToFramerate / anim.TicksPerSecond); result.Duration = anim.DurationInTicks != 0 ? // Don't divide by 0 (float)(anim.DurationInTicks / anim.TicksPerSecond) : 0; result.FrameDuration = (float)(1 / settings.ResampleToFramerate); //result.Duration += result.FrameDuration; int frameCount = (int)Math.Round(result.Duration / result.FrameDuration); double resampleTickMult = settings.ResampleToFramerate / anim.TicksPerSecond; Dictionary <string, int> transformTrackIndexMapping = new Dictionary <string, int>(); List <string> transformTrackNames = new List <string>(); // Populate transform track names. foreach (var nodeChannel in anim.NodeAnimationChannels) { if (nodeChannel.NodeName == settings.RootMotionNodeName && settings.ExcludeRootMotionNodeFromTransformTracks) { continue; } transformTrackNames.Add(nodeChannel.NodeName); } result.TransformTrackToBoneIndices.Clear(); if (settings.ExistingBoneDefaults != null) { var boneNamesInExistingSkel = settings.ExistingBoneDefaults.Keys.ToList(); transformTrackNames = boneNamesInExistingSkel; foreach (var tt in transformTrackNames) { result.TransformTrackToBoneIndices.Add(tt, boneNamesInExistingSkel.IndexOf(tt)); } } else { int i = 0; foreach (var t in transformTrackNames) { result.TransformTrackToBoneIndices.Add(t, i++); } } // Populate transform track names. foreach (var nodeChannel in anim.NodeAnimationChannels) { //if (nodeChannel.NodeName == settings.RootMotionNodeName && settings.ExcludeRootMotionNodeFromTransformTracks) // continue; transformTrackIndexMapping.Add(nodeChannel.NodeName, transformTrackNames.IndexOf(nodeChannel.NodeName)); } result.TransformTrackNames = transformTrackNames; result.Frames = new List <ImportedAnimation.Frame>(); for (int i = 0; i <= frameCount; i++) { var f = new ImportedAnimation.Frame(); for (int j = 0; j < transformTrackNames.Count; j++) { if (settings.ExistingBoneDefaults != null && settings.ExistingBoneDefaults.ContainsKey(transformTrackNames[j]) && settings.InitalizeUnanimatedTracksToTPose) { f.BoneTransforms.Add(settings.ExistingBoneDefaults[transformTrackNames[j]]); } else { f.BoneTransforms.Add(NewBlendableTransform.Identity); } } result.Frames.Add(f); } var rootMotionRotationFrames = new NQuaternion[frameCount + 1]; //DEBUGGING var DEBUG_ALL_NODE_NAMES_SORTED = anim.NodeAnimationChannels.Select(n => n.NodeName).OrderBy(n => n).ToList(); for (int i = 0; i < anim.NodeAnimationChannelCount; i++) { var nodeChannel = anim.NodeAnimationChannels[i]; int lastKeyIndex = -1; bool hasPosition = nodeChannel.HasPositionKeys; bool hasRotation = nodeChannel.HasRotationKeys; bool hasScale = nodeChannel.HasScalingKeys; if (nodeChannel.NodeName.Contains("$AssimpFbx$_Translation")) { hasPosition = true; hasRotation = false; hasScale = false; } else if (nodeChannel.NodeName.Contains("$AssimpFbx$_Rotation")) { hasPosition = false; hasRotation = true; hasScale = false; } else if (nodeChannel.NodeName.Contains("$AssimpFbx$_Scaling")) { hasPosition = false; hasRotation = false; hasScale = true; } bool isRootMotionNode = nodeChannel.NodeName == settings.RootMotionNodeName || (nodeChannel.NodeName.StartsWith(settings.RootMotionNodeName) && nodeChannel.NodeName.Contains("_$AssimpFbx$_")); if (isRootMotionNode) { if (hasPosition) { lastKeyIndex = -1; foreach (var keyPos in nodeChannel.PositionKeys) { int frame = (int)Math.Floor(keyPos.Time * resampleTickMult); result.Frames[frame].RootMotionTranslation = NVector3.Transform(keyPos.Value.ToNumerics(), sceneMatrix_ForRootMotion); //if (settings.FlipQuaternionHandedness) //{ // result.Frames[frame].RootMotionTranslation.X *= -1; //} // Fill in from the last keyframe to this one for (int f = lastKeyIndex + 1; f <= Math.Min(frame - 1, result.Frames.Count - 1); f++) { float lerpS = 1f * (f - lastKeyIndex) / (frame - lastKeyIndex); var blendFrom = result.Frames[lastKeyIndex].RootMotionTranslation; var blendTo = result.Frames[frame].RootMotionTranslation; result.Frames[f].RootMotionTranslation = NVector3.Lerp(blendFrom, blendTo, lerpS); } lastKeyIndex = frame; } // Fill in from last key to end of animation. for (int f = lastKeyIndex + 1; f <= result.Frames.Count - 1; f++) { result.Frames[f].RootMotionTranslation = result.Frames[lastKeyIndex].RootMotionTranslation; } } if (hasRotation && settings.EnableRotationalRootMotion) { lastKeyIndex = -1; foreach (var keyPos in nodeChannel.RotationKeys) { int frame = (int)Math.Floor(keyPos.Time * resampleTickMult); var curFrameRotation = keyPos.Value.ToNumerics(); curFrameRotation.Y *= -1; curFrameRotation.Z *= -1; if (settings.FlipQuaternionHandedness) { curFrameRotation = SapMath.MirrorQuat(curFrameRotation); } if (frame >= 0 && frame < frameCount) { rootMotionRotationFrames[frame] = curFrameRotation; } // Fill in from the last keyframe to this one for (int f = lastKeyIndex + 1; f <= Math.Min(frame - 1, result.Frames.Count - 1); f++) { float lerpS = 1f * (f - lastKeyIndex) / (frame - lastKeyIndex); var blendFrom = rootMotionRotationFrames[lastKeyIndex]; var blendTo = curFrameRotation; var blended = NQuaternion.Slerp(blendFrom, blendTo, lerpS); //blended = NQuaternion.Normalize(blended); rootMotionRotationFrames[f] = blended; } lastKeyIndex = frame; } // Fill in from last key to end of animation. for (int f = lastKeyIndex + 1; f <= result.Frames.Count - 1; f++) { rootMotionRotationFrames[f] = rootMotionRotationFrames[lastKeyIndex]; } } } if (isRootMotionNode) { hasPosition = false; hasRotation = !settings.EnableRotationalRootMotion; } if (!(isRootMotionNode && !settings.ExcludeRootMotionNodeFromTransformTracks)) { string nodeName = nodeChannel.NodeName; int transformIndex = transformTrackIndexMapping[nodeName]; int memeIndex = nodeName.IndexOf("_$AssimpFbx$_"); if (memeIndex >= 0) { nodeName = nodeName.Substring(0, memeIndex); } if (transformIndex >= 0 && transformIndex < transformTrackNames.Count) { // TRANSLATION if (hasPosition) { lastKeyIndex = -1; foreach (var keyPos in nodeChannel.PositionKeys) { int frame = (int)Math.Floor(keyPos.Time * resampleTickMult); var curFrameTransform = result.Frames[frame].BoneTransforms[transformIndex]; curFrameTransform.Translation = NVector3.Transform(keyPos.Value.ToNumerics(), sceneMatrix); result.Frames[frame].BoneTransforms[transformIndex] = curFrameTransform; // Fill in from the last keyframe to this one for (int f = lastKeyIndex + 1; f <= Math.Min(frame - 1, result.Frames.Count - 1); f++) { float lerpS = 1f * (f - lastKeyIndex) / (frame - lastKeyIndex); var blendFrom = result.Frames[lastKeyIndex].BoneTransforms[transformIndex].Translation; var blendTo = curFrameTransform.Translation; var blended = NVector3.Lerp(blendFrom, blendTo, lerpS); var copyOfStruct = result.Frames[f].BoneTransforms[transformIndex]; copyOfStruct.Translation = blended; result.Frames[f].BoneTransforms[transformIndex] = copyOfStruct; } lastKeyIndex = frame; } // Fill in from last key to end of animation. for (int f = lastKeyIndex + 1; f <= result.Frames.Count - 1; f++) { var x = result.Frames[f].BoneTransforms[transformIndex]; x.Translation = result.Frames[lastKeyIndex].BoneTransforms[transformIndex].Translation; result.Frames[f].BoneTransforms[transformIndex] = x; } } // SCALE if (hasScale) { lastKeyIndex = -1; foreach (var keyPos in nodeChannel.ScalingKeys) { int frame = (int)Math.Floor(keyPos.Time * resampleTickMult); var curFrameTransform = result.Frames[frame].BoneTransforms[transformIndex]; curFrameTransform.Scale = keyPos.Value.ToNumerics(); result.Frames[frame].BoneTransforms[transformIndex] = curFrameTransform; // Fill in from the last keyframe to this one for (int f = lastKeyIndex + 1; f <= Math.Min(frame - 1, result.Frames.Count - 1); f++) { float lerpS = 1f * (f - lastKeyIndex) / (frame - lastKeyIndex); var blendFrom = result.Frames[lastKeyIndex].BoneTransforms[transformIndex].Scale; var blendTo = curFrameTransform.Scale; var blended = NVector3.Lerp(blendFrom, blendTo, lerpS); var copyOfStruct = result.Frames[f].BoneTransforms[transformIndex]; copyOfStruct.Scale = blended; result.Frames[f].BoneTransforms[transformIndex] = copyOfStruct; } lastKeyIndex = frame; } // Fill in from last key to end of animation. for (int f = lastKeyIndex + 1; f <= result.Frames.Count - 1; f++) { var x = result.Frames[f].BoneTransforms[transformIndex]; x.Scale = result.Frames[lastKeyIndex].BoneTransforms[transformIndex].Scale; result.Frames[f].BoneTransforms[transformIndex] = x; } } // ROTATION if (hasRotation) { lastKeyIndex = -1; foreach (var keyPos in nodeChannel.RotationKeys) { int frame = (int)Math.Floor(keyPos.Time * resampleTickMult); var curFrameTransform = result.Frames[frame].BoneTransforms[transformIndex]; curFrameTransform.Rotation = keyPos.Value.ToNumerics(); curFrameTransform.Rotation.Y *= -1; curFrameTransform.Rotation.Z *= -1; if (settings.FlipQuaternionHandedness) { curFrameTransform.Rotation = SapMath.MirrorQuat(curFrameTransform.Rotation); } result.Frames[frame].BoneTransforms[transformIndex] = curFrameTransform; // Fill in from the last keyframe to this one for (int f = lastKeyIndex + 1; f <= Math.Min(frame - 1, result.Frames.Count - 1); f++) { float lerpS = 1f * (f - lastKeyIndex) / (frame - lastKeyIndex); var blendFrom = result.Frames[lastKeyIndex].BoneTransforms[transformIndex].Rotation; var blendTo = curFrameTransform.Rotation; var blended = NQuaternion.Slerp(blendFrom, blendTo, lerpS); //blended = NQuaternion.Normalize(blended); var copyOfStruct = result.Frames[f].BoneTransforms[transformIndex]; copyOfStruct.Rotation = blended; result.Frames[f].BoneTransforms[transformIndex] = copyOfStruct; } lastKeyIndex = frame; } // Fill in from last key to end of animation. for (int f = lastKeyIndex + 1; f <= result.Frames.Count - 1; f++) { var x = result.Frames[f].BoneTransforms[transformIndex]; x.Rotation = result.Frames[lastKeyIndex].BoneTransforms[transformIndex].Rotation; result.Frames[f].BoneTransforms[transformIndex] = x; } } } else { Console.WriteLine("unmapped transform track."); } } } if (settings.BonesToFlipBackwardsAboutYAxis.Count > 0) { var trackIndicesToFlip = result.TransformTrackNames .Select((x, i) => i) .Where(x => settings.BonesToFlipBackwardsAboutYAxis.Contains(result.TransformTrackNames[x])) .ToList(); foreach (var f in result.Frames) { foreach (var i in trackIndicesToFlip) { var t = f.BoneTransforms[i]; t.Rotation = NQuaternion.CreateFromRotationMatrix(NMatrix.CreateFromQuaternion(f.BoneTransforms[i].Rotation) * NMatrix.CreateRotationY(SapMath.Pi)); t.Translation = NVector3.Transform(t.Translation, NMatrix.CreateRotationY(SapMath.Pi)); f.BoneTransforms[i] = t; } } } result.FrameCount = frameCount; result.Name = anim.Name ?? settings.ExistingHavokAnimationTemplate?.Name ?? "SAP Custom Animation"; float rootMotionRot = 0; for (int f = 0; f < result.Frames.Count; f++) { if (f > 0 && settings.EnableRotationalRootMotion) { var curMat = NMatrix.CreateFromQuaternion(rootMotionRotationFrames[f]); var oldMat = NMatrix.CreateFromQuaternion(rootMotionRotationFrames[f - 1]); if (NMatrix.Invert(oldMat, out NMatrix inverseOldMat)) { var deltaMat = curMat * inverseOldMat; var deltaVec = NVector3.Transform(NVector3.UnitX, deltaMat); float deltaAngle = (float)Math.Atan2(deltaVec.Z, deltaVec.X); rootMotionRot += deltaAngle; } } result.Frames[f].RootMotionRotation = rootMotionRot; } break; } } result.RootMotion = new RootMotionData( new NVector4(0, 1, 0, 0), new NVector4(0, 0, 1, 0), result.Duration, result.Frames.Select(f => f.RootMotion).ToArray()); // Copy first frame for loop? //for (int i = 0; i < result.TransformTrackNames.Count; i++) //{ // result.Frames[result.Frames.Count - 1].BoneTransforms[i] = result.Frames[0].BoneTransforms[i]; //} var rootMotionStart = result.Frames[0].RootMotion; for (int i = 0; i < result.Frames.Count; i++) { result.Frames[i].RootMotionTranslation.X -= rootMotionStart.X; result.Frames[i].RootMotionTranslation.Y -= rootMotionStart.Y; result.Frames[i].RootMotionTranslation.Z -= rootMotionStart.Z; result.Frames[i].RootMotionRotation -= rootMotionStart.W; var xyz = NVector3.Transform(result.Frames[i].RootMotion.XYZ(), NMatrix.CreateRotationY(-rootMotionStart.W)); result.Frames[i].RootMotionTranslation.X = xyz.X; result.Frames[i].RootMotionTranslation.Y = xyz.Y; result.Frames[i].RootMotionTranslation.Z = xyz.Z; //for (int t = 0; t < result.Frames[i].BoneTransforms.Count; t++) //{ // if (i > 0 && NQuaternion.Dot(result.Frames[i - 1].BoneTransforms[t].Rotation, result.Frames[i].BoneTransforms[t].Rotation) < 0.995) // { // var tf = result.Frames[i].BoneTransforms[t]; // tf.Rotation = NQuaternion.Conjugate(result.Frames[i].BoneTransforms[t].Rotation); // result.Frames[i].BoneTransforms[t] = tf; // } //} } // HOTFIX FOR BAD FBX if (result.Frames.Count >= 3) { result.Frames[result.Frames.Count - 1].RootMotionRotation = result.Frames[result.Frames.Count - 2].RootMotionRotation + (result.Frames[result.Frames.Count - 2].RootMotionRotation - result.Frames[result.Frames.Count - 3].RootMotionRotation); } //var endFrame = new ImportedAnimation.Frame(); //foreach (var t in result.Frames[0].BoneTransforms) //{ // endFrame.BoneTransforms.Add(t); //} //endFrame.RootMotionTranslation = result.Frames[result.Frames.Count - 1].RootMotionTranslation + // (result.Frames[result.Frames.Count - 1].RootMotionTranslation - result.Frames[result.Frames.Count - 2].RootMotionTranslation); //endFrame.RootMotionRotation = result.Frames[result.Frames.Count - 1].RootMotionRotation + // (result.Frames[result.Frames.Count - 1].RootMotionRotation - result.Frames[result.Frames.Count - 2].RootMotionRotation); ////endFrame.RootMotionRotation = result.Frames[result.Frames.Count - 1].RootMotionRotation; //result.Frames.Add(endFrame); return(result); }
public static FLVERMetaskeleton GenerateFlverMetaskeletonFromRootNode( Node rootNode, Matrix4x4 rootNodeAbsoluteMatrix, float importScale) { var bonesAssimp = new List <Node>(); var skel = new FLVERMetaskeleton(); var dummyAttachBoneNames = new List <string>(); NMatrix matrixScale = NMatrix.CreateScale(importScale, importScale, importScale); // Returns index of bone in master bone list if boneNode is a bone. // Returns -1 if boneNode is a DummyPoly (denoted with a node name starting with "DUMMY_POLY"). int AddBone(Node boneNode, Node parentBoneNode, Matrix4x4 parentAbsoluteMatrix) { short parentBoneIndex = (short)(bonesAssimp.IndexOf(parentBoneNode)); var thisBoneMatrix = boneNode.Transform; var thisNodeAbsoluteMatrix = thisBoneMatrix * parentAbsoluteMatrix; var boneTrans = FLVERBoneTransform.FromMatrix4x4( (parentBoneIndex == -1 ? thisNodeAbsoluteMatrix : thisBoneMatrix), true); if (boneNode.Name.StartsWith("DUMMY_POLY")) { // TODO thisNodeAbsoluteMatrix.Decompose(out Vector3D dummyScale, out Quaternion dummyQuat, out Vector3D dummyTranslation); var dmy = new FLVER.Dummy(); dmy.ParentBoneIndex = parentBoneIndex; dmy.Position = dummyTranslation.ToNumerics(); // Format: "DUMMY_POLY|<RefID>|<AttachBoneName>" // Example: "DUMMY_POLY|220|Spine1" string[] dummyNameParts = boneNode.Name.Split('|'); //ErrorTODO: TryParse dmy.ReferenceID = short.Parse(dummyNameParts[1].Trim()); if (dummyNameParts.Length == 3) { dummyAttachBoneNames.Add(dummyNameParts[2]); } else { dummyAttachBoneNames.Add(null); } //NOTE: Maybe this should be specifiable? I forget what the point of false is here. dmy.UseUpwardVector = true; var sceneRotation = NMatrix.CreateRotationX(boneTrans.Rotation.X) * NMatrix.CreateRotationZ(boneTrans.Rotation.Z) * NMatrix.CreateRotationY(boneTrans.Rotation.Y); dmy.Upward = NVector3.Transform(new NVector3(0, 1, 0), sceneRotation); //TODO: Check if forward vector3 should be 1 or -1; dmy.Forward = NVector3.Transform(new NVector3(0, 0, 1), sceneRotation); skel.DummyPoly.Add(dmy); return(-1); } else { bonesAssimp.Add(boneNode); int thisBoneIndex = bonesAssimp.Count - 1; var flverBone = new FLVER.Bone(); if (parentBoneNode != null) { flverBone.ParentIndex = parentBoneIndex; } flverBone.Name = boneNode.Name; flverBone.BoundingBoxMin = new NVector3(float.MaxValue, float.MaxValue, float.MaxValue); flverBone.BoundingBoxMax = new NVector3(float.MinValue, float.MinValue, float.MinValue); flverBone.Translation = boneTrans.Translation * importScale; flverBone.Rotation = boneTrans.Rotation; flverBone.Scale = boneTrans.Scale; skel.Bones.Add(flverBone); List <int> childBoneIndices = new List <int>(); foreach (var c in boneNode.Children) { int cIndex = AddBone(c, boneNode, thisNodeAbsoluteMatrix); //cIndex will be -1 if the child node was a DummyPoly instead of a bone. if (cIndex >= 0) { childBoneIndices.Add(cIndex); } } if (childBoneIndices.Count > 0) { flverBone.ChildIndex = (short)childBoneIndices[0]; for (int i = 0; i < childBoneIndices.Count; i++) { var thisChildBone = skel.Bones[childBoneIndices[i]]; if (i == 0) { thisChildBone.PreviousSiblingIndex = -1; } else { thisChildBone.PreviousSiblingIndex = (short)(childBoneIndices[i - 1]); } if (i == childBoneIndices.Count - 1) { thisChildBone.NextSiblingIndex = -1; } else { thisChildBone.NextSiblingIndex = (short)(childBoneIndices[i + 1]); } } } return(thisBoneIndex); } } //if (rootNode.Children == null) // throw new InvalidDataException("Assimp scene has no heirarchy."); var root = rootNode; //var master = root.Children[0]; //foreach (var c in root.Children) //{ // AddBone(c, null, root.Transform * rootNodeAbsoluteMatrix); //} AddBone(root, null, rootNodeAbsoluteMatrix); // Apply parent bone transforms to DummyPoly foreach (var d in skel.DummyPoly) { if (d.ParentBoneIndex >= 0) { var parentMat = skel.Bones[d.ParentBoneIndex].GetAbsoluteNMatrix(skel.Bones); d.Position = NVector3.Transform(d.Position, parentMat); d.Upward = NVector3.TransformNormal(d.Upward, parentMat); d.Forward = NVector3.TransformNormal(d.Forward, parentMat); } } return(skel); }