Files
UnrealEngineUWP/Engine/Source/Developer/PhysicsUtilities/Private/SkinnedBoneTriangleCache.cpp
richard talbotwatkin 2cfb317099 LWC-related fix for convex hull decomposition. Assume that all input points will always have float precision.
Also remove unnecessary allocations by allowing the async task to assume ownership of the vertex and index arrays passed to it.
#rb Andy.Davidson, Cedric.Caillaud
#jira UE-125187

#ROBOMERGE-AUTHOR: richard.talbotwatkin
#ROBOMERGE-SOURCE: CL 17448234 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v870-17433530)

[CL 17448242 by richard talbotwatkin in ue5-release-engine-test branch]
2021-09-07 14:54:16 -04:00

168 lines
5.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SkinnedBoneTriangleCache.h"
#include "Components/SkeletalMeshComponent.h"
#include "Rendering/SkeletalMeshModel.h"
#include "Rendering/SkeletalMeshRenderData.h"
FSkinnedBoneTriangleCache::FSkinnedBoneTriangleCache(USkeletalMesh& InSkeletalMesh, const FPhysAssetCreateParams& Params)
: SkeletalMesh(InSkeletalMesh),
StaticLODModel(*SkeletalMesh.GetImportedModel()),
RenderData(*SkeletalMesh.GetResourceForRendering()),
VertexBuffer(RenderData.LODRenderData[0].StaticVertexBuffers.PositionVertexBuffer),
InfluenceHeuristic(Params.VertWeight),
BoneIndexToInfluencedVertices(),
BoneIndexToTriangles(),
LODModelIndexBufferInOrder()
{
}
void FSkinnedBoneTriangleCache::BuildCache()
{
BuildInfluencedIndexSetForEachBone();
BuildOwnedTrianglesSetForEachBone();
}
void FSkinnedBoneTriangleCache::GetVerticesAndIndicesForBone(const int32 BoneIndex, TArray<FVector3f>& OutVertexPositions, TArray<uint32>& OutIndices) const
{
OutVertexPositions.Empty();
OutIndices.Empty();
const FTriangleArray* TriangleArrayPointer = BoneIndexToTriangles.Find(BoneIndex);
if ( !TriangleArrayPointer )
{
return;
}
const FTriangleArray& TrianglesForBone = *TriangleArrayPointer;
const FMatrix ComponentToBoneMatrix = BoneTransformMatrix(BoneIndex);
TMap<FSkinnedVertexIndex, uint32> SkinnedVertIndexToOutputIndex;
for ( int32 CurrentIndex = 0; CurrentIndex < TrianglesForBone.Num(); ++CurrentIndex )
{
const FTriangleIndex TriangleIndex = TrianglesForBone[CurrentIndex];
check(BufferIndexForTri(TriangleIndex, 2) < static_cast<uint32>(LODModelIndexBufferInOrder.Num()));
for ( int32 TriangleVert = 0; TriangleVert < 3; ++TriangleVert )
{
const uint32 BufferIndex = BufferIndexForTri(TriangleIndex, TriangleVert);
const FSkinnedVertexIndex VertIndex = LODModelIndexBufferInOrder[BufferIndex];
// If we haven't seen this vertex before, we need to add it to our output positions.
if ( !SkinnedVertIndexToOutputIndex.Contains(VertIndex) )
{
OutVertexPositions.Add(VertexPosition(VertIndex, ComponentToBoneMatrix));
SkinnedVertIndexToOutputIndex.Add(VertIndex, static_cast<uint32>(OutVertexPositions.Num() - 1));
}
// Map the skinned vert index to the index in our output array.
OutIndices.Add(SkinnedVertIndexToOutputIndex[VertIndex]);
}
}
}
void FSkinnedBoneTriangleCache::BuildInfluencedIndexSetForEachBone()
{
const uint32 TotalVertices = VertexBuffer.GetNumVertices();
for ( FSkinnedVertexIndex VertIndex = 0; VertIndex < TotalVertices; ++VertIndex )
{
AddIndexToInfluencerBoneSets(VertIndex);
}
}
void FSkinnedBoneTriangleCache::AddIndexToInfluencerBoneSets(const FSkinnedVertexIndex VertIndex)
{
int32 SectionIndex;
int32 SoftVertIndex;
RenderData.LODRenderData[0].GetSectionFromVertexIndex(VertIndex, SectionIndex, SoftVertIndex);
const FSkelMeshSection& Section = StaticLODModel.LODModels[0].Sections[SectionIndex];
const FSoftSkinVertex& SoftVert = Section.SoftVertices[SoftVertIndex];
const uint8 MaxWeight = InfluenceHeuristic == EVW_DominantWeight ? SoftVert.GetMaximumWeight() : 0;
for (int32 InfluenceIndex = 0; InfluenceIndex < MAX_TOTAL_INFLUENCES; ++InfluenceIndex)
{
const uint8 InfluenceWeight = SoftVert.InfluenceWeights[InfluenceIndex];
if ( InfluenceHeuristic == EVW_DominantWeight )
{
if ( InfluenceWeight < MaxWeight )
{
continue;
}
}
else
{
if ( InfluenceWeight < 1 )
{
continue;
}
}
const uint8 BoneMapIndex = SoftVert.InfluenceBones[InfluenceIndex];
const int32 ActualBoneIndex = Section.BoneMap[BoneMapIndex];
FInfluencedVerticesSet& InfluencedVertexIndicesForBone = BoneIndexToInfluencedVertices.FindOrAdd(ActualBoneIndex);
InfluencedVertexIndicesForBone.Add(VertIndex);
}
}
void FSkinnedBoneTriangleCache::BuildOwnedTrianglesSetForEachBone()
{
LODModelIndexBufferInOrder.Empty();
RenderData.LODRenderData[0].MultiSizeIndexContainer.GetIndexBuffer(LODModelIndexBufferInOrder);
// We assume that each triplet of indices in the index buffer forms a triangle.
check(LODModelIndexBufferInOrder.Num() % 3 == 0);
const uint32 TotalTriangles = LODModelIndexBufferInOrder.Num() / 3;
for ( FTriangleIndex TriangleIndex = 0; TriangleIndex < TotalTriangles; ++TriangleIndex )
{
AddTriangleIndexToOwnerBoneSets(TriangleIndex);
}
}
void FSkinnedBoneTriangleCache::AddTriangleIndexToOwnerBoneSets(const FTriangleIndex TriangleIndex)
{
check(BufferIndexForTri(TriangleIndex, 2) < static_cast<uint32>(LODModelIndexBufferInOrder.Num()));
const FSkinnedVertexIndex TriangleVertices[3] =
{
LODModelIndexBufferInOrder[BufferIndexForTri(TriangleIndex, 0)],
LODModelIndexBufferInOrder[BufferIndexForTri(TriangleIndex, 1)],
LODModelIndexBufferInOrder[BufferIndexForTri(TriangleIndex, 2)]
};
for ( FBoneIndexToInfluencedVertices::TConstIterator ConstIt = BoneIndexToInfluencedVertices.CreateConstIterator(); ConstIt; ++ConstIt )
{
const FBoneIndex CurrentBoneIndex = ConstIt.Key();
const FInfluencedVerticesSet& InfluencedVerticesForBone = ConstIt.Value();
for (int32 TriangleVert = 0; TriangleVert < 3; ++TriangleVert)
{
if (InfluencedVerticesForBone.Contains(TriangleVertices[TriangleVert]))
{
FTriangleArray& TriangleArrayForBone = BoneIndexToTriangles.FindOrAdd(CurrentBoneIndex);
TriangleArrayForBone.Add(TriangleIndex);
break;
}
}
}
}
FVector3f FSkinnedBoneTriangleCache::VertexPosition(const FSkinnedVertexIndex VertIndex, const FMatrix& ComponentToBoneMatrix) const
{
const FVector3f& Position = VertexBuffer.VertexPosition(VertIndex);
return ComponentToBoneMatrix.TransformPosition(Position);
}
FMatrix FSkinnedBoneTriangleCache::BoneTransformMatrix(FBoneIndex BoneIndex) const
{
return SkeletalMesh.GetRefBasesInvMatrix()[BoneIndex];
}