Skip to content

Commit

Permalink
Merge pull request #1013 from Soraiko/master
Browse files Browse the repository at this point in the history
Update of FBX Exporter (See details)
  • Loading branch information
kenjiuno authored Apr 12, 2024
2 parents 41e21ff + 1e3446d commit 6bab378
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 59 deletions.
61 changes: 12 additions & 49 deletions OpenKh.AssimpUtils/Kh2MdlxAssimp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using OpenKh.Kh2.Models;
using OpenKh.Kh2.Models.VIF;
using System.Numerics;
using OpenKh.Engine.Monogame.Helpers;

namespace OpenKh.AssimpUtils
{
Expand All @@ -16,15 +17,7 @@ public static Assimp.Scene getAssimpScene(MdlxParser mParser)
Assimp.Scene scene = AssimpGeneric.GetBaseScene();

// Divide the model in a mesh per texture and each mesh in its meshDescriptors
Dictionary<int, List<MeshDescriptor>> dic_meshDescriptorsByMeshId = new Dictionary<int, List<MeshDescriptor>>();
foreach (MeshDescriptor meshDesc in mParser.MeshDescriptors)
{
if (!dic_meshDescriptorsByMeshId.ContainsKey(meshDesc.TextureIndex))
{
dic_meshDescriptorsByMeshId.Add(meshDesc.TextureIndex, new List<MeshDescriptor>());
}
dic_meshDescriptorsByMeshId[meshDesc.TextureIndex].Add(meshDesc);
}
Dictionary<int, List<MeshDescriptor>> dic_meshDescriptorsByMeshId = Kh2MdlxAssimp.getMeshDescriptos(mParser);

// MESHES AND THEIR DATA
for (int i = 0; i < dic_meshDescriptorsByMeshId.Keys.Count; i++)
Expand Down Expand Up @@ -59,6 +52,7 @@ public static Assimp.Scene getAssimpScene(MdlxParser mParser)
scene.RootNode.Children.Add(iMeshNode);
}

mParser.skinnedBones = new bool[mParser.Bones.Count];
// VERTICES
for (int i = 0; i < dic_meshDescriptorsByMeshId.Keys.Count; i++)
{
Expand All @@ -76,6 +70,7 @@ public static Assimp.Scene getAssimpScene(MdlxParser mParser)
foreach (var boneAssign in boneAssigns)
{
Assimp.Bone bone = AssimpGeneric.FindBone(iMesh.Bones, "Bone" + boneAssign.MatrixIndex);
mParser.skinnedBones[boneAssign.MatrixIndex] = true;
bone.VertexWeights.Add(new Assimp.VertexWeight(currentVertex, boneAssign.Weight));
}

Expand Down Expand Up @@ -125,7 +120,7 @@ public static Assimp.Scene getAssimpScene(MdlxParser mParser)
parentNode.Children.Add(boneNode);
}

ComputeMatrices(ref matricesToReverse, mParser);
MatrixRecursivity.ComputeMatrices(ref matricesToReverse, mParser);

foreach (Assimp.Mesh mesh in scene.Meshes)
{
Expand All @@ -138,50 +133,18 @@ public static Assimp.Scene getAssimpScene(MdlxParser mParser)
return scene;
}

public static void ReverseMatrices(ref List<Microsoft.Xna.Framework.Matrix> matrices, MdlxParser mParser)
{
bool[] treatedMatrices = new bool[mParser.Bones.Count];

int dirtyCount;
do
{
dirtyCount = mParser.Bones.Count;
for (int b = 0; b < mParser.Bones.Count; b++)
{
if (treatedMatrices[b] == false)
{
int remainingToTreat = 0;
for (int j = 0; j < mParser.Bones.Count; j++)
{
if (mParser.Bones[j].Parent == b && treatedMatrices[j] == false)
remainingToTreat++;
}
if (remainingToTreat == 0) /* Children's children are all calculated. */
{
if (mParser.Bones[b].Parent > -1)
{
matrices[b] *= Microsoft.Xna.Framework.Matrix.Invert(matrices[mParser.Bones[b].Parent]);
}
treatedMatrices[b] = true;
dirtyCount--;
}
}
else
dirtyCount--;
}
}
while (dirtyCount > 0);
}

public static void ComputeMatrices(ref List<Microsoft.Xna.Framework.Matrix> matrices, MdlxParser mParser)
public static Dictionary<int, List<MeshDescriptor>> getMeshDescriptos(MdlxParser mParser)
{
for (int b = 0; b < mParser.Bones.Count; b++)
var output = new Dictionary<int, List<MeshDescriptor>>();
foreach (MeshDescriptor meshDesc in mParser.MeshDescriptors)
{
if (mParser.Bones[b].Parent > -1)
if (!output.ContainsKey(meshDesc.TextureIndex))
{
matrices[b] *= matrices[mParser.Bones[b].Parent];
output.Add(meshDesc.TextureIndex, new List<MeshDescriptor>());
}
output[meshDesc.TextureIndex].Add(meshDesc);
}
return output;
}

public static Assimp.Scene getAssimpScene(ModelSkeletal model)
Expand Down
92 changes: 92 additions & 0 deletions OpenKh.Engine.MonoGame/Helpers/MatrixRecursivity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using OpenKh.Engine.Parsers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenKh;
using System.Numerics;

namespace OpenKh.Engine.Monogame.Helpers
{
public class MatrixRecursivity
{
public static void ReverseMatrices(ref List<Microsoft.Xna.Framework.Matrix> matrices, MdlxParser mParser)
{
bool[] treatedMatrices = new bool[mParser.Bones.Count];

int awaitingReverseCount;
do
{
awaitingReverseCount = mParser.Bones.Count;
for (int b = 0; b < mParser.Bones.Count; b++)
{
if (treatedMatrices[b] == false)
{
int awaitingReverseChildrenCount = 0;
for (int j = 0; j < mParser.Bones.Count; j++)
if (mParser.Bones[j].Parent == b && treatedMatrices[j] == false)
awaitingReverseChildrenCount++;
if (awaitingReverseChildrenCount == 0)
{
if (mParser.Bones[b].Parent > -1)
matrices[b] *= Microsoft.Xna.Framework.Matrix.Invert(matrices[mParser.Bones[b].Parent]);
treatedMatrices[b] = true;
awaitingReverseCount--;
}
}
else
awaitingReverseCount--;
}
}
while (awaitingReverseCount > 0);
}

public static void ComputeMatrices(ref List<Microsoft.Xna.Framework.Matrix> matrices, MdlxParser mParser)
{
for (int b = 0; b < mParser.Bones.Count; b++)
if (mParser.Bones[b].Parent > -1)
matrices[b] *= matrices[mParser.Bones[b].Parent];
}

public static int LocateMostSimilarPose(List<Microsoft.Xna.Framework.Matrix> matrices, Matrix4x4[] Fk, MdlxParser mParser, float similarity, bool skinnedMatricesOnly)
{
if (Fk.Length != mParser.Bones.Count)
throw new Exception("Incorrect input pose matrices.");
Microsoft.Xna.Framework.Vector3[] scales = new Microsoft.Xna.Framework.Vector3[mParser.Bones.Count];
Microsoft.Xna.Framework.Quaternion[] rotates = new Microsoft.Xna.Framework.Quaternion[mParser.Bones.Count];
Microsoft.Xna.Framework.Vector3[] translates = new Microsoft.Xna.Framework.Vector3[mParser.Bones.Count];

for (int j = 0; j < Fk.Length; j++)
{
Fk[j].ToXnaMatrix().Decompose(out scales[j], out rotates[j], out translates[j]);
rotates[j].Normalize();
}
float smallestDist = Single.MaxValue;
int position = (matrices.Count/ mParser.Bones.Count)-1;
for (int i=0; i< matrices.Count; i+= mParser.Bones.Count)
{
float currentDist = 0;
for (int j = 0; j < mParser.Bones.Count; j++)
{
if (skinnedMatricesOnly && mParser.skinnedBones[j] == false) continue;
Microsoft.Xna.Framework.Vector3 scale;
Microsoft.Xna.Framework.Quaternion rotate;
Microsoft.Xna.Framework.Vector3 translate;
matrices[i + j].Decompose(out scale, out rotate, out translate);
rotate.Normalize();
currentDist += Microsoft.Xna.Framework.Vector3.Distance(scale, scales[j]);
currentDist += (float)(Math.Abs(rotate.X - rotates[j].X) + Math.Abs(rotate.Y - rotates[j].Y) + Math.Abs(rotate.Z - rotates[j].Z) + Math.Abs(rotate.W - rotates[j].W));
currentDist += Microsoft.Xna.Framework.Vector3.Distance(translate, translates[j]);
}
if (currentDist < similarity && currentDist < smallestDist)
{
smallestDist = currentDist;
position = i / mParser.Bones.Count;
}
}
Console.WriteLine(smallestDist);
return position;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
using System.Threading.Tasks;
using System.Numerics;

namespace OpenKh.Tools.Kh2MsetMotionEditor.Helpers
namespace OpenKh.Engine.Monogame.Helpers
{
internal static class NumericsToXnaExtensions
public static class NumericsToXnaExtensions
{
public static xna.Matrix ToXnaMatrix(this Matrix4x4 it) => new xna.Matrix(
it.M11, it.M12, it.M13, it.M14,
Expand Down
1 change: 1 addition & 0 deletions OpenKh.Engine/Parsers/MdlxParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public class MeshDescriptor
public class MdlxParser : IModelMotion
{
private readonly Kkdf2MdlxParser _parsedModel;
public bool[] skinnedBones;

public MdlxParser(Mdlx mdlx)
{
Expand Down
26 changes: 19 additions & 7 deletions OpenKh.Tools.Kh2MsetMotionEditor/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using OpenKh.Tools.Kh2MsetMotionEditor.Interfaces;
using OpenKh.Tools.Kh2MsetMotionEditor.Usecases;
using OpenKh.Tools.Kh2MsetMotionEditor.Windows;
using OpenKh.Engine.Monogame.Helpers;
using System;
using System.Collections.Generic;
using System.IO;
Expand Down Expand Up @@ -354,6 +355,8 @@ private void ExportFBXCOLLADA(AssimpGeneric.FileFormat fileFormat)
var motionData = _loadedModel.MotionData;
if (motionData != null)
{
List<Microsoft.Xna.Framework.Matrix> allMatrices = new List<xna.Matrix>(0);
int offset = (int)((_loadedModel.FrameEnd * 2) - motionData.InterpolatedMotionHeader.FrameCount);
Animation animation = new Animation();
animation.Name = selectedMotionName;
animation.TicksPerSecond = fileFormat == AssimpGeneric.FileFormat.fbx ? 24f : 30f;
Expand All @@ -366,11 +369,12 @@ private void ExportFBXCOLLADA(AssimpGeneric.FileFormat fileFormat)
animation.NodeAnimationChannels.Add(nodeAnimationChannel);
}


for (int f = 0; f < motionData.InterpolatedMotionHeader.FrameCount; f++)
{
float timeKey = (float)((1 / animation.TicksPerSecond) * f);

var fkIk = _loadedModel.PoseProvider?.Invoke((float)f);
var fkIk = _loadedModel.PoseProvider?.Invoke((float)(offset+f));

List<Microsoft.Xna.Framework.Matrix> matrices = new List<Microsoft.Xna.Framework.Matrix>(0);
List<bool> dirtyMatrices = new List<bool>(0);
Expand All @@ -386,7 +390,8 @@ private void ExportFBXCOLLADA(AssimpGeneric.FileFormat fileFormat)
matrices.Add(fkIk.Fk[mIndex].ToXnaMatrix());
}
}
Kh2MdlxAssimp.ReverseMatrices(ref matrices, mParser);
allMatrices.AddRange(matrices);
MatrixRecursivity.ReverseMatrices(ref matrices, mParser);

for (int b = 0; b < mParser.Bones.Count; b++)
{
Expand All @@ -403,11 +408,18 @@ private void ExportFBXCOLLADA(AssimpGeneric.FileFormat fileFormat)
}

scene.Animations.Add(animation);
}
int loopFrame = MatrixRecursivity.LocateMostSimilarPose(allMatrices, _loadedModel.PoseProvider?.Invoke((float)(offset + motionData.InterpolatedMotionHeader.FrameCount)).Fk, mParser, 2f, true);

AssimpGeneric.ExportScene(scene, fileFormat, filename);
OpenKh.Tools.Kh2MdlxEditor.Views.Main_Window.exportTextures(_loadedModel.MdlxRenderableList[0].Textures, dirPath);
System.Windows.Forms.MessageBox.Show("Export complete.", "Complete", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
string loopFrame_ = loopFrame.ToString();
if (loopFrame == 0)
loopFrame_ = "BEGIN";
else if(loopFrame == motionData.InterpolatedMotionHeader.FrameCount-1)
loopFrame_ = "END";

AssimpGeneric.ExportScene(scene, fileFormat, Path.GetDirectoryName(filename)+@"\" + Path.GetFileNameWithoutExtension(filename) +"_LoopAt("+ loopFrame_ + ")"+Path.GetExtension(filename));
OpenKh.Tools.Kh2MdlxEditor.Views.Main_Window.exportTextures(_loadedModel.MdlxRenderableList[0].Textures, dirPath);
System.Windows.Forms.MessageBox.Show("Export complete.", "Complete", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
}
}
}
}
Expand All @@ -418,7 +430,7 @@ private void ExportFBXCOLLADA(AssimpGeneric.FileFormat fileFormat)
},
FileDialogFilterComposer.Compose()
.AddExtensions("Autodesk FBX ", "fbx"),
_loadedModel.MdlxFile + "-" + selectedMotionName.Replace(" ", "_") + "." + AssimpGeneric.GetFormatFileExtension(fileFormat)
Path.GetFileNameWithoutExtension(_loadedModel.MdlxFile) + "-" + selectedMotionName.Replace(" ", "_") + "." + AssimpGeneric.GetFormatFileExtension(fileFormat)
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public Action CreateToolRunnable()

var lastKeyTime = 60f / _loadedModel.FramePerSecond * _loadedModel.FrameEnd;

if (lastKeyTime < frame)
if (frame> lastKeyTime)
{
frame -= lastKeyTime - (60f / _loadedModel.FramePerSecond * _loadedModel.FrameLoop);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using OpenKh.Engine.Parsers;
using OpenKh.Kh2;
using OpenKh.Tools.Kh2MsetMotionEditor.Helpers;
using OpenKh.Engine.Monogame.Helpers;
using System;
using System.Collections.Generic;
using System.Drawing;
Expand Down

0 comments on commit 6bab378

Please sign in to comment.