mirror of
https://github.com/sampletext32/ParkanPlayground.git
synced 2026-08-15 02:57:49 +04:00
push
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
using System.Collections;
|
||||
using System.Numerics;
|
||||
using Common;
|
||||
using MshLib;
|
||||
using Quaternion = System.Numerics.Quaternion;
|
||||
using Vector3 = System.Numerics.Vector3;
|
||||
|
||||
namespace NResUI.Rendering.Viewport.Msh;
|
||||
|
||||
public static class MshRestPoseBuilder
|
||||
{
|
||||
public static IReadOnlyList<MshPieceRestPose> BuildRestPose(Msh0x01.Msh0x01Component nodesComponent, List<Msh0x08.AnimationDescriptor> animationDescriptors)
|
||||
{
|
||||
var nodeList = nodesComponent.Nodes;
|
||||
var animationList = animationDescriptors;
|
||||
|
||||
var poses = new MshPieceRestPose[nodeList.Count];
|
||||
var state = new byte[nodeList.Count];
|
||||
|
||||
for (var nodeIndex = 0; nodeIndex < nodeList.Count; nodeIndex++)
|
||||
BuildNodePose(nodeIndex, nodeList, animationList, poses, state);
|
||||
|
||||
return poses;
|
||||
}
|
||||
|
||||
private static Matrix4x4 BuildNodePose(
|
||||
int nodeIndex,
|
||||
List<Msh0x01.Node> nodes,
|
||||
List<Msh0x08.AnimationDescriptor> animationDescriptors,
|
||||
MshPieceRestPose[] poses,
|
||||
byte[] state)
|
||||
{
|
||||
if (state[nodeIndex] == 2)
|
||||
return poses[nodeIndex].MeshSpaceTransform;
|
||||
|
||||
if (state[nodeIndex] == 1)
|
||||
{
|
||||
// Broken/cyclic parent chain. Keep this node local so the viewer remains usable.
|
||||
return Matrix4x4.Identity;
|
||||
}
|
||||
state[nodeIndex] = 1;
|
||||
|
||||
var node = nodes[nodeIndex]!;
|
||||
var parentIndex = GetParentIndex(node);
|
||||
var fallbackKeyframeIndex = GetFallbackKeyframeIndex(node);
|
||||
var hasFallbackPose = fallbackKeyframeIndex >= 0 && fallbackKeyframeIndex < animationDescriptors.Count;
|
||||
|
||||
// var localTransform = Matrix4x4.Identity;
|
||||
Matrix4x4 localTransform;
|
||||
if (hasFallbackPose)
|
||||
{
|
||||
localTransform = BuildTransformFromAnimationDescriptor(animationDescriptors[fallbackKeyframeIndex]!);
|
||||
}
|
||||
else
|
||||
{
|
||||
localTransform = Matrix4x4.Identity;
|
||||
|
||||
Console.WriteLine($"Node {nodeIndex} has no fallback");
|
||||
}
|
||||
|
||||
if (parentIndex == -1)
|
||||
{
|
||||
localTransform.Translation = Vector3.Zero;
|
||||
|
||||
Console.WriteLine($"Node {nodeIndex} has no parent");
|
||||
}
|
||||
|
||||
var meshSpaceTransform = localTransform;
|
||||
if (parentIndex >= 0 && parentIndex < nodes.Count && parentIndex != nodeIndex)
|
||||
{
|
||||
var parentTransform = BuildNodePose(parentIndex, nodes, animationDescriptors, poses, state);
|
||||
meshSpaceTransform = localTransform * parentTransform;
|
||||
}
|
||||
|
||||
poses[nodeIndex] = new MshPieceRestPose(
|
||||
NodeIndex: nodeIndex,
|
||||
ParentIndex: parentIndex,
|
||||
FallbackKeyframeIndex: fallbackKeyframeIndex,
|
||||
HasFallbackPose: hasFallbackPose,
|
||||
LocalTransform: localTransform,
|
||||
MeshSpaceTransform: meshSpaceTransform);
|
||||
|
||||
state[nodeIndex] = 2;
|
||||
return meshSpaceTransform;
|
||||
}
|
||||
|
||||
private static int GetParentIndex(Msh0x01.Node node)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToInt32(node.ParentIndexOrMinusOne);
|
||||
}
|
||||
catch
|
||||
{
|
||||
var rawParent = Convert.ToUInt16(node.ParentIndexOrLink);
|
||||
return rawParent == ushort.MaxValue ? -1 : rawParent;
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetFallbackKeyframeIndex(Msh0x01.Node node)
|
||||
{
|
||||
try
|
||||
{
|
||||
var value = Convert.ToUInt16(node.FallbackKey0x08);
|
||||
return value == ushort.MaxValue ? -1 : value;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static Matrix4x4 BuildTransformFromAnimationDescriptor(Msh0x08.AnimationDescriptor descriptor)
|
||||
{
|
||||
var position = ToSystemVector3(descriptor.Position);
|
||||
var rotation = ToSystemQuaternion(descriptor.Rotation);
|
||||
|
||||
var matrix = Matrix4x4.CreateFromQuaternion(rotation);
|
||||
matrix.Translation = position;
|
||||
return matrix;
|
||||
}
|
||||
|
||||
private static Vector3 ToSystemVector3(dynamic vector)
|
||||
{
|
||||
return new Vector3(
|
||||
Convert.ToSingle(vector.X),
|
||||
Convert.ToSingle(vector.Y),
|
||||
Convert.ToSingle(vector.Z));
|
||||
}
|
||||
|
||||
private static Quaternion ToSystemQuaternion(UShortQuaternion packedQuaternion)
|
||||
{
|
||||
// MSH 0x08 stores quaternion as W, X, Y, Z.
|
||||
// System.Numerics.Quaternion constructor expects X, Y, Z, W.
|
||||
|
||||
var q = new Quaternion(
|
||||
packedQuaternion.X / 32767f,
|
||||
packedQuaternion.Y / 32767f,
|
||||
packedQuaternion.Z / 32767f,
|
||||
packedQuaternion.W / 32767f
|
||||
);
|
||||
|
||||
if (q.LengthSquared() < 1e-8f)
|
||||
return Quaternion.Identity;
|
||||
|
||||
return Quaternion.Normalize(q);
|
||||
}
|
||||
}
|
||||
|
||||
public readonly record struct MshPieceRestPose(
|
||||
int NodeIndex,
|
||||
int ParentIndex,
|
||||
int FallbackKeyframeIndex,
|
||||
bool HasFallbackPose,
|
||||
Matrix4x4 LocalTransform,
|
||||
Matrix4x4 MeshSpaceTransform);
|
||||
@@ -49,6 +49,9 @@ public static class MshViewportLoader
|
||||
var positions = Msh0x03.ReadComponent(fs, archive);
|
||||
var indices = Msh0x06.ReadComponent(fs, archive);
|
||||
var batches = Msh0x0D.ReadComponent(fs, archive);
|
||||
var animationDescriptors = Msh0x08.ReadComponent(fs, archive);
|
||||
var restPoses = MshRestPoseBuilder.BuildRestPose(nodes, animationDescriptors);
|
||||
var mshToViewportTransform = Matrix4x4.CreateRotationX(-MathF.PI * 0.5f);
|
||||
var names = TryReadNames(fs, archive);
|
||||
|
||||
var pieces = new List<ViewportPiece>();
|
||||
@@ -56,6 +59,7 @@ public static class MshViewportLoader
|
||||
for (var nodeIndex = 0; nodeIndex < nodes.Nodes.Count; nodeIndex++)
|
||||
{
|
||||
var node = nodes.Nodes[nodeIndex];
|
||||
var restPose = restPoses[nodeIndex];
|
||||
var slotIndex = node.ResolveSlotIndex(DefaultModelState, DefaultLod);
|
||||
if (slotIndex == ushort.MaxValue)
|
||||
continue;
|
||||
@@ -72,24 +76,24 @@ public static class MshViewportLoader
|
||||
continue;
|
||||
|
||||
var name = ResolvePieceName(names, nodeIndex);
|
||||
var parentIndex = node.ParentIndexOrMinusOne;
|
||||
|
||||
pieces.Add(new ViewportPiece(
|
||||
id: nodeIndex,
|
||||
name: name,
|
||||
mesh: meshBuildResult.Mesh,
|
||||
localTransform: Matrix4x4.Identity,
|
||||
localTransform: restPose.MeshSpaceTransform * mshToViewportTransform,
|
||||
boundsMin: meshBuildResult.BoundsMin,
|
||||
boundsMax: meshBuildResult.BoundsMax,
|
||||
debugInfo: new ViewportPieceDebugInfo
|
||||
{
|
||||
SourceKind = "MSH 0x01 piece",
|
||||
SourcePieceIndex = nodeIndex,
|
||||
SourceParentIndex = parentIndex,
|
||||
SourceParentIndex = restPose.ParentIndex,
|
||||
GeometrySlotIndex = slotIndex,
|
||||
Msh01Flags = (uint)node.Flags,
|
||||
BatchCount = meshBuildResult.BatchCount,
|
||||
TriangleCount = meshBuildResult.TriangleCount
|
||||
TriangleCount = meshBuildResult.TriangleCount,
|
||||
FallbackKeyframeIndex = restPose.FallbackKeyframeIndex,
|
||||
HasRestPose = restPose.HasFallbackPose
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -135,9 +139,19 @@ public static class MshViewportLoader
|
||||
if (!IsValidTriangle(positions.Count, vertexIndex0, vertexIndex1, vertexIndex2))
|
||||
continue;
|
||||
|
||||
AddTriangleVertex(positions[vertexIndex0], color, vertices, outIndices, ref boundsMin, ref boundsMax);
|
||||
AddTriangleVertex(positions[vertexIndex1], color, vertices, outIndices, ref boundsMin, ref boundsMax);
|
||||
AddTriangleVertex(positions[vertexIndex2], color, vertices, outIndices, ref boundsMin, ref boundsMax);
|
||||
var p0 = ToNumericsVector3(positions[vertexIndex0]);
|
||||
var p1 = ToNumericsVector3(positions[vertexIndex1]);
|
||||
var p2 = ToNumericsVector3(positions[vertexIndex2]);
|
||||
|
||||
var normal = Vector3.Cross(p1 - p0, p2 - p0);
|
||||
if (normal.LengthSquared() < 1e-8f)
|
||||
normal = Vector3.UnitY;
|
||||
else
|
||||
normal = Vector3.Normalize(normal);
|
||||
|
||||
AddTriangleVertex(p0, color, normal, vertices, outIndices, ref boundsMin, ref boundsMax);
|
||||
AddTriangleVertex(p1, color, normal, vertices, outIndices, ref boundsMin, ref boundsMax);
|
||||
AddTriangleVertex(p2, color, normal, vertices, outIndices, ref boundsMin, ref boundsMax);
|
||||
triangleCount++;
|
||||
}
|
||||
}
|
||||
@@ -148,14 +162,21 @@ public static class MshViewportLoader
|
||||
var mesh = PrimitiveMeshes.CreateColoredIndexedMesh(gl, vertices, outIndices, PrimitiveType.Triangles);
|
||||
return new PieceMeshBuildResult(mesh, boundsMin, boundsMax, batchCount, triangleCount);
|
||||
}
|
||||
|
||||
private static Vector3 ToNumericsVector3(Common.Vector3 position)
|
||||
{
|
||||
return new Vector3(position.X, position.Y, position.Z);
|
||||
}
|
||||
|
||||
private static void AddTriangleVertex(
|
||||
Common.Vector3 position,
|
||||
Vector3 position,
|
||||
Vector3 color,
|
||||
Vector3 normal,
|
||||
List<float> vertices,
|
||||
List<uint> indices,
|
||||
ref Vector3 boundsMin,
|
||||
ref Vector3 boundsMax)
|
||||
ref Vector3 boundsMax
|
||||
)
|
||||
{
|
||||
var vertexIndex = (uint)(vertices.Count / 6);
|
||||
|
||||
@@ -165,6 +186,9 @@ public static class MshViewportLoader
|
||||
vertices.Add(color.X);
|
||||
vertices.Add(color.Y);
|
||||
vertices.Add(color.Z);
|
||||
vertices.Add(normal.X);
|
||||
vertices.Add(normal.Y);
|
||||
vertices.Add(normal.Z);
|
||||
|
||||
indices.Add(vertexIndex);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user