Fixed an issue with the geometry collection debug draw inital selection when the debug draw components are waiting for some rigid body ids array sync.

#jira UE-76700
#rb none

[CL 7207104 by kriss gossart in 4.23 branch]
This commit is contained in:
kriss gossart
2019-06-27 13:29:00 -04:00
parent 0fa848b651
commit ebe5643d17
4 changed files with 109 additions and 24 deletions

View File

@@ -18,6 +18,10 @@
#include "Components/BillboardComponent.h"
#include "GenericPlatform/GenericPlatformMath.h"
#include "HAL/IConsoleManager.h"
#if INCLUDE_CHAOS
#include "PBDRigidsSolver.h"
#endif // #if INCLUDE_CHAOS
DEFINE_LOG_CATEGORY_STATIC(LogGeometryCollectionDebugDrawActor, Log, All);
@@ -255,11 +259,11 @@ void AGeometryCollectionDebugDrawActor::Tick(float DeltaSeconds)
// Clear all persistent strings and debug lines.
Flush();
UWorld* const World = GetWorld();
#if INCLUDE_CHAOS && WITH_EDITOR
// Check editor pause status and force a dynamic update on all components to catchup with the physics thread
// This can't be done in the GeometryCollectionDebugDrawComponent since it doesn't tick at every frame,
// and can't be done in GeometryCollectionComponent either since it doesn't usually tick while paused.
UWorld* const World = GetWorld();
const bool bIsEditorPaused = World && World->IsPlayInEditor() && World->bDebugPauseExecution;
if (bIsEditorPaused && !bWasEditorPaused)
{
@@ -277,12 +281,56 @@ void AGeometryCollectionDebugDrawActor::Tick(float DeltaSeconds)
}
bWasEditorPaused = bIsEditorPaused;
#endif // #if INCLUDE_CHAOS && WITH_EDITOR
#if GEOMETRYCOLLECTION_DEBUG_DRAW
// Check badly synced collections in case it is still looking for an id match
if (World && SelectedRigidBody.Id != INDEX_NONE && !SelectedRigidBody.GeometryCollection)
{
#if INCLUDE_CHAOS
// Check the id is within the selected solver range
const Chaos::FPBDRigidsSolver* const Solver =
SelectedRigidBody.Solver ? SelectedRigidBody.Solver->GetSolver() : // Selected solver
World->PhysicsScene_Chaos ? World->PhysicsScene_Chaos->GetSolver() : // Default world solver
nullptr; // No solver
const bool IsWithinRange = Solver ? (uint32(SelectedRigidBody.Id) < Solver->GetRigidParticles().Size()): false;
if (!IsWithinRange)
{
UE_LOG(LogGeometryCollectionDebugDrawActor, VeryVerbose, TEXT("The selection id is out of range."));
}
else // Statement continues below...
#endif // #if INCLUDE_CHAOS
{
UE_LOG(LogGeometryCollectionDebugDrawActor, VeryVerbose, TEXT("The selection couldn't be found. The property update will run on all components still containing any invalid rigid body ids."));
// Check for delayed Rigid Body Id array initializations
for (TActorIterator<AGeometryCollectionActor> ActorIterator(World); ActorIterator; ++ActorIterator)
{
if (UGeometryCollectionDebugDrawComponent* const GeometryCollectionDebugDrawComponent = ActorIterator->GetGeometryCollectionDebugDrawComponent())
{
if (GeometryCollectionDebugDrawComponent->GeometryCollectionDebugDrawActor == this &&
GeometryCollectionDebugDrawComponent->HasIncompleteRigidBodyIdSync())
{
const bool bIsSelected = GeometryCollectionDebugDrawComponent->OnDebugDrawPropertiesChanged(false);
if (bIsSelected)
{
SelectedRigidBody.GeometryCollection = *ActorIterator;
UE_LOG(LogGeometryCollectionDebugDrawActor, Verbose, TEXT("Selection found. Stopping continuous property update."));
break;
}
}
}
}
}
}
#endif // #if GEOMETRYCOLLECTION_DEBUG_DRAW
}
void AGeometryCollectionDebugDrawActor::BeginPlay()
{
Super::BeginPlay();
#if ENABLE_DRAW_DEBUG
// Initialize text renderer
const FDebugDrawDelegate DebugDrawTextDelegate = FDebugDrawDelegate::CreateUObject(this, &AGeometryCollectionDebugDrawActor::DebugDrawText);
DebugDrawTextDelegateHandle = UDebugDrawService::Register(TEXT("TextRender"), DebugDrawTextDelegate); // TextRender is an engine show flag that works in both editor and game modes
#endif // #if ENABLE_DRAW_DEBUG
@@ -485,7 +533,9 @@ void AGeometryCollectionDebugDrawActor::PostEditChangeProperty(FPropertyChangedE
bool bForceVisibilityUpdate = false;
if (PropertyName == GET_MEMBER_NAME_CHECKED(FGeometryCollectionDebugDrawActorSelectedRigidBody, Solver )) { GeometryCollectionDebugDrawActorCVars::SelectedRigidBodySolver ->Set(*SelectedRigidBody.GetSolverName(), SetBy); }
if (PropertyName == GET_MEMBER_NAME_CHECKED(AGeometryCollectionDebugDrawActor, SelectedRigidBody )) { GeometryCollectionDebugDrawActorCVars::SelectedRigidBodySolver ->Set(*SelectedRigidBody.GetSolverName(), SetBy);
GeometryCollectionDebugDrawActorCVars::SelectedRigidBodyId ->Set( SelectedRigidBody.Id , SetBy); }
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FGeometryCollectionDebugDrawActorSelectedRigidBody, Solver )) { GeometryCollectionDebugDrawActorCVars::SelectedRigidBodySolver ->Set(*SelectedRigidBody.GetSolverName(), SetBy); }
else if (PropertyName == GET_MEMBER_NAME_CHECKED(FGeometryCollectionDebugDrawActorSelectedRigidBody, Id )) { GeometryCollectionDebugDrawActorCVars::SelectedRigidBodyId ->Set( SelectedRigidBody.Id , SetBy); }
else if (PropertyName == GET_MEMBER_NAME_CHECKED(AGeometryCollectionDebugDrawActor, bDebugDrawWholeCollection)) { GeometryCollectionDebugDrawActorCVars::DebugDrawWholeCollection->Set(int32(bDebugDrawWholeCollection ), SetBy); }
else if (PropertyName == GET_MEMBER_NAME_CHECKED(AGeometryCollectionDebugDrawActor, bDebugDrawHierarchy )) { GeometryCollectionDebugDrawActorCVars::DebugDrawHierarchy ->Set(int32(bDebugDrawHierarchy ), SetBy); }

View File

@@ -7,6 +7,7 @@
#include "GeometryCollection/GeometryCollectionComponent.h"
#include "GeometryCollection/GeometryCollectionObject.h"
#include "GeometryCollection/GeometryCollectionDebugDrawActor.h"
#include "GeometryCollection/GeometryCollection.h"
#if INCLUDE_CHAOS
#include "SolverObjects/GeometryCollectionPhysicsObject.h"
#endif // #if INCLUDE_CHAOS
@@ -109,6 +110,7 @@ UGeometryCollectionDebugDrawComponent::UGeometryCollectionDebugDrawComponent(con
, SelectedRigidBodyId(INDEX_NONE)
, SelectedTransformIndex(INDEX_NONE)
, HiddenTransformIndex(INDEX_NONE)
, bHasIncompleteRigidBodyIdSync(false)
, SelectedChaosSolver(nullptr)
#endif // #if GEOMETRYCOLLECTION_DEBUG_DRAW
{
@@ -148,7 +150,7 @@ void UGeometryCollectionDebugDrawComponent::BeginPlay()
}
// Update the visibility and tick status depending on the debug draw properties currently selected
OnDebugDrawPropertiesChanged(true);
OnDebugDrawPropertiesChanged(false);
#if INCLUDE_CHAOS
// Find or create level set renderer
@@ -540,6 +542,7 @@ void UGeometryCollectionDebugDrawComponent::DebugDrawTick()
void UGeometryCollectionDebugDrawComponent::UpdateSelectedTransformIndex()
{
check(GeometryCollectionComponent);
// No actor, no selection
if (!GeometryCollectionDebugDrawActor)
{
@@ -548,7 +551,8 @@ void UGeometryCollectionDebugDrawComponent::UpdateSelectedTransformIndex()
}
// Check whether the selected rigid body id, or solver has changed
if (SelectedRigidBodyId == GeometryCollectionDebugDrawActor->SelectedRigidBody.Id &&
if (!bHasIncompleteRigidBodyIdSync &&
SelectedRigidBodyId == GeometryCollectionDebugDrawActor->SelectedRigidBody.Id &&
SelectedChaosSolver == GeometryCollectionDebugDrawActor->SelectedRigidBody.Solver)
{
return;
@@ -569,32 +573,59 @@ void UGeometryCollectionDebugDrawComponent::UpdateSelectedTransformIndex()
// Check rigid body id sync
// Note that this test alone isn't enough to ensure that the rigid body ids are valid.
const TManagedArray<int32>& RigidBodyIds = GeometryCollectionComponent->RigidBodyIds;
if (RigidBodyIds.Num() == 0) { return; }
// Find the matching transform if any
bool bInvalidRigidBodyIdsFound = false;
for (int32 i = 0; i < RigidBodyIds.Num(); ++i)
if (RigidBodyIds.Num() == 0)
{
if (RigidBodyIds[i] == INDEX_NONE)
bHasIncompleteRigidBodyIdSync = !!GeometryCollectionComponent->GetTransformArray().Num();
UE_CLOG(bHasIncompleteRigidBodyIdSync && GetOwner(), LogGeometryCollectionDebugDraw, Verbose, TEXT("UpdateSelectedTransformIndex(): Empty RigidBodyIds array for actor %s."), *GetOwner()->GetName());
return;
}
// Find the matching transform if any (and also check the sync completion status)
bHasIncompleteRigidBodyIdSync = false;
const TManagedArray<TSet<int32>>& ChildrenRest = GeometryCollectionComponent->GetChildrenArrayRest();
const TManagedArray<TSet<int32>>& Children = GeometryCollectionComponent->GetChildrenArray();
for (int32 TransformIndex = 0; TransformIndex < RigidBodyIds.Num(); ++TransformIndex)
{
// Is this the selected id?
if (RigidBodyIds[TransformIndex] == GeometryCollectionDebugDrawActor->SelectedRigidBody.Id)
{
bInvalidRigidBodyIdsFound = true;
}
else if (RigidBodyIds[i] == GeometryCollectionDebugDrawActor->SelectedRigidBody.Id)
{
SelectedTransformIndex = i;
SelectedTransformIndex = TransformIndex;
bHasIncompleteRigidBodyIdSync = false; // Found it, the wait for a sync can be canceled
break;
}
// Check the reason behind any invalid index
if (RigidBodyIds[TransformIndex] == INDEX_NONE)
{
// Look for detached clusters in order to differentiate un-synced vs empty cluster rigid body ids.
int32 ChildTransformIndex = TransformIndex;
while (const TSet<int32>::TConstIterator ChildTransformIterator = Children[ChildTransformIndex].CreateConstIterator())
{
// Go down to the cluster's leaf level through the first child
ChildTransformIndex = *ChildTransformIterator;
}
// If this is a leaf bone, it can not be a detached cluster so it should have a valid rigid body
// In which case the sync has yet to happen and it might be worth trying this again later
if (!ChildrenRest[ChildTransformIndex].Num())
{
bHasIncompleteRigidBodyIdSync = true;
UE_CLOG(GetOwner(), LogGeometryCollectionDebugDraw, VeryVerbose, TEXT("UpdateSelectedTransformIndex(): Invalid rigid body id for actor %s, TransformIndex %d."), *GetOwner()->GetName(), TransformIndex);
}
else
{
// This should match the SimulationType == FST_CLUSTERED or IsClustered(int32 Element)
ensure(GeometryCollectionComponent->GetSimulationTypeArrayRest()[ChildTransformIndex] == FGeometryCollection::ESimulationTypes::FST_Clustered);
UE_CLOG(GetOwner(), LogGeometryCollectionDebugDraw, VeryVerbose, TEXT("UpdateSelectedTransformIndex(): Found empty cluster for actor %s, TransformIndex %d."), *GetOwner()->GetName(), TransformIndex);
}
}
}
UE_CLOG(bHasIncompleteRigidBodyIdSync && GetOwner(), LogGeometryCollectionDebugDraw, Verbose, TEXT("UpdateSelectedTransformIndex(): Invalid RigidBodyIds array elements for actor %s."), *GetOwner()->GetName());
// Update selected rigid body index and solver
// This needs to be done to mark the change of selection as already processed, and only when no bad ids have been found.
// Otherwise updating these would prevent finding the selected transform at the next call, once the remaining ids have fully synced.
// If a selection has been found, the update must be made, even if some invalid ids have been detected.
if (SelectedTransformIndex != INDEX_NONE || !bInvalidRigidBodyIdsFound)
{
SelectedRigidBodyId = GeometryCollectionDebugDrawActor->SelectedRigidBody.Id;
SelectedChaosSolver = GeometryCollectionDebugDrawActor->SelectedRigidBody.Solver;
}
SelectedRigidBodyId = GeometryCollectionDebugDrawActor->SelectedRigidBody.Id;
SelectedChaosSolver = GeometryCollectionDebugDrawActor->SelectedRigidBody.Solver;
}
int32 UGeometryCollectionDebugDrawComponent::CountFaces(int32 TransformIndex, bool bDebugDrawClustering) const

View File

@@ -242,6 +242,9 @@ public:
/** Update selection and visibility after a change in cluster. Only handled when the debug drawing is active (the component is ticking). */
void OnClusterChanged();
/** Return whether the geometry collection rigid body id array is not completely initialized. This can happen when running the physics multithreaded. */
FORCEINLINE bool HasIncompleteRigidBodyIdSync() const { return bHasIncompleteRigidBodyIdSync; }
private:
/** Recursively compute global cluster transforms. Only gives geometry transforms for the leaf nodes, mid-level transforms are those of the clusters. */
void ComputeClusterTransforms(int32 Index, TArray<bool>& IsComputed, TArray<FTransform>& InOutGlobalTransforms);
@@ -291,6 +294,7 @@ private:
int32 SelectedRigidBodyId;
int32 SelectedTransformIndex;
int32 HiddenTransformIndex;
bool bHasIncompleteRigidBodyIdSync;
AChaosSolverActor* SelectedChaosSolver;
#endif // #if GEOMETRYCOLLECTION_DEBUG_DRAW
};