Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/origin/master' into fix-mapgen-…
Browse files Browse the repository at this point in the history
…smaller
  • Loading branch information
kenjiuno committed Dec 9, 2022
2 parents dafe2f2 + 1bcede0 commit c14d2af
Show file tree
Hide file tree
Showing 51 changed files with 2,865 additions and 86 deletions.
190 changes: 190 additions & 0 deletions OpenKh.Command.AnbMaker/Commands/AnbCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
using Assimp;
using McMaster.Extensions.CommandLineUtils;
using NLog;
using OpenKh.Command.AnbMaker.Commands.Interfaces;
using OpenKh.Command.AnbMaker.Commands.Utils;
using OpenKh.Command.AnbMaker.Extensions;
using OpenKh.Command.AnbMaker.Utils;
using OpenKh.Command.AnbMaker.Utils.Builder;
using OpenKh.Command.AnbMaker.Utils.Builder.Models;
using OpenKh.Kh2;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static OpenKh.Command.AnbMaker.Utils.Builder.RawMotionBuilder;
using static OpenKh.Kh2.Motion;

namespace OpenKh.Command.AnbMaker.Commands
{
[HelpOption]
[Command(Description = "fbx file: fbx to raw anb")]
internal class AnbCommand : IFbxSourceItemSelector, IMsetInjector
{
[Required]
[FileExists]
[Argument(0, Description = "fbx input")]
public string InputModel { get; set; }

[Argument(1, Description = "anb output")]
public string Output { get; set; }

[Option(Description = "specify root armature node name", ShortName = "r")]
public string RootName { get; set; }

[Option(Description = "specify mesh name to read bone data", ShortName = "m")]
public string MeshName { get; set; }

[Option(Description = "apply scaling to each source node", ShortName = "x")]
public float NodeScaling { get; set; } = 1;

[Option(Description = "specify animation name to read bone data", ShortName = "a")]
public string AnimationName { get; set; }

[Option(Description = "optionally inject new motion into mset directly", ShortName = "w")]
public string MsetFile { get; set; }

[Option(Description = "zero based target index of bar entry in mset file", ShortName = "i")]
public int MsetIndex { get; set; }

protected int OnExecute(CommandLineApplication app)
{
var logger = LogManager.GetLogger("RawMotionMaker");

Output = Path.GetFullPath(Output ?? Path.GetFileNameWithoutExtension(InputModel) + ".anb");

Console.WriteLine($"Writing to: {Output}");

var parms = new UseAssimpForRaw(
InputModel,
MeshName,
RootName,
AnimationName,
NodeScaling
)
.Parameters;

foreach (var parm in parms.Take(1))
{
var builder = new RawMotionBuilder(
parm
);

logger.Debug($"(frameCount {parm.DurationInTicks:#,##0}) x (boneCount {parm.BoneCount:#,##0}) -> {builder.Raw.AnimationMatrices.Count:#,##0} matrices ({64 * builder.Raw.AnimationMatrices.Count:#,##0} bytes)");

var rawMotionStream = new MemoryStream();
RawMotion.Write(rawMotionStream, builder.Raw);

var anbBarStream = new MemoryStream();
Bar.Write(
anbBarStream,
new Bar.Entry[]
{
new Bar.Entry
{
Type = Bar.EntryType.Motion,
Name = "raw",
Stream = rawMotionStream,
}
}
);

File.WriteAllBytes(Output, anbBarStream.ToArray());
File.WriteAllBytes(Output + ".raw", rawMotionStream.ToArray());

logger.Debug("Raw motion data generation successful");

new MsetInjector().InjectMotionTo(this, rawMotionStream.ToArray());
}

return 0;
}

internal class UseAssimpForRaw
{
public IEnumerable<RawMotionBuilder.Parameter> Parameters { get; }

public UseAssimpForRaw(
string inputModel,
string meshName,
string rootName,
string animationName,
float nodeScaling
)
{
var assimp = new Assimp.AssimpContext();
var scene = assimp.ImportFile(inputModel, Assimp.PostProcessSteps.None);

var outputList = new List<RawMotionBuilder.Parameter>();

bool IsMeshNameMatched(string it) =>
string.IsNullOrEmpty(meshName)
? true
: it == meshName;

bool IsAnimationNameMatched(string it) =>
string.IsNullOrEmpty(animationName)
? true
: it == animationName;

foreach (var fbxMesh in scene.Meshes.Where(mesh => IsMeshNameMatched(mesh.Name)))
{
var fbxArmatureRoot = scene.RootNode.FindNode(rootName ?? "bone000"); //"kh_sk"
var fbxArmatureNodes = AssimpHelper.FlattenNodes(fbxArmatureRoot);
var fbxArmatureBoneCount = fbxArmatureNodes.Length;

foreach (var fbxAnim in scene.Animations.Where(anim => IsAnimationNameMatched(anim.Name)))
{
outputList.Add(
new Parameter
{
DurationInTicks = (int)fbxAnim.DurationInTicks,
TicksPerSecond = (float)fbxAnim.TicksPerSecond,
BoneCount = fbxArmatureNodes.Length,
NodeScaling = nodeScaling,
Bones = fbxArmatureNodes
.Select(
node => new ABone
{
NodeName = node.ArmatureNode.Name,
ParentIndex = node.ParentIndex,
}
)
.ToArray(),

GetRelativeMatrix = (frameIdx, boneIdx) =>
{
var name = fbxArmatureNodes[boneIdx].ArmatureNode.Name;

var hit = fbxAnim.NodeAnimationChannels.FirstOrDefault(it => it.NodeName == name);

var translation = (hit == null)
? new Vector3D(0, 0, 0)
: hit.PositionKeys.GetInterpolatedVector(frameIdx);

var rotation = (hit == null)
? new Assimp.Quaternion(w: 1, 0, 0, 0)
: hit.RotationKeys.GetInterpolatedQuaternion(frameIdx);

var scale = (hit == null)
? new Vector3D(1, 1, 1)
: hit.ScalingKeys.GetInterpolatedVector(frameIdx);

return System.Numerics.Matrix4x4.Identity
* System.Numerics.Matrix4x4.CreateFromQuaternion(rotation.ToDotNetQuaternion())
* System.Numerics.Matrix4x4.CreateScale(scale.ToDotNetVector3())
* System.Numerics.Matrix4x4.CreateTranslation(translation.ToDotNetVector3())
;
}
}
);
}
}

Parameters = outputList;
}
}
}
}
131 changes: 131 additions & 0 deletions OpenKh.Command.AnbMaker/Commands/AnbExCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
using McMaster.Extensions.CommandLineUtils;
using NLog;
using OpenKh.Command.AnbMaker.Commands.Interfaces;
using OpenKh.Command.AnbMaker.Commands.Utils;
using OpenKh.Command.AnbMaker.Utils.AssimpAnimSource;
using OpenKh.Command.AnbMaker.Utils.Builder;
using OpenKh.Command.AnbMaker.Utils.Builder.Models;
using OpenKh.Command.AnbMaker.Utils.JsonAnimSource;
using OpenKh.Kh2;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace OpenKh.Command.AnbMaker.Commands
{
[HelpOption]
[Command(Description = "fbx file: fbx to interpolated motion anb")]
internal class AnbExCommand : IFbxSourceItemSelector, IMsetInjector
{
[Required]
[FileExists]
[Argument(0, Description = "fbx input")]
public string InputModel { get; set; }

[Argument(1, Description = "anb output")]
public string Output { get; set; }

[Option(Description = "specify root armature node name", ShortName = "r")]
public string RootName { get; set; }

[Option(Description = "specify mesh name to read bone data", ShortName = "m")]
public string MeshName { get; set; }

[Option(Description = "specify animation name to read bone data", ShortName = "a")]
public string AnimationName { get; set; }

[Option(Description = "apply scaling to each source node", ShortName = "x")]
public float NodeScaling { get; set; } = 1;

[Option(Description = "optionally inject new motion into mset directly", ShortName = "w")]
public string MsetFile { get; set; }

[Option(Description = "zero based target index of bar entry in mset file", ShortName = "i")]
public int MsetIndex { get; set; }

protected int OnExecute(CommandLineApplication app)
{
var logger = LogManager.GetLogger("InterpolatedMotionMaker");

Output = Path.GetFullPath(Output ?? Path.GetFileNameWithoutExtension(InputModel) + ".anb");

Console.WriteLine($"Writing to: {Output}");

IEnumerable<BasicSourceMotion> parms;
if (Path.GetExtension(InputModel).ToLowerInvariant() == ".json")
{
parms = new UseJson(
inputModel: InputModel,
meshName: MeshName,
rootName: RootName,
animationName: AnimationName,
nodeScaling: 1
)
.Parameters;
}
else
{
parms = new UseAssimp(
inputModel: InputModel,
meshName: MeshName,
rootName: RootName,
animationName: AnimationName,
nodeScaling: NodeScaling
)
.Parameters;
}

foreach (var parm in parms.Take(1))
{
var builder = new InterpolatedMotionBuilder(parm);

var ipm = builder.Ipm;

logger.Debug($"{ipm.ConstraintActivations.Count,6:#,##0} ConstraintActivations");
logger.Debug($"{ipm.Constraints.Count,6:#,##0} Constraints");
logger.Debug($"{ipm.ExpressionNodes.Count,6:#,##0} ExpressionNodes");
logger.Debug($"{ipm.Expressions.Count,6:#,##0} Expressions");
logger.Debug($"{ipm.ExternalEffectors.Count,6:#,##0} ExternalEffectors");
logger.Debug($"{ipm.FCurveKeys.Count,6:#,##0} FCurveKeys");
logger.Debug($"{ipm.FCurvesForward.Count,6:#,##0} FCurvesForward");
logger.Debug($"{ipm.FCurvesInverse.Count,6:#,##0} FCurvesInverse");
logger.Debug($"{ipm.IKHelpers.Count,6:#,##0} IKHelpers");
logger.Debug($"{ipm.InitialPoses.Count,6:#,##0} InitialPoses");
logger.Debug($"{ipm.Joints.Count,6:#,##0} Joints");
logger.Debug($"{ipm.KeyTangents.Count,6:#,##0} KeyTangents");
logger.Debug($"{ipm.KeyTimes.Count,6:#,##0} KeyTimes");
logger.Debug($"{ipm.KeyValues.Count,6:#,##0} KeyValues");

var motionStream = (MemoryStream)ipm.toStream();

var anbBarStream = new MemoryStream();
Bar.Write(
anbBarStream,
new Bar.Entry[]
{
new Bar.Entry
{
Type = Bar.EntryType.Motion,
Name = "A999",
Stream = motionStream,
}
}
);

File.WriteAllBytes(Output, anbBarStream.ToArray());
File.WriteAllBytes(Output + ".raw", motionStream.ToArray());

logger.Debug($"Motion data generation successful");

new MsetInjector().InjectMotionTo(this, motionStream.ToArray());
}

return 0;
}
}
}
Loading

0 comments on commit c14d2af

Please sign in to comment.