// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "SpanAllocator.h" #include "Containers/Map.h" #include "SceneExtensions.h" #include "RendererPrivateUtils.h" #include "Matrix3x4.h" #include "Delegates/DelegateCombinations.h" #include "Delegates/Delegate.h" #include "GameTime.h" #define ENABLE_SKELETON_DEBUG_NAME (UE_BUILD_DEBUG | UE_BUILD_DEVELOPMENT) struct FSkeletonBatch { #if ENABLE_SKELETON_DEBUG_NAME FName SkeletonName = TEXT("Invalid"); #endif FGuid SkeletonGuid; uint32 MaxBoneTransforms = 0u; uint32 UniqueAnimationCount = 0u; }; struct FSkeletonBatchKey { #if ENABLE_SKELETON_DEBUG_NAME FName SkeletonName = TEXT("Invalid"); #endif FGuid SkeletonGuid; FGuid TransformProviderId; bool operator == (const FSkeletonBatchKey& InOther) const { return SkeletonGuid == InOther.SkeletonGuid && TransformProviderId == InOther.TransformProviderId; } bool operator != (const FSkeletonBatchKey& InOther) const { return !(*this == InOther); } friend inline SIZE_T GetTypeHash(const FSkeletonBatchKey& InKey) { return HashCombine(GetTypeHash(InKey.SkeletonGuid), GetTypeHash(InKey.TransformProviderId)); } }; class FSkinningSceneExtensionProxy; class FSkinningTransformProvider : public ISceneExtension { DECLARE_SCENE_EXTENSION(RENDERER_API, FSkinningTransformProvider); public: typedef FGuid FProviderId; struct FProviderRange { FProviderId Id; uint32 Count; uint32 Offset; }; struct FProviderIndirection { FProviderIndirection(uint32 InIndex, uint32 InTransformOffset, uint32 InHierarchyOffset) : Index(InIndex) , TransformOffset(InTransformOffset) , HierarchyOffset(InHierarchyOffset) {} uint32 Index = 0; uint32 TransformOffset = 0; uint32 HierarchyOffset = 0; }; struct FProviderContext { FProviderContext( const TConstArrayView InPrimitives, const TConstArrayView InProxies, const TConstArrayView InIndirections, const TConstArrayView InSkeletonBatches, float InDeltaTime, FRDGBuilder& InGraphBuilder, FRDGBufferRef InTransformBuffer, FRDGBufferSRVRef InHierarchyBufferSRV ) : Primitives(InPrimitives) , Proxies(InProxies) , Indirections(InIndirections) , SkeletonBatches(InSkeletonBatches) , GraphBuilder(InGraphBuilder) , TransformBuffer(InTransformBuffer) , HierarchyBufferSRV(InHierarchyBufferSRV) , DeltaTime(InDeltaTime) { } TConstArrayView Primitives; TConstArrayView Proxies; TConstArrayView Indirections; TConstArrayView SkeletonBatches; FRDGBuilder& GraphBuilder; FRDGBufferRef TransformBuffer; FRDGBufferSRVRef HierarchyBufferSRV; float DeltaTime = 0.0f; }; DECLARE_DELEGATE_OneParam(FOnProvideTransforms, FProviderContext&); public: using ISceneExtension::ISceneExtension; static bool ShouldCreateExtension(FScene& InScene); RENDERER_API void RegisterProvider(const FProviderId& Id, const FOnProvideTransforms& Delegate, bool bUsesSkeletonBatches); RENDERER_API void UnregisterProvider(const FProviderId& Id); void Broadcast(const TConstArrayView Ranges, FProviderContext& Context); inline bool HasProviders() const { return !Providers.IsEmpty(); } inline TArray GetProviderIds() const { TArray Ids; Ids.Reserve(Providers.Num()); for (const FTransformProvider& Provider : Providers) { Ids.Add(Provider.Id); } return Ids; } inline TArray GetPrimitiveProviderIds() const { TArray Ids; Ids.Reserve(Providers.Num()); for (const FTransformProvider& Provider : Providers) { if (!Provider.bUsesSkeletonBatches) { Ids.Add(Provider.Id); } } return Ids; } inline TArray GetSkeletonProviderIds() const { TArray Ids; Ids.Reserve(Providers.Num()); for (const FTransformProvider& Provider : Providers) { if (Provider.bUsesSkeletonBatches) { Ids.Add(Provider.Id); } } return Ids; } private: struct FTransformProvider { FProviderId Id; FOnProvideTransforms Delegate; uint8 bUsesSkeletonBatches : 1 = false; }; TArray Providers; }; RENDERER_API const FSkinningTransformProvider::FProviderId& GetRefPoseProviderId(); RENDERER_API const FSkinningTransformProvider::FProviderId& GetAnimRuntimeProviderId();