Files
UnrealEngine/Engine/Shaders/Private/Skinning/AnimBankEval.usf
2025-05-18 13:04:45 +08:00

188 lines
6.9 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "/Engine/Public/Platform.ush"
#include "/Engine/Private/Common.ush"
#include "/Engine/Private/SceneData.ush"
#include "/Engine/Private/BoneTransform.ush"
#include "/Engine/Private/Visualization.ush"
#include "/Engine/Private/Nanite/NaniteDataDecode.ush"
#include "/Engine/Shared/SkinningDefinitions.h"
ByteAddressBuffer HeaderBuffer;
ByteAddressBuffer BankBuffer;
ByteAddressBuffer SrcTransformBuffer;
RWByteAddressBuffer TransformBuffer;
float DeltaTime;
struct FKeyIndices
{
int KeyIndex1;
int KeyIndex2;
float Alpha;
};
FKeyIndices GetKeyIndicesFromTime(float Time, int KeyCount, float SequenceLength, float FramesPerSecond)
{
FKeyIndices Indices;
// Check for 1-frame, before-first-frame and after-last-frame cases.
if (Time <= 0.0f || KeyCount == 1)
{
Indices.KeyIndex1 = 0;
Indices.KeyIndex2 = 0;
Indices.Alpha = 0.0f;
}
else if (Time >= SequenceLength)
{
Indices.KeyIndex1 = KeyCount - 1;
Indices.KeyIndex2 = 0;
Indices.Alpha = 0.0f;
}
else
{
// Calculate the frames per second if we didn't provide any.
if (FramesPerSecond <= 0.0f)
{
const int FrameCount = KeyCount - 1;
FramesPerSecond = FrameCount / SequenceLength;
}
const float KeyPos = Time * FramesPerSecond;
// Find the integer part (ensuring within range) and that gives us the 'starting' key index.
int IntegerPart = int(KeyPos);
IntegerPart -= ((float)IntegerPart > KeyPos);
Indices.KeyIndex1 = clamp(IntegerPart, 0, KeyCount - 1);
// The alpha (fractional part) is just the remainder.
Indices.Alpha = KeyPos - (float)Indices.KeyIndex1;
Indices.KeyIndex2 = Indices.KeyIndex1 + 1;
// If we have gone over the end, do different things in case of looping
if (Indices.KeyIndex2 == KeyCount)
{
Indices.KeyIndex2 = Indices.KeyIndex1;
}
}
return Indices;
}
[numthreads(BONES_PER_GROUP, 1, 1)]
void BankEvaluateCS(uint3 GroupId : SV_GroupID, uint GroupIndex : SV_GroupIndex)
{
const uint BoneBlock = GroupId.x;
const uint LocalBoneIndex = GroupIndex;
const FBankBlockHeader BoneBlockHeader = HeaderBuffer.Load<FBankBlockHeader>(BoneBlock * uint(sizeof(FBankBlockHeader)));
if (LocalBoneIndex < BoneBlockHeader.BlockBoneCount)
{
const uint BankRecordHeaderOffset = BoneBlockHeader.BankRecordOffset;
const FBankRecordHeader BankRecordHeader = BankBuffer.Load<FBankRecordHeader>(BankRecordHeaderOffset);
if (BankRecordHeader.Playing)
{
const uint BoneTransformSize = (uint)select(BankRecordHeader.HasScale != 0, sizeof(FBoneTransformWithScale), sizeof(FBoneTransform));
const uint BoneTransformRange = BankRecordHeader.BoneCount * BoneTransformSize;
const uint MappingKeyOffset = BankRecordHeaderOffset + (uint)sizeof(FBankRecordHeader);
const uint BoneKeyOffset = MappingKeyOffset + BoneTransformRange;
const float SampleInterval = 1.0f / BankRecordHeader.SampleRate;
const float TrackLength = (BankRecordHeader.FrameCount - 1) * SampleInterval;
float Time = fmod(BankRecordHeader.CurrentTime, TrackLength);
if (Time < 0.0f)
{
Time += TrackLength;
}
const float FramesPerSecond = -1.0f;
FKeyIndices KeyIndices = GetKeyIndicesFromTime(Time, BankRecordHeader.FrameCount, TrackLength, FramesPerSecond);
if (!BankRecordHeader.Interpolating)
{
// Forcing alpha to zero disables pose interpolation (interpolation method is "step")
KeyIndices.Alpha = 0.0f;
}
const uint BoneIndex = (BoneBlockHeader.BlockLocalIndex * BONES_PER_GROUP) + LocalBoneIndex;
// TODO: Scale version
FBoneTransform InvGlobalRefPoseTransform = BankBuffer.Load<FBoneTransform>(MappingKeyOffset + ((uint)BoneIndex * BoneTransformSize));
FBoneTransform MeshGlobalAnimPoseTransform;
if (KeyIndices.Alpha <= 0.0f)
{
const uint KeyIndex = (KeyIndices.KeyIndex1 * BankRecordHeader.BoneCount) + BoneIndex;
MeshGlobalAnimPoseTransform = BankBuffer.Load<FBoneTransform>(BoneKeyOffset + (KeyIndex * BoneTransformSize));
QuatNormalize(MeshGlobalAnimPoseTransform.Rotation);
}
else if (KeyIndices.Alpha >= 1.0f)
{
const uint KeyIndex = (KeyIndices.KeyIndex2 * BankRecordHeader.BoneCount) + BoneIndex;
MeshGlobalAnimPoseTransform = BankBuffer.Load<FBoneTransform>(BoneKeyOffset + (KeyIndex * BoneTransformSize));
QuatNormalize(MeshGlobalAnimPoseTransform.Rotation);
}
else
{
const uint KeyIndexA = (KeyIndices.KeyIndex1 * BankRecordHeader.BoneCount) + BoneIndex;
const uint KeyIndexB = (KeyIndices.KeyIndex2 * BankRecordHeader.BoneCount) + BoneIndex;
FBoneTransform MeshGlobalTransformA = BankBuffer.Load<FBoneTransform>(BoneKeyOffset + (KeyIndexA * BoneTransformSize));
FBoneTransform MeshGlobalTransformB = BankBuffer.Load<FBoneTransform>(BoneKeyOffset + (KeyIndexB * BoneTransformSize));
// Ensure rotations are normalized before blending
QuatNormalize(MeshGlobalTransformA.Rotation);
QuatNormalize(MeshGlobalTransformB.Rotation);
// NOTE: Rotation will already be normalized
MeshGlobalAnimPoseTransform = BlendBoneTransforms(MeshGlobalTransformA, MeshGlobalTransformB, KeyIndices.Alpha);
}
MeshGlobalAnimPoseTransform = MultiplyBoneTransform(InvGlobalRefPoseTransform, MeshGlobalAnimPoseTransform);
const float4x4 CurrentTransform44 = MatrixFromBoneTransform(MeshGlobalAnimPoseTransform);
const float3x4 CurrentTransform = (float3x4)transpose(CurrentTransform44);
StoreCompressedBoneTransform(TransformBuffer, BankRecordHeader.TransformOffset, BoneIndex, transpose(CurrentTransform));
}
}
}
[numthreads(BONES_PER_GROUP, 1, 1)]
void BankScatterCS(uint3 GroupId : SV_GroupID, uint GroupIndex : SV_GroupIndex)
{
const uint GlobalBlockIndex = GroupId.x;
const uint LocalTransformIndex = GroupIndex;
const FBankScatterHeader BlockHeader = HeaderBuffer.Load<FBankScatterHeader>(GlobalBlockIndex * uint(sizeof(FBankScatterHeader)));
if (LocalTransformIndex < BlockHeader.BlockTransformCount)
{
float4x3 PreviousTransform;
float4x3 CurrentTransform;
BRANCH
if (BlockHeader.BlockSrcTransformOffset == ~uint(0))
{
PreviousTransform[0] = float3(1.0f, 0.0f, 0.0f);
PreviousTransform[1] = float3(0.0f, 1.0f, 0.0f);
PreviousTransform[2] = float3(0.0f, 0.0f, 1.0f);
PreviousTransform[3] = float3(0.0f, 0.0f, 0.0f);
CurrentTransform[0] = float3(1.0f, 0.0f, 0.0f);
CurrentTransform[1] = float3(0.0f, 1.0f, 0.0f);
CurrentTransform[2] = float3(0.0f, 0.0f, 1.0f);
CurrentTransform[3] = float3(0.0f, 0.0f, 0.0f);
}
else
{
PreviousTransform = LoadCompressedBoneTransform(TransformBuffer, BlockHeader.BlockDstTransformOffset, LocalTransformIndex);
CurrentTransform = LoadCompressedBoneTransform(SrcTransformBuffer, BlockHeader.BlockSrcTransformOffset, LocalTransformIndex);
}
StoreCompressedBoneTransform(TransformBuffer, BlockHeader.BlockDstTransformOffset, LocalTransformIndex, CurrentTransform);
StoreCompressedBoneTransform(TransformBuffer, BlockHeader.BlockDstTransformOffset, BlockHeader.TotalTransformCount + LocalTransformIndex, PreviousTransform);
}
}