mirror of
https://github.com/4sval/FModel.git
synced 2026-04-01 14:45:45 -05:00
128 lines
3.9 KiB
C#
128 lines
3.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using CUE4Parse_Conversion.Meshes.PSK;
|
|
using CUE4Parse.UE4.Assets.Exports.Animation;
|
|
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
|
using CUE4Parse.UE4.Objects.Core.Math;
|
|
using CUE4Parse.UE4.Objects.UObject;
|
|
using FModel.Views.Snooper.Animations;
|
|
using FModel.Views.Snooper.Buffers;
|
|
using FModel.Views.Snooper.Shading;
|
|
using OpenTK.Graphics.OpenGL4;
|
|
|
|
namespace FModel.Views.Snooper.Models;
|
|
|
|
public class SkeletalModel : UModel
|
|
{
|
|
private BufferObject<float> _morphVbo;
|
|
|
|
public readonly Skeleton Skeleton;
|
|
public readonly List<Morph> Morphs;
|
|
|
|
public bool HasMorphTargets => Morphs.Count > 0;
|
|
|
|
public float MorphTime;
|
|
|
|
public SkeletalModel(USkeletalMesh export, CSkeletalMesh skeletalMesh, Transform transform = null)
|
|
: base(export, skeletalMesh.LODs[LodLevel], export.Materials, skeletalMesh.LODs[LodLevel].Verts, skeletalMesh.LODs.Count, transform)
|
|
{
|
|
Box = skeletalMesh.BoundingBox * Constants.SCALE_DOWN_RATIO;
|
|
Skeleton = new Skeleton(export.ReferenceSkeleton);
|
|
|
|
var sockets = new List<FPackageIndex>();
|
|
sockets.AddRange(export.Sockets);
|
|
if (export.Skeleton.TryLoad(out USkeleton skeleton))
|
|
{
|
|
Skeleton.Name = skeleton.Name;
|
|
// Skeleton.Merge(skeleton.ReferenceSkeleton);
|
|
sockets.AddRange(skeleton.Sockets);
|
|
}
|
|
|
|
for (int i = 0; i < sockets.Count; i++)
|
|
{
|
|
if (sockets[i].Load<USkeletalMeshSocket>() is not { } socket) continue;
|
|
Sockets.Add(new Socket(socket));
|
|
}
|
|
|
|
Morphs = new List<Morph>();
|
|
for (var i = 0; i < export.MorphTargets.Length; i++)
|
|
{
|
|
if (!export.MorphTargets[i].TryLoad(out UMorphTarget morphTarget) ||
|
|
morphTarget.MorphLODModels.Length < 1 || morphTarget.MorphLODModels[0].Vertices.Length < 1)
|
|
continue;
|
|
|
|
Morphs.Add(new Morph(Vertices, VertexSize, morphTarget));
|
|
}
|
|
}
|
|
|
|
public SkeletalModel(USkeleton export, FBox box) : base(export)
|
|
{
|
|
Indices = Array.Empty<uint>();
|
|
Materials = Array.Empty<Material>();
|
|
Vertices = Array.Empty<float>();
|
|
Sections = Array.Empty<Section>();
|
|
AddInstance(Transform.Identity);
|
|
|
|
Box = box * Constants.SCALE_DOWN_RATIO;
|
|
Morphs = new List<Morph>();
|
|
Skeleton = new Skeleton(export.ReferenceSkeleton);
|
|
Skeleton.Name = export.Name;
|
|
|
|
for (int i = 0; i < export.Sockets.Length; i++)
|
|
{
|
|
if (export.Sockets[i].Load<USkeletalMeshSocket>() is not { } socket) continue;
|
|
Sockets.Add(new Socket(socket));
|
|
}
|
|
}
|
|
|
|
public override void Setup(Options options)
|
|
{
|
|
base.Setup(options);
|
|
|
|
Skeleton.Setup();
|
|
if (!HasMorphTargets) return;
|
|
|
|
for (int morph = 0; morph < Morphs.Count; morph++)
|
|
{
|
|
Morphs[morph].Setup();
|
|
if (morph == 0)
|
|
_morphVbo = new BufferObject<float>(Morphs[morph].Vertices, BufferTarget.ArrayBuffer);
|
|
}
|
|
|
|
Vao.Bind();
|
|
Vao.VertexAttributePointer(13, 3, VertexAttribPointerType.Float, Morph.VertexSize, 0); // morph position
|
|
Vao.VertexAttributePointer(14, 3, VertexAttribPointerType.Float, Morph.VertexSize, 0); // morph tangent
|
|
Vao.Unbind();
|
|
}
|
|
|
|
public void Render(Shader shader)
|
|
{
|
|
shader.SetUniform("uMorphTime", MorphTime);
|
|
Skeleton.Render(shader);
|
|
}
|
|
|
|
public void RenderBones(Shader shader)
|
|
{
|
|
shader.SetUniform("uInstanceMatrix", GetTransform().Matrix);
|
|
Skeleton.RenderBones();
|
|
}
|
|
|
|
public void UpdateMorph(int index)
|
|
{
|
|
_morphVbo.Update(Morphs[index].Vertices);
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
Skeleton?.Dispose();
|
|
if (HasMorphTargets) _morphVbo.Dispose();
|
|
foreach (var morph in Morphs)
|
|
{
|
|
morph?.Dispose();
|
|
}
|
|
Morphs.Clear();
|
|
|
|
base.Dispose();
|
|
}
|
|
}
|