GetBoneTransform at runtime but it's flickering now, for later me

This commit is contained in:
Asval
2023-08-12 06:34:12 +02:00
parent 250b199b2a
commit d97f570328
11 changed files with 149 additions and 202 deletions

View File

@@ -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
}

View File

@@ -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];

View File

@@ -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;

View File

@@ -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;

View File

@@ -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}" />

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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)
{

View File

@@ -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);
}
}