mirror of
https://github.com/sampletext32/ParkanPlayground.git
synced 2026-08-15 02:57:49 +04:00
animations and QOL
This commit is contained in:
@@ -3,9 +3,10 @@ using NResUI.Rendering.Viewport;
|
||||
|
||||
namespace NResUI.Rendering.Viewport.Meshes;
|
||||
|
||||
public sealed class GpuMesh
|
||||
public sealed class GpuMesh : IDisposable
|
||||
{
|
||||
private readonly GL _gl;
|
||||
private bool _disposed;
|
||||
|
||||
public uint VertexArrayObject { get; }
|
||||
public uint VertexBufferObject { get; }
|
||||
@@ -34,7 +35,21 @@ public sealed class GpuMesh
|
||||
|
||||
public unsafe void Draw()
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
_gl.BindVertexArray(VertexArrayObject);
|
||||
_gl.DrawElements(PrimitiveType, IndexCount, DrawElementsType.UnsignedInt, null);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
_gl.DeleteBuffer(ElementBufferObject);
|
||||
_gl.DeleteBuffer(VertexBufferObject);
|
||||
_gl.DeleteVertexArray(VertexArrayObject);
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,22 @@ public static class MshRestPoseBuilder
|
||||
/// Собирает bind/rest pose для pieces из fallback keyframes 0x08.
|
||||
/// Циклы и битые parent-ссылки не должны ломать viewport, поэтому такие узлы остаются с identity transform.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<MshPieceRestPose> BuildRestPose(Msh0x01.Msh0x01Component nodesComponent, List<Msh0x08.AnimationDescriptor> animationDescriptors)
|
||||
public static IReadOnlyList<MshPieceRestPose> BuildRestPose(Msh0x01.Msh0x01Component nodesComponent, IReadOnlyList<MshTransformKeyframe> animationDescriptors)
|
||||
{
|
||||
return BuildPose(
|
||||
nodesComponent,
|
||||
animationDescriptors,
|
||||
[],
|
||||
MshAnimationPoseMode.DefaultKeyframe,
|
||||
0.0f);
|
||||
}
|
||||
|
||||
public static IReadOnlyList<MshPieceRestPose> BuildPose(
|
||||
Msh0x01.Msh0x01Component nodesComponent,
|
||||
IReadOnlyList<MshTransformKeyframe> animationDescriptors,
|
||||
IReadOnlyList<MshAnimationMapEntry> animationMap,
|
||||
MshAnimationPoseMode poseMode,
|
||||
float sampleTime)
|
||||
{
|
||||
var nodeList = nodesComponent.Nodes;
|
||||
var animationList = animationDescriptors;
|
||||
@@ -22,7 +37,7 @@ public static class MshRestPoseBuilder
|
||||
var state = new byte[nodeList.Count];
|
||||
|
||||
for (var nodeIndex = 0; nodeIndex < nodeList.Count; nodeIndex++)
|
||||
BuildNodePose(nodeIndex, nodeList, animationList, poses, state);
|
||||
BuildNodePose(nodeIndex, nodeList, animationList, animationMap, poses, state, poseMode, sampleTime);
|
||||
|
||||
return poses;
|
||||
}
|
||||
@@ -30,9 +45,12 @@ public static class MshRestPoseBuilder
|
||||
private static Matrix4x4 BuildNodePose(
|
||||
int nodeIndex,
|
||||
List<Msh0x01.Node> nodes,
|
||||
List<Msh0x08.AnimationDescriptor> animationDescriptors,
|
||||
IReadOnlyList<MshTransformKeyframe> animationDescriptors,
|
||||
IReadOnlyList<MshAnimationMapEntry> animationMap,
|
||||
MshPieceRestPose[] poses,
|
||||
byte[] state)
|
||||
byte[] state,
|
||||
MshAnimationPoseMode poseMode,
|
||||
float sampleTime)
|
||||
{
|
||||
if (state[nodeIndex] == 2)
|
||||
return poses[nodeIndex].MeshSpaceTransform;
|
||||
@@ -49,11 +67,10 @@ public static class MshRestPoseBuilder
|
||||
var fallbackKeyframeIndex = GetFallbackKeyframeIndex(node);
|
||||
var hasFallbackPose = fallbackKeyframeIndex >= 0 && fallbackKeyframeIndex < animationDescriptors.Count;
|
||||
|
||||
// var localTransform = Matrix4x4.Identity;
|
||||
Matrix4x4 localTransform;
|
||||
if (hasFallbackPose)
|
||||
{
|
||||
localTransform = BuildTransformFromAnimationDescriptor(animationDescriptors[fallbackKeyframeIndex]!);
|
||||
localTransform = BuildLocalTransform(node, animationDescriptors, animationMap, poseMode, sampleTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -69,7 +86,7 @@ public static class MshRestPoseBuilder
|
||||
var meshSpaceTransform = localTransform;
|
||||
if (parentIndex >= 0 && parentIndex < nodes.Count && parentIndex != nodeIndex)
|
||||
{
|
||||
var parentTransform = BuildNodePose(parentIndex, nodes, animationDescriptors, poses, state);
|
||||
var parentTransform = BuildNodePose(parentIndex, nodes, animationDescriptors, animationMap, poses, state, poseMode, sampleTime);
|
||||
meshSpaceTransform = localTransform * parentTransform;
|
||||
}
|
||||
|
||||
@@ -85,6 +102,43 @@ public static class MshRestPoseBuilder
|
||||
return meshSpaceTransform;
|
||||
}
|
||||
|
||||
private static Matrix4x4 BuildLocalTransform(
|
||||
Msh0x01.Node node,
|
||||
IReadOnlyList<MshTransformKeyframe> animationDescriptors,
|
||||
IReadOnlyList<MshAnimationMapEntry> animationMap,
|
||||
MshAnimationPoseMode poseMode,
|
||||
float sampleTime)
|
||||
{
|
||||
if (poseMode == MshAnimationPoseMode.AnimationSample)
|
||||
{
|
||||
return MshAnimationSampler.ToMatrix(MshAnimationSampler.SamplePieceAnimationAtTime(
|
||||
node,
|
||||
animationDescriptors,
|
||||
animationMap,
|
||||
sampleTime));
|
||||
}
|
||||
|
||||
return BuildTransformFromAnimationDescriptor(animationDescriptors[node.DefaultKeyframeIndex0x08]);
|
||||
}
|
||||
|
||||
private static bool IsValidSampleStream(
|
||||
Msh0x01.Node node,
|
||||
IReadOnlyList<MshTransformKeyframe> animationDescriptors,
|
||||
IReadOnlyList<MshAnimationMapEntry> animationMap,
|
||||
float sampleTime)
|
||||
{
|
||||
if (animationMap.Count == 0 || node.AnimMapStart0x13 == ushort.MaxValue)
|
||||
return false;
|
||||
|
||||
var frameIndex = (int)MathF.Round(sampleTime - 0.5f, MidpointRounding.AwayFromZero);
|
||||
if (frameIndex < 0 || node.AnimMapStart0x13 + frameIndex >= animationMap.Count)
|
||||
return false;
|
||||
|
||||
var keyframeIndex = animationMap[node.AnimMapStart0x13 + frameIndex].KeyframeIndex;
|
||||
return keyframeIndex < node.DefaultKeyframeIndex0x08 &&
|
||||
keyframeIndex + 1 < animationDescriptors.Count;
|
||||
}
|
||||
|
||||
private static int GetParentIndex(Msh0x01.Node node)
|
||||
{
|
||||
return node.ParentIndexOrLink == ushort.MaxValue ? -1 : node.ParentIndexOrLink;
|
||||
@@ -103,14 +157,9 @@ public static class MshRestPoseBuilder
|
||||
}
|
||||
}
|
||||
|
||||
private static Matrix4x4 BuildTransformFromAnimationDescriptor(Msh0x08.AnimationDescriptor descriptor)
|
||||
private static Matrix4x4 BuildTransformFromAnimationDescriptor(MshTransformKeyframe descriptor)
|
||||
{
|
||||
var position = ToSystemVector3(descriptor.Position);
|
||||
var rotation = ToSystemQuaternion(descriptor.Rotation);
|
||||
|
||||
var matrix = Matrix4x4.CreateFromQuaternion(rotation);
|
||||
matrix.Translation = position;
|
||||
return matrix;
|
||||
return MshAnimationSampler.ToMatrix(MshAnimationSampler.FromKeyframe(descriptor));
|
||||
}
|
||||
|
||||
private static Vector3 ToSystemVector3(dynamic vector)
|
||||
@@ -143,6 +192,12 @@ public static class MshRestPoseBuilder
|
||||
}
|
||||
}
|
||||
|
||||
public enum MshAnimationPoseMode
|
||||
{
|
||||
DefaultKeyframe,
|
||||
AnimationSample
|
||||
}
|
||||
|
||||
public readonly record struct MshPieceRestPose(
|
||||
int NodeIndex,
|
||||
int ParentIndex,
|
||||
|
||||
@@ -3,7 +3,7 @@ using NResUI.Rendering.Viewport.Meshes;
|
||||
|
||||
namespace NResUI.Rendering.Viewport;
|
||||
|
||||
public sealed class ViewportPiece
|
||||
public sealed class ViewportPiece : IDisposable
|
||||
{
|
||||
public int Id { get; }
|
||||
public string Name { get; }
|
||||
@@ -75,4 +75,10 @@ public sealed class ViewportPiece
|
||||
TriangleCount = 12
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var mesh in Meshes)
|
||||
mesh.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,12 +39,14 @@ public sealed class ViewportScene
|
||||
|
||||
public void ClearPieces()
|
||||
{
|
||||
DisposePieces();
|
||||
_pieces.Clear();
|
||||
ClearSelection();
|
||||
}
|
||||
|
||||
public void ReplacePieces(IEnumerable<ViewportPiece> pieces)
|
||||
{
|
||||
DisposePieces();
|
||||
_pieces.Clear();
|
||||
_pieces.AddRange(pieces);
|
||||
ClearSelection();
|
||||
@@ -104,6 +106,12 @@ public sealed class ViewportScene
|
||||
return scene;
|
||||
}
|
||||
|
||||
private void DisposePieces()
|
||||
{
|
||||
foreach (var piece in _pieces)
|
||||
piece.Dispose();
|
||||
}
|
||||
|
||||
private static bool TryTransformBounds(
|
||||
Vector3 localMin,
|
||||
Vector3 localMax,
|
||||
|
||||
Reference in New Issue
Block a user