mirror of
https://github.com/4sval/FModel.git
synced 2026-09-30 21:19:33 -05:00
GetBoneTransform at runtime but it's flickering now, for later me
This commit is contained in:
Submodule CUE4Parse updated: b18da13023...d0c44876fc
@@ -85,10 +85,10 @@ public partial class MainWindow
|
||||
#if DEBUG
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken,
|
||||
"ShooterGame/Content/Characters/Guide/S0/3P/Models/TP_Guide_S0_Skelmesh.uasset"));
|
||||
"fortnitegame/Content/Characters/Player/Female/Medium/Bodies/F_Med_Soldier_01/Meshes/F_Med_Soldier_01.uasset"));
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken,
|
||||
"ShooterGame/Content/Characters/Guide/S0/Ability_Q/3P/Anims/TP_Guide_S0_Q_WolfTotem_Cast_Outro_Montage.uasset"));
|
||||
"fortnitegame/Content/Animation/Game/MainPlayer/Emotes/Cowbell/Cowbell_CMM_Loop_M.uasset"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,15 @@ layout(std430, binding = 1) buffer BoneMatrices
|
||||
{
|
||||
mat4 uFinalBonesMatrix[];
|
||||
};
|
||||
layout(std430, binding = 2) buffer RestBoneMatrices
|
||||
{
|
||||
mat4 uRestBonesMatrix[];
|
||||
};
|
||||
|
||||
uniform mat4 uView;
|
||||
uniform mat4 uProjection;
|
||||
uniform float uMorphTime;
|
||||
uniform bool uIsAnimated;
|
||||
|
||||
out vec3 fPos;
|
||||
out vec3 fNormal;
|
||||
@@ -37,14 +42,14 @@ void main()
|
||||
vec4 finalPos = vec4(0.0);
|
||||
vec4 finalNormal = vec4(0.0);
|
||||
vec4 finalTangent = vec4(0.0);
|
||||
if (vBoneIds != vBoneWeights)
|
||||
if (uIsAnimated)
|
||||
{
|
||||
for(int i = 0 ; i < 4; i++)
|
||||
{
|
||||
int boneIndex = int(vBoneIds[i]);
|
||||
if(boneIndex < 0) break;
|
||||
|
||||
mat4 boneMatrix = uFinalBonesMatrix[boneIndex];
|
||||
mat4 boneMatrix = uFinalBonesMatrix[boneIndex] * inverse(uRestBonesMatrix[boneIndex]);
|
||||
mat4 inverseBoneMatrix = transpose(inverse(boneMatrix));
|
||||
float weight = vBoneWeights[i];
|
||||
|
||||
|
||||
@@ -11,11 +11,16 @@ layout(std430, binding = 1) buffer BoneMatrices
|
||||
{
|
||||
mat4 uFinalBonesMatrix[];
|
||||
};
|
||||
layout(std430, binding = 2) buffer RestBoneMatrices
|
||||
{
|
||||
mat4 uRestBonesMatrix[];
|
||||
};
|
||||
|
||||
uniform mat4 uView;
|
||||
uniform vec3 uViewPos;
|
||||
uniform mat4 uProjection;
|
||||
uniform float uMorphTime;
|
||||
uniform bool uIsAnimated;
|
||||
|
||||
void main()
|
||||
{
|
||||
@@ -24,14 +29,14 @@ void main()
|
||||
|
||||
vec4 finalPos = vec4(0.0);
|
||||
vec4 finalNormal = vec4(0.0);
|
||||
if (vBoneIds != vBoneWeights)
|
||||
if (uIsAnimated)
|
||||
{
|
||||
for(int i = 0 ; i < 4; i++)
|
||||
{
|
||||
int boneIndex = int(vBoneIds[i]);
|
||||
if(boneIndex < 0) break;
|
||||
|
||||
mat4 boneMatrix = uFinalBonesMatrix[boneIndex];
|
||||
mat4 boneMatrix = uFinalBonesMatrix[boneIndex] * inverse(uRestBonesMatrix[boneIndex]);
|
||||
float weight = vBoneWeights[i];
|
||||
|
||||
finalPos += boneMatrix * bindPos * weight;
|
||||
|
||||
@@ -10,24 +10,29 @@ layout(std430, binding = 1) buffer BoneMatrices
|
||||
{
|
||||
mat4 uFinalBonesMatrix[];
|
||||
};
|
||||
layout(std430, binding = 2) buffer RestBoneMatrices
|
||||
{
|
||||
mat4 uRestBonesMatrix[];
|
||||
};
|
||||
|
||||
uniform mat4 uView;
|
||||
uniform mat4 uProjection;
|
||||
uniform float uMorphTime;
|
||||
uniform bool uIsAnimated;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 bindPos = vec4(mix(vPos, vMorphTargetPos, uMorphTime), 1.0);
|
||||
|
||||
vec4 finalPos = vec4(0.0);
|
||||
if (vBoneIds != vBoneWeights)
|
||||
if (uIsAnimated)
|
||||
{
|
||||
for(int i = 0 ; i < 4; i++)
|
||||
{
|
||||
int boneIndex = int(vBoneIds[i]);
|
||||
if(boneIndex < 0) break;
|
||||
|
||||
finalPos += uFinalBonesMatrix[boneIndex] * bindPos * vBoneWeights[i];
|
||||
finalPos += uFinalBonesMatrix[boneIndex] * inverse(uRestBonesMatrix[boneIndex]) * bindPos * vBoneWeights[i];
|
||||
}
|
||||
}
|
||||
else finalPos = bindPos;
|
||||
|
||||
@@ -655,47 +655,50 @@
|
||||
<GridSplitter Grid.Column="1" Width="4" VerticalAlignment="Stretch" ResizeDirection="Columns" KeyboardIncrement="0"
|
||||
Visibility="{Binding SelectedItem.HasImage, ElementName=TabControlName, Converter={StaticResource BoolToVisibilityConverter}}"
|
||||
Background="{DynamicResource {x:Static adonisUi:Brushes.Layer3BackgroundBrush}}" />
|
||||
<Image Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Center" Stretch="Uniform"
|
||||
Visibility="{Binding SelectedItem.HasImage, ElementName=TabControlName, Converter={StaticResource BoolToVisibilityConverter}}"
|
||||
Source="{Binding SelectedItem.SelectedImage.Image, ElementName=TabControlName}" RenderOptions.BitmapScalingMode="{Binding SelectedItem.SelectedImage.RenderNearestNeighbor, ElementName=TabControlName, Converter={x:Static converters:BoolToRenderModeConverter.Instance}}">
|
||||
<Image.InputBindings>
|
||||
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding SelectedItem.ImageCommand, ElementName=TabControlName}" CommandParameter="Open"/>
|
||||
</Image.InputBindings>
|
||||
<Image.ContextMenu>
|
||||
<ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
|
||||
<MenuItem Header="Disable Alpha Channel" IsCheckable="True" IsChecked="{Binding DataContext.SelectedImage.NoAlpha}" />
|
||||
<MenuItem Header="Open Image" Command="{Binding DataContext.ImageCommand}" CommandParameter="Open">
|
||||
<MenuItem.Icon>
|
||||
<Viewbox Width="16" Height="16">
|
||||
<Canvas Width="24" Height="24">
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="M20,4H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V6C22,4.9,21.1,4,20,4z M20,18H4V6h16V18z" />
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="M6,12c0.55,0,1-0.45,1-1V9h2c0.55,0,1-0.45,1-1S9.55,7,9,7H6C5.45,7,5,7.45,5,8v3C5,11.55,5.45,12,6,12z" />
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="M15,17h3c0.55,0,1-0.45,1-1v-3c0-0.55-0.45-1-1-1s-1,0.45-1,1v2h-2c-0.55,0-1,0.45-1,1S14.45,17,15,17z" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Copy Image" Command="{Binding DataContext.ImageCommand}" CommandParameter="Copy">
|
||||
<MenuItem.Icon>
|
||||
<Viewbox Width="16" Height="16">
|
||||
<Canvas Width="24" Height="24">
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource CopyIcon}" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Save Image" Command="{Binding DataContext.ImageCommand}" CommandParameter="Save">
|
||||
<MenuItem.Icon>
|
||||
<Viewbox Width="16" Height="16">
|
||||
<Canvas Width="24" Height="24">
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource SaveIcon}" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
</Image.ContextMenu>
|
||||
</Image>
|
||||
<Border Grid.Column="2" BorderBrush="#3b3d4a" BorderThickness="1" HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Visibility="{Binding SelectedItem.HasImage, ElementName=TabControlName, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<Image VerticalAlignment="Center" HorizontalAlignment="Center" Stretch="Uniform"
|
||||
Visibility="{Binding SelectedItem.HasImage, ElementName=TabControlName, Converter={StaticResource BoolToVisibilityConverter}}"
|
||||
Source="{Binding SelectedItem.SelectedImage.Image, ElementName=TabControlName}" RenderOptions.BitmapScalingMode="{Binding SelectedItem.SelectedImage.RenderNearestNeighbor, ElementName=TabControlName, Converter={x:Static converters:BoolToRenderModeConverter.Instance}}">
|
||||
<Image.InputBindings>
|
||||
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding SelectedItem.ImageCommand, ElementName=TabControlName}" CommandParameter="Open"/>
|
||||
</Image.InputBindings>
|
||||
<Image.ContextMenu>
|
||||
<ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
|
||||
<MenuItem Header="Disable Alpha Channel" IsCheckable="True" IsChecked="{Binding DataContext.SelectedImage.NoAlpha}" />
|
||||
<MenuItem Header="Open Image" Command="{Binding DataContext.ImageCommand}" CommandParameter="Open">
|
||||
<MenuItem.Icon>
|
||||
<Viewbox Width="16" Height="16">
|
||||
<Canvas Width="24" Height="24">
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="M20,4H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V6C22,4.9,21.1,4,20,4z M20,18H4V6h16V18z" />
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="M6,12c0.55,0,1-0.45,1-1V9h2c0.55,0,1-0.45,1-1S9.55,7,9,7H6C5.45,7,5,7.45,5,8v3C5,11.55,5.45,12,6,12z" />
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="M15,17h3c0.55,0,1-0.45,1-1v-3c0-0.55-0.45-1-1-1s-1,0.45-1,1v2h-2c-0.55,0-1,0.45-1,1S14.45,17,15,17z" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Copy Image" Command="{Binding DataContext.ImageCommand}" CommandParameter="Copy">
|
||||
<MenuItem.Icon>
|
||||
<Viewbox Width="16" Height="16">
|
||||
<Canvas Width="24" Height="24">
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource CopyIcon}" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Save Image" Command="{Binding DataContext.ImageCommand}" CommandParameter="Save">
|
||||
<MenuItem.Icon>
|
||||
<Viewbox Width="16" Height="16">
|
||||
<Canvas Width="24" Height="24">
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource SaveIcon}" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
</Image.ContextMenu>
|
||||
</Image>
|
||||
</Border>
|
||||
<TextBlock Grid.Column="2" VerticalAlignment="Bottom" HorizontalAlignment="Center"
|
||||
Visibility="{Binding SelectedItem.HasMultipleImages, ElementName=TabControlName, Converter={StaticResource BoolToVisibilityConverter}}"
|
||||
Text="{Binding SelectedItem.Page, ElementName=TabControlName}" />
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace FModel.Views.Snooper.Animations;
|
||||
public class Animation : IDisposable
|
||||
{
|
||||
private readonly UObject _export;
|
||||
private readonly CAnimSet _animSet;
|
||||
|
||||
public readonly CAnimSet UnrealAnim;
|
||||
public readonly string Path;
|
||||
public readonly string Name;
|
||||
public readonly Sequence[] Sequences;
|
||||
@@ -38,12 +38,12 @@ public class Animation : IDisposable
|
||||
|
||||
public Animation(UObject export, CAnimSet animSet) : this(export)
|
||||
{
|
||||
_animSet = animSet;
|
||||
UnrealAnim = animSet;
|
||||
|
||||
Sequences = new Sequence[_animSet.Sequences.Count];
|
||||
Sequences = new Sequence[UnrealAnim.Sequences.Count];
|
||||
for (int i = 0; i < Sequences.Length; i++)
|
||||
{
|
||||
Sequences[i] = new Sequence(_animSet.Sequences[i]);
|
||||
Sequences[i] = new Sequence(UnrealAnim.Sequences[i]);
|
||||
EndTime = Sequences[i].EndTime;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ public class Animation : IDisposable
|
||||
for (int i = 0; i < Sequences.Length; i++)
|
||||
{
|
||||
var sequence = Sequences[i];
|
||||
if (elapsedTime < sequence.EndTime && elapsedTime >= sequence.StartTime)
|
||||
if (elapsedTime <= sequence.EndTime && elapsedTime >= sequence.StartTime)
|
||||
{
|
||||
Framing[i] = (elapsedTime - sequence.StartTime) / sequence.TimePerFrame;
|
||||
}
|
||||
@@ -122,7 +122,7 @@ public class Animation : IDisposable
|
||||
{
|
||||
if (selected) AttachedModels.Remove(guid); else AttachedModels.Add(guid);
|
||||
model.Skeleton.ResetAnimatedData(true);
|
||||
if (!selected) model.Skeleton.Animate(_animSet, s.Renderer.AnimateWithRotationOnly);
|
||||
if (!selected) model.Skeleton.Animate(UnrealAnim);
|
||||
}
|
||||
}
|
||||
ImGui.EndMenu();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using CUE4Parse_Conversion.Animations.PSA;
|
||||
using CUE4Parse.UE4.Assets.Exports.Animation;
|
||||
using CUE4Parse.UE4.Objects.Core.Math;
|
||||
using CUE4Parse.Utils;
|
||||
using FModel.Views.Snooper.Buffers;
|
||||
using FModel.Views.Snooper.Shading;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using Serilog;
|
||||
|
||||
@@ -14,27 +14,24 @@ namespace FModel.Views.Snooper.Animations;
|
||||
public class Skeleton : IDisposable
|
||||
{
|
||||
private int _handle;
|
||||
private BufferObject<Matrix4x4> _rest;
|
||||
private BufferObject<Matrix4x4> _ssbo;
|
||||
|
||||
public string Name;
|
||||
public readonly Dictionary<string, Bone> BonesByLoweredName;
|
||||
public bool IsAnimated { get; private set; }
|
||||
|
||||
private Transform[][][] _animatedBonesTransform; // [sequence][bone][frame]
|
||||
private readonly Matrix4x4[] _invertedBonesMatrix;
|
||||
public int BoneCount => _invertedBonesMatrix.Length;
|
||||
public bool IsAnimated => _animatedBonesTransform.Length > 0;
|
||||
public readonly int BoneCount;
|
||||
public readonly Dictionary<string, Bone> BonesByLoweredName;
|
||||
|
||||
public Skeleton()
|
||||
{
|
||||
BonesByLoweredName = new Dictionary<string, Bone>();
|
||||
_animatedBonesTransform = Array.Empty<Transform[][]>();
|
||||
_invertedBonesMatrix = Array.Empty<Matrix4x4>();
|
||||
}
|
||||
|
||||
public Skeleton(FReferenceSkeleton referenceSkeleton) : this()
|
||||
{
|
||||
_invertedBonesMatrix = new Matrix4x4[referenceSkeleton.FinalRefBoneInfo.Length];
|
||||
for (int boneIndex = 0; boneIndex < _invertedBonesMatrix.Length; boneIndex++)
|
||||
BoneCount = referenceSkeleton.FinalRefBoneInfo.Length;
|
||||
for (int boneIndex = 0; boneIndex < BoneCount; boneIndex++)
|
||||
{
|
||||
var info = referenceSkeleton.FinalRefBoneInfo[boneIndex];
|
||||
var boneTransform = new Transform
|
||||
@@ -53,128 +50,35 @@ public class Skeleton : IDisposable
|
||||
}
|
||||
|
||||
BonesByLoweredName[info.Name.Text.ToLower()] = bone;
|
||||
|
||||
Matrix4x4.Invert(boneTransform.Matrix, out var inverted);
|
||||
_invertedBonesMatrix[bone.Index] = inverted;
|
||||
}
|
||||
}
|
||||
|
||||
public void Animate(CAnimSet anim, bool rotationOnly)
|
||||
{
|
||||
MapSkeleton(anim);
|
||||
|
||||
_animatedBonesTransform = new Transform[anim.Sequences.Count][][];
|
||||
for (int s = 0; s < _animatedBonesTransform.Length; s++)
|
||||
{
|
||||
var sequence = anim.Sequences[s];
|
||||
_animatedBonesTransform[s] = new Transform[BoneCount][];
|
||||
foreach (var bone in BonesByLoweredName.Values)
|
||||
{
|
||||
_animatedBonesTransform[s][bone.Index] = new Transform[sequence.NumFrames];
|
||||
|
||||
var skeletonBoneIndex = bone.SkeletonIndex;
|
||||
if (sequence.OriginalSequence.FindTrackForBoneIndex(skeletonBoneIndex) < 0)
|
||||
{
|
||||
for (int frame = 0; frame < _animatedBonesTransform[s][bone.Index].Length; frame++)
|
||||
{
|
||||
_animatedBonesTransform[s][bone.Index][frame] = new Transform
|
||||
{
|
||||
Relation = bone.IsRoot ? bone.Rest.Relation :
|
||||
bone.Rest.LocalMatrix * _animatedBonesTransform[s][bone.ParentIndex][frame].Matrix
|
||||
};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bone.AnimatedBySequences.Add(s);
|
||||
for (int frame = 0; frame < _animatedBonesTransform[s][bone.Index].Length; frame++)
|
||||
{
|
||||
var boneOrientation = bone.Rest.Rotation;
|
||||
var bonePosition = bone.Rest.Position;
|
||||
var boneScale = bone.Rest.Scale;
|
||||
|
||||
sequence.Tracks[skeletonBoneIndex].GetBoneTransform(frame, sequence.NumFrames, ref boneOrientation, ref bonePosition, ref boneScale);
|
||||
|
||||
switch (anim.Skeleton.BoneTree[skeletonBoneIndex])
|
||||
{
|
||||
case EBoneTranslationRetargetingMode.Skeleton when !rotationOnly:
|
||||
{
|
||||
var targetTransform = sequence.RetargetBasePose?[skeletonBoneIndex] ?? anim.Skeleton.ReferenceSkeleton.FinalRefBonePose[skeletonBoneIndex];
|
||||
bonePosition = targetTransform.Translation;
|
||||
break;
|
||||
}
|
||||
case EBoneTranslationRetargetingMode.AnimationScaled when !rotationOnly:
|
||||
{
|
||||
var sourceTranslationLength = (bone.Rest.Position / Constants.SCALE_DOWN_RATIO).Size();
|
||||
if (sourceTranslationLength > UnrealMath.KindaSmallNumber)
|
||||
{
|
||||
var targetTranslationLength = sequence.RetargetBasePose?[skeletonBoneIndex].Translation.Size() ?? anim.Skeleton.ReferenceSkeleton.FinalRefBonePose[skeletonBoneIndex].Translation.Size();
|
||||
bonePosition.Scale(targetTranslationLength / sourceTranslationLength);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EBoneTranslationRetargetingMode.AnimationRelative when !rotationOnly:
|
||||
{
|
||||
// can't tell if it's working or not
|
||||
var sourceSkelTrans = bone.Rest.Position / Constants.SCALE_DOWN_RATIO;
|
||||
var refPoseTransform = sequence.RetargetBasePose?[skeletonBoneIndex] ?? anim.Skeleton.ReferenceSkeleton.FinalRefBonePose[skeletonBoneIndex];
|
||||
|
||||
boneOrientation = boneOrientation * FQuat.Conjugate(bone.Rest.Rotation) * refPoseTransform.Rotation;
|
||||
bonePosition += refPoseTransform.Translation - sourceSkelTrans;
|
||||
boneScale *= refPoseTransform.Scale3D * bone.Rest.Scale;
|
||||
boneOrientation.Normalize();
|
||||
break;
|
||||
}
|
||||
case EBoneTranslationRetargetingMode.OrientAndScale when !rotationOnly:
|
||||
{
|
||||
var sourceSkelTrans = bone.Rest.Position / Constants.SCALE_DOWN_RATIO;
|
||||
var targetSkelTrans = sequence.RetargetBasePose?[skeletonBoneIndex].Translation ?? anim.Skeleton.ReferenceSkeleton.FinalRefBonePose[skeletonBoneIndex].Translation;
|
||||
|
||||
if (!sourceSkelTrans.Equals(targetSkelTrans))
|
||||
{
|
||||
var sourceSkelTransLength = sourceSkelTrans.Size();
|
||||
var targetSkelTransLength = targetSkelTrans.Size();
|
||||
if (!UnrealMath.IsNearlyZero(sourceSkelTransLength * targetSkelTransLength))
|
||||
{
|
||||
var sourceSkelTransDir = sourceSkelTrans / sourceSkelTransLength;
|
||||
var targetSkelTransDir = targetSkelTrans / targetSkelTransLength;
|
||||
|
||||
var deltaRotation = FQuat.FindBetweenNormals(sourceSkelTransDir, targetSkelTransDir);
|
||||
var scale = targetSkelTransLength / sourceSkelTransLength;
|
||||
bonePosition = deltaRotation.RotateVector(bonePosition) * scale;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_animatedBonesTransform[s][bone.Index][frame] = new Transform
|
||||
{
|
||||
Relation = bone.IsRoot ? bone.Rest.Relation : _animatedBonesTransform[s][bone.ParentIndex][frame].Matrix,
|
||||
Rotation = boneOrientation,
|
||||
Position = rotationOnly ? bone.Rest.Position : bonePosition * Constants.SCALE_DOWN_RATIO,
|
||||
Scale = boneScale
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MapSkeleton(CAnimSet anim)
|
||||
public void Animate(CAnimSet animation)
|
||||
{
|
||||
IsAnimated = true;
|
||||
ResetAnimatedData();
|
||||
|
||||
// map bones
|
||||
for (int boneIndex = 0; boneIndex < anim.Skeleton.BoneCount; boneIndex++)
|
||||
for (int boneIndex = 0; boneIndex < animation.Skeleton.BoneCount; boneIndex++)
|
||||
{
|
||||
var info = anim.Skeleton.ReferenceSkeleton.FinalRefBoneInfo[boneIndex];
|
||||
var info = animation.Skeleton.ReferenceSkeleton.FinalRefBoneInfo[boneIndex];
|
||||
if (!BonesByLoweredName.TryGetValue(info.Name.Text.ToLower(), out var bone))
|
||||
continue;
|
||||
|
||||
bone.SkeletonIndex = boneIndex;
|
||||
}
|
||||
|
||||
// find playable sequences
|
||||
for (int s = 0; s < animation.Sequences.Count; s++)
|
||||
{
|
||||
var sequence = animation.Sequences[s];
|
||||
foreach (var bone in BonesByLoweredName.Values.Where(bone => sequence.OriginalSequence.FindTrackForBoneIndex(bone.SkeletonIndex) >= 0))
|
||||
{
|
||||
bone.AnimatedBySequences.Add(s);
|
||||
}
|
||||
sequence.Retarget(animation.Skeleton);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
foreach ((var boneName, var bone) in BonesByLoweredName)
|
||||
{
|
||||
@@ -195,7 +99,7 @@ public class Skeleton : IDisposable
|
||||
}
|
||||
|
||||
if (!full) return;
|
||||
_animatedBonesTransform = Array.Empty<Transform[][]>();
|
||||
IsAnimated = false;
|
||||
_ssbo.UpdateRange(BoneCount, Matrix4x4.Identity);
|
||||
}
|
||||
|
||||
@@ -203,11 +107,18 @@ public class Skeleton : IDisposable
|
||||
{
|
||||
_handle = GL.CreateProgram();
|
||||
|
||||
_rest = new BufferObject<Matrix4x4>(BoneCount, BufferTarget.ShaderStorageBuffer);
|
||||
foreach (var bone in BonesByLoweredName.Values)
|
||||
{
|
||||
_rest.Update(bone.Index, bone.Rest.Matrix);
|
||||
}
|
||||
_rest.Unbind();
|
||||
|
||||
_ssbo = new BufferObject<Matrix4x4>(BoneCount, BufferTarget.ShaderStorageBuffer);
|
||||
_ssbo.UpdateRange(BoneCount, Matrix4x4.Identity);
|
||||
}
|
||||
|
||||
public void UpdateAnimationMatrices(Animation animation)
|
||||
public void UpdateAnimationMatrices(Animation animation, bool rotationOnly)
|
||||
{
|
||||
if (!IsAnimated) return;
|
||||
|
||||
@@ -215,17 +126,28 @@ public class Skeleton : IDisposable
|
||||
|
||||
foreach (var bone in BonesByLoweredName.Values)
|
||||
{
|
||||
var (s, f) = GetBoneFrameData(bone, animation);
|
||||
var frameInSequence = Math.Min(f.FloorToInt(), animation.Sequences[s].EndFrame);
|
||||
var nextFrameInSequence = Math.Min(frameInSequence + 1, animation.Sequences[s].EndFrame);
|
||||
var lerpAmount = Math.Clamp(f - frameInSequence, 0, 1);
|
||||
var boneRelation = bone.IsRoot ? bone.Rest.Relation : bone.Rest.LocalMatrix * _ssbo.Get(bone.ParentIndex);
|
||||
if (bone.IsAnimated)
|
||||
{
|
||||
var (s, f) = GetBoneFrameData(bone, animation);
|
||||
var sequence = animation.UnrealAnim.Sequences[s];
|
||||
var boneOrientation = bone.Rest.Rotation;
|
||||
var bonePosition = bone.Rest.Position;
|
||||
var boneScale = bone.Rest.Scale;
|
||||
|
||||
var boneIndex = bone.Index;
|
||||
var matrix = Matrix4x4.Lerp(
|
||||
_animatedBonesTransform[s][boneIndex][frameInSequence].Matrix,
|
||||
_animatedBonesTransform[s][boneIndex][nextFrameInSequence].Matrix,
|
||||
lerpAmount);
|
||||
_ssbo.Update(boneIndex, _invertedBonesMatrix[boneIndex] * matrix);
|
||||
sequence.Tracks[bone.SkeletonIndex].GetBoneTransform(f, sequence.NumFrames, ref boneOrientation, ref bonePosition, ref boneScale);
|
||||
if (!bone.IsRoot) boneRelation = _ssbo.Get(bone.ParentIndex);
|
||||
bonePosition = rotationOnly ? bone.Rest.Position : bonePosition * Constants.SCALE_DOWN_RATIO;
|
||||
|
||||
_ssbo.Update(bone.Index, new Transform
|
||||
{
|
||||
Relation = boneRelation,
|
||||
Rotation = boneOrientation,
|
||||
Position = bonePosition,
|
||||
Scale = boneScale
|
||||
}.Matrix);
|
||||
}
|
||||
else _ssbo.Update(bone.Index, boneRelation);
|
||||
}
|
||||
|
||||
_ssbo.Unbind();
|
||||
@@ -260,17 +182,28 @@ public class Skeleton : IDisposable
|
||||
return (s, f);
|
||||
}
|
||||
|
||||
public Matrix4x4 GetBoneMatrix(Bone bone) => IsAnimated ? bone.Rest.Matrix * _ssbo.Get(bone.Index) : bone.Rest.Matrix;
|
||||
|
||||
public void Render()
|
||||
public Matrix4x4 GetBoneMatrix(Bone bone)
|
||||
{
|
||||
_ssbo.Bind();
|
||||
var anim = _ssbo.Get(bone.Index);
|
||||
_ssbo.Unbind();
|
||||
|
||||
return IsAnimated ? anim : bone.Rest.Matrix;
|
||||
}
|
||||
|
||||
public void Render(Shader shader)
|
||||
{
|
||||
shader.SetUniform("uIsAnimated", IsAnimated);
|
||||
|
||||
_ssbo.BindBufferBase(1);
|
||||
_rest.BindBufferBase(2);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
BonesByLoweredName.Clear();
|
||||
|
||||
_rest?.Dispose();
|
||||
_ssbo?.Dispose();
|
||||
GL.DeleteProgram(_handle);
|
||||
}
|
||||
|
||||
@@ -40,17 +40,15 @@ public class BufferObject<TDataType> : IDisposable where TDataType : unmanaged
|
||||
|
||||
public unsafe void Update(TDataType[] data)
|
||||
{
|
||||
Bind();
|
||||
GL.BufferSubData(_bufferTarget, IntPtr.Zero, data.Length * sizeof(TDataType), data);
|
||||
Unbind();
|
||||
}
|
||||
|
||||
public unsafe TDataType Get(int offset)
|
||||
{
|
||||
TDataType data = default;
|
||||
|
||||
Bind();
|
||||
GL.GetBufferSubData(_bufferTarget, (IntPtr) (offset * sizeof(TDataType)), sizeof(TDataType), ref data);
|
||||
Unbind();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -285,9 +285,7 @@ public class Model : IDisposable
|
||||
|
||||
public void UpdateMorph(int index)
|
||||
{
|
||||
_morphVbo.Bind();
|
||||
_morphVbo.Update(Morphs[index].Vertices);
|
||||
_morphVbo.Unbind();
|
||||
}
|
||||
|
||||
public void AttachModel(Model attachedTo, Socket socket, SocketAttachementInfo info)
|
||||
@@ -398,7 +396,7 @@ public class Model : IDisposable
|
||||
|
||||
_vao.Bind();
|
||||
shader.SetUniform("uMorphTime", MorphTime);
|
||||
if (HasSkeleton) Skeleton.Render();
|
||||
if (HasSkeleton) Skeleton.Render(shader);
|
||||
if (!outline)
|
||||
{
|
||||
shader.SetUniform("uUvCount", UvCount);
|
||||
@@ -434,7 +432,7 @@ public class Model : IDisposable
|
||||
|
||||
_vao.Bind();
|
||||
shader.SetUniform("uMorphTime", MorphTime);
|
||||
if (HasSkeleton) Skeleton.Render();
|
||||
if (HasSkeleton) Skeleton.Render(shader);
|
||||
|
||||
foreach (var section in Sections)
|
||||
{
|
||||
|
||||
@@ -115,7 +115,7 @@ public class Renderer : IDisposable
|
||||
var animSet = skeleton.ConvertAnims(animSequence);
|
||||
var animation = new Animation(animSequence, animSet, guid);
|
||||
maxElapsedTime = animation.TotalElapsedTime;
|
||||
model.Skeleton.Animate(animSet, AnimateWithRotationOnly);
|
||||
model.Skeleton.Animate(animSet);
|
||||
Options.AddAnimation(animation);
|
||||
break;
|
||||
}
|
||||
@@ -124,7 +124,7 @@ public class Renderer : IDisposable
|
||||
var animSet = skeleton.ConvertAnims(animMontage);
|
||||
var animation = new Animation(animMontage, animSet, guid);
|
||||
maxElapsedTime = animation.TotalElapsedTime;
|
||||
model.Skeleton.Animate(animSet, AnimateWithRotationOnly);
|
||||
model.Skeleton.Animate(animSet);
|
||||
Options.AddAnimation(animation);
|
||||
|
||||
foreach (var notifyEvent in animMontage.Notifies)
|
||||
@@ -191,7 +191,7 @@ public class Renderer : IDisposable
|
||||
var animSet = skeleton.ConvertAnims(animComposite);
|
||||
var animation = new Animation(animComposite, animSet, guid);
|
||||
maxElapsedTime = animation.TotalElapsedTime;
|
||||
model.Skeleton.Animate(animSet, AnimateWithRotationOnly);
|
||||
model.Skeleton.Animate(animSet);
|
||||
Options.AddAnimation(animation);
|
||||
break;
|
||||
}
|
||||
@@ -267,7 +267,7 @@ public class Renderer : IDisposable
|
||||
animation.TimeCalculation(Options.Tracker.ElapsedTime);
|
||||
foreach (var guid in animation.AttachedModels.Where(guid => Options.Models[guid].HasSkeleton))
|
||||
{
|
||||
Options.Models[guid].Skeleton.UpdateAnimationMatrices(animation);
|
||||
Options.Models[guid].Skeleton.UpdateAnimationMatrices(animation, AnimateWithRotationOnly);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user