Merging conflict by hand.

/src/ROBOMERGE_ENGINE_Dev_Networking/Engine/Plugins/Experimental/GeometryCollectionPlugin/Source/GeometryCollectionEditor/GeometryCollectionEditor.Build.cs - merging //UE4/Main/Engine/Plugins/Experimental/GeometryCollectionPlugin/Source/GeometryCollectionEditor/GeometryCollectionEditor.Build.cs#1
/src/ROBOMERGE_ENGINE_Dev_Networking/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/PBDCollisionConstraint.cpp - merging //UE4/Main/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/PBDCollisionConstraint.cpp#1
/src/ROBOMERGE_ENGINE_Dev_Networking/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/PBDRigidsEvolution.cpp - merging //UE4/Main/Engine/Source/Runtime/Experimental/Chaos/Private/Chaos/PBDRigidsEvolution.cpp#1


--------------------------------------
Copying //UE4/Dev-Physics to //UE4/Dev-Main.

#rb none
#lockdown Nick.Penwarden

#ROBOMERGE-OWNER: ryan.gerleve
#ROBOMERGE-AUTHOR: michael.lentine
#ROBOMERGE-SOURCE: CL 4653110 in //UE4/Main/...
#ROBOMERGE-BOT: ENGINE (Main -> Dev-Networking)

[CL 4653305 by ryan gerleve in Dev-Networking branch]
This commit is contained in:
ryan gerleve
2018-12-12 11:43:42 -05:00
parent 9cf33ae7ca
commit 9843ebaa9f
770 changed files with 82159 additions and 17577 deletions

View File

@@ -0,0 +1,38 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
namespace UnrealBuildTool.Rules
{
public class GeometryCollectionEngine : ModuleRules
{
public GeometryCollectionEngine(ReadOnlyTargetRules Target) : base(Target)
{
PrivateIncludePaths.Add("Runtime/Experimental/GeometryCollectionEngine/Private");
PublicIncludePaths.Add(ModuleDirectory + "/Public");
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"Engine",
"RenderCore",
"RHI",
"Chaos",
"ChaosSolvers",
"PhysX",
"APEX",
"FieldSystemCore",
"FieldSystemEngine",
"GeometryCollectionCore",
"GeometryCollectionSimulationCore",
"ChaosSolverEngine"
}
);
if(Target.bBuildEditor)
{
PrivateDependencyModuleNames.Add("UnrealEd");
}
}
}
}

View File

@@ -0,0 +1,126 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
GeometryCollectionActor.cpp: AGeometryCollectionActor methods.
=============================================================================*/
#if INCLUDE_CHAOS
#include "GeometryCollection/GeometryCollectionActor.h"
#include "Chaos/Utilities.h"
#include "Chaos/Plane.h"
#include "Chaos/Box.h"
#include "Chaos/Sphere.h"
#include "Chaos/PerParticleGravity.h"
#include "Chaos/ImplicitObject.h"
#include "Engine/SkeletalMesh.h"
#include "GeometryCollection/GeometryCollectionAlgo.h"
#include "GeometryCollection/GeometryCollectionComponent.h"
#include "GeometryCollection/GeometryCollectionUtility.h"
#include "GeometryCollection/GeometryCollectionBoneNode.h"
#include "Math/Box.h"
#include "Physics/PhysicsInterfaceCore.h"
DEFINE_LOG_CATEGORY_STATIC(AGeometryCollectionActorLogging, Log, All);
AGeometryCollectionActor::AGeometryCollectionActor(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
UE_LOG(AGeometryCollectionActorLogging, Verbose, TEXT("AGeometryCollectionActor::AGeometryCollectionActor()"));
GeometryCollectionComponent = CreateDefaultSubobject<UGeometryCollectionComponent>(TEXT("GeometryCollectionComponent0"));
RootComponent = GeometryCollectionComponent;
#if GEOMETRYCOLLECTION_DEBUG_DRAW
GeometryCollectionDebugDrawComponent = CreateDefaultSubobject<UGeometryCollectionDebugDrawComponent>(TEXT("GeometryCollectionDrawComponent0"));
GeometryCollectionDebugDrawComponent->GeometryCollectionComponent = GeometryCollectionComponent;
#else
GeometryCollectionDebugDrawComponent = nullptr;
#endif
PrimaryActorTick.bCanEverTick = true;
SetActorTickEnabled(true);
}
void AGeometryCollectionActor::Tick(float DeltaTime)
{
UE_LOG(AGeometryCollectionActorLogging, Verbose, TEXT("AGeometryCollectionActor::Tick()"));
if (GeometryCollectionComponent)
{
GeometryCollectionComponent->SetRenderStateDirty();
}
}
const Chaos::PBDRigidsSolver* GetSolver(const AGeometryCollectionActor& GeomCollectionActor)
{
return GeomCollectionActor.GetGeometryCollectionComponent()->ChaosSolverActor != nullptr ? GeomCollectionActor.GetGeometryCollectionComponent()->ChaosSolverActor->GetSolver() : FPhysScene_Chaos::GetInstance()->GetSolver();
}
bool LowLevelRaycastImp(const Chaos::TVector<float, 3>& Start, const Chaos::TVector<float, 3>& Dir, float DeltaMag, const AGeometryCollectionActor& GeomCollectionActor, FHitResult& OutHit)
{
using namespace Chaos;
//todo(ocohen): need to add thread safety / lock semantics
const TManagedArray<int32>& RigidBodyIdArray = GeomCollectionActor.GetGeometryCollectionComponent()->GetRigidBodyIdArray();
const TSharedPtr<FPhysScene_Chaos> Scene = GeomCollectionActor.GetGeometryCollectionComponent()->GetPhysicsScene();
ensure(Scene);
const Chaos::PBDRigidsSolver* Solver = GetSolver(GeomCollectionActor);
ensure(Solver);
const TPBDRigidParticles<float, 3>& Particles = Solver->GetRigidParticles(); //todo(ocohen): should these just get passed in instead of hopping through scene?
for (int32 Idx = 0; Idx < RigidBodyIdArray.Num(); ++Idx)
{
const int32 RigidBodyIdx = RigidBodyIdArray[Idx];
const TRigidTransform<float, 3> TM(Particles.X(RigidBodyIdx), Particles.R(RigidBodyIdx));
const TVector<float, 3> StartLocal = TM.InverseTransformPositionNoScale(Start);
const TVector<float, 3> DirLocal = TM.InverseTransformVectorNoScale(Dir);
const TVector<float, 3> EndLocal = StartLocal + DirLocal * DeltaMag; //todo(ocohen): apeiron just undoes this later, we should fix the API
const TImplicitObject<float, 3>* Object = Particles.Geometry(RigidBodyIdx); //todo(ocohen): can this ever be null?
Pair<TVector<float, 3>, bool> Result = Object->FindClosestIntersection(StartLocal, EndLocal, /*Thickness=*/0.f);
if (Result.Second) //todo(ocohen): once we do more than just a bool we need to get the closest point
{
const float Distance = (Result.First - StartLocal).Size();
OutHit.Actor = const_cast<AGeometryCollectionActor*>(&GeomCollectionActor);
OutHit.Component = GeomCollectionActor.GetGeometryCollectionComponent();
OutHit.bBlockingHit = true;
OutHit.Distance = Distance;
OutHit.Time = Distance / (EndLocal - StartLocal).Size();
OutHit.Location = TM.TransformPositionNoScale(Result.First);
OutHit.ImpactPoint = OutHit.Location;
const TVector<float, 3> LocalNormal = Object->Normal(Result.First);
OutHit.ImpactNormal = TM.TransformVectorNoScale(LocalNormal);
OutHit.Normal = OutHit.ImpactNormal;
return true;
}
}
return false;
}
bool AGeometryCollectionActor::RaycastSingle(FVector Start, FVector End, FHitResult& OutHit) const
{
if (GeometryCollectionComponent)
{
OutHit = FHitResult();
OutHit.TraceStart = Start;
OutHit.TraceEnd = End;
const FVector Delta = (End - Start);
const float DeltaMag = Delta.Size();
if (DeltaMag > KINDA_SMALL_NUMBER)
{
const FVector Dir = Delta / DeltaMag;
return LowLevelRaycastImp(Start, Dir, DeltaMag, *this, OutHit);
}
}
return false;
}
#endif

View File

@@ -0,0 +1,217 @@
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
GeometryCollectionActor.cpp: AGeometryCollectionActor methods.
=============================================================================*/
#include "GeometryCollection/GeometryCollectionActor.h"
#if !INCLUDE_CHAOS
#include "GeometryCollection/GeometryCollectionAlgo.h"
#include "GeometryCollection/GeometryCollectionComponent.h"
#include "GeometryCollection/GeometryCollectionUtility.h"
#include "GeometryCollection/GeometryCollectionBoneNode.h"
#include "GeometryCollection/GeometryCollectionObject.h"
#include "Engine/SkeletalMesh.h"
#include "Math/Box.h"
#include "Physics/PhysicsInterfaceCore.h"
#include "Physics/ImmediatePhysics/ImmediatePhysicsActorHandle.h"
#include "Chaos/Utilities.h"
#include "Chaos/Plane.h"
#include "Chaos/Box.h"
#include "Chaos/Sphere.h"
DEFINE_LOG_CATEGORY_STATIC(AGeometryCollectionActorLogging, Log, All);
FTransform TransformMatrix(const FTransform& A, const FTransform& B) { return B * A; }
AGeometryCollectionActor::AGeometryCollectionActor(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, bInitializedState(false)
, RigidBodyIdArray(new TManagedArray<int32>())
, CenterOfMassArray(new TManagedArray<FVector>())
{
GeometryCollectionComponent = CreateDefaultSubobject<UGeometryCollectionComponent>(TEXT("GeometryCollectionComponent0"));
RootComponent = GeometryCollectionComponent;
AGeometryCollectionActor::bInitializedState = false;
PrimaryActorTick.bCanEverTick = true;
SetActorTickEnabled(true);
}
void AGeometryCollectionActor::Tick(float DeltaTime)
{
UE_LOG(AGeometryCollectionActorLogging, Verbose, TEXT("AGeometryCollectionActor::Tick()"));
UGeometryCollection* Collection = GeometryCollectionComponent->GetDynamicCollection();
if (Collection && !AGeometryCollectionActor::bInitializedState)
{
Collection->GetGeometryCollection()->AddAttribute<int32>("RigidBodyID", FGeometryCollection::TransformGroup, RigidBodyIdArray);
Collection->GetGeometryCollection()->AddAttribute<FVector>("CenterOfMass", FGeometryCollection::TransformGroup, CenterOfMassArray);
Scene.SetKinematicUpdateFunction([this](FSolverCallbacks::FParticlesType& Particles, const float Dt, const float Time, const int32 Index) {
});
Scene.SetStartFrameFunction([this](const float StartFrame) {
StartFrameCallback(StartFrame);
});
Scene.SetEndFrameFunction([this](const float EndFrame) {
EndFrameCallback(EndFrame);
});
Scene.SetCreateBodiesFunction([this](FSolverCallbacks::FParticlesType& Particles) {
CreateRigidBodyCallback(Particles);
});
Scene.SetParameterUpdateFunction([this](FSolverCallbacks::FParticlesType& Particles, const float, const int32 Index) {
});
Scene.SetDisableCollisionsUpdateFunction([this](TSet<TTuple<int32, int32>>&) {
});
Scene.AddPBDConstraintFunction([this](FSolverCallbacks::FParticlesType&, const float) {
});
Scene.AddForceFunction([this](FSolverCallbacks::FParticlesType& Particles, const float, const int32 Index) {
Particles[Index]->AddForce(FVector(0, 0, -980.f));
});
bInitializedState = true;
Scene.Init();
#if INCLUDE_CHAOS
UGeometryCollection* RestCollection = const_cast<UGeometryCollection*>(GeometryCollectionComponent->GetRestCollection());
if (GeometryCollectionComponent->bClearCache)
{
RestCollection->RecordedTracks.Records.Reset();
}
#endif
}
int32 NumTimeSteps = 1.f;
float dt = GWorld->DeltaTimeSeconds / (float)NumTimeSteps;
for (int i = 0; i < NumTimeSteps; i++)
{
Scene.Tick(dt);
}
}
void AGeometryCollectionActor::StartFrameCallback(float EndFrame)
{
UE_LOG(AGeometryCollectionActorLogging, Verbose, TEXT("AGeometryCollectionActor::StartFrameCallback()"));
UGeometryCollection* Collection = GeometryCollectionComponent->GetDynamicCollection();
if (!Scene.GetSimulation()->NumActors() && Collection->GetGeometryCollection()->HasAttribute("RigidBodyID", FGeometryCollection::TransformGroup))
{
TManagedArray<int32> & RigidBodyId = *RigidBodyIdArray;
TManagedArray<FVector> & CenterOfMass = *CenterOfMassArray;
TManagedArray<FTransform> & Transform = *Collection->GetGeometryCollection()->Transform;
TManagedArray<int32> & BoneMap = *Collection->GetGeometryCollection()->BoneMap;
TManagedArray<FVector> & Vertex = *Collection->GetGeometryCollection()->Vertex;
PxMaterial* NewMaterial = GPhysXSDK->createMaterial(0, 0, 0);
// floor
FTransform FloorTransform;
PxRigidStatic* FloorActor = GPhysXSDK->createRigidStatic(U2PTransform(FTransform::Identity));
PxShape* FloorShape = PxRigidActorExt::createExclusiveShape(*FloorActor, PxBoxGeometry(U2PVector(FVector(10000.f, 10000.f, 10.f))), *NewMaterial);
// This breaks threading correctness in a general sense but is needed until we can call this in create rigid bodies
const_cast<ImmediatePhysics::FSimulation*>(Scene.GetSimulation())->CreateStaticActor(FloorActor, FloorTransform);
FVector Scale = GeometryCollectionComponent->GetComponentTransform().GetScale3D();
TArray<FBox> Bounds;
Bounds.AddZeroed(Collection->GetGeometryCollection()->NumElements(FGeometryCollection::TransformGroup));
TArray<int32> SurfaceParticlesCount;
SurfaceParticlesCount.AddZeroed(Collection->GetGeometryCollection()->NumElements(FGeometryCollection::TransformGroup));
TArray<FVector> SumOfMass;
SumOfMass.AddZeroed(Collection->GetGeometryCollection()->NumElements(FGeometryCollection::TransformGroup));
for (int i = 0; i < Vertex.Num(); i++)
{
FVector ScaledVertex = Scale * Vertex[i];
int32 ParticleIndex = BoneMap[i];
Bounds[ParticleIndex] += ScaledVertex;
SurfaceParticlesCount[ParticleIndex]++;
SumOfMass[ParticleIndex] += ScaledVertex;
}
for (int32 i = 0; i < Collection->GetGeometryCollection()->Transform->Num(); ++i)
{
if (SurfaceParticlesCount[i] && 0.f < Bounds[i].GetSize().SizeSquared())
{
CenterOfMass[i] = SumOfMass[i] / SurfaceParticlesCount[i];
Bounds[i] = Bounds[i].InverseTransformBy(FTransform(CenterOfMass[i]));
RigidBodyId[i] = i;
int32 RigidBodyIndex = RigidBodyId[i];
FTransform NewTransform = TransformMatrix(GeometryCollectionComponent->GetComponentTransform(), Transform[i]);
float SideSquared = Bounds[i].GetSize()[0] * Bounds[i].GetSize()[0] / 6.f;
PxRigidDynamic* NewActor = GPhysXSDK->createRigidDynamic(U2PTransform(FTransform::Identity));
NewActor->setLinearVelocity(U2PVector(FVector(0.f, 0.f, 0.f)));
NewActor->setAngularVelocity(U2PVector(FVector(0.f, 0.f, 0.f)));
NewActor->setMass(1.f);
NewActor->setMassSpaceInertiaTensor(U2PVector(FVector(SideSquared, SideSquared, SideSquared)));
PxShape* NewShape = PxRigidActorExt::createExclusiveShape(*NewActor, PxBoxGeometry(U2PVector((Bounds[i].Max - Bounds[i].Min) / 2.f)), *NewMaterial);
const_cast<ImmediatePhysics::FSimulation*>(Scene.GetSimulation())->CreateDynamicActor(NewActor, NewTransform);
}
}
}
}
void AGeometryCollectionActor::CreateRigidBodyCallback(FSolverCallbacks::FParticlesType& Particles)
{
}
void AGeometryCollectionActor::EndFrameCallback(float EndFrame)
{
UE_LOG(AGeometryCollectionActorLogging, Log, TEXT("AGeometryCollectionActor::EndFrameFunction()"));
UGeometryCollection* Collection = GeometryCollectionComponent->GetDynamicCollection();
if (Collection->GetGeometryCollection()->HasAttribute("RigidBodyID", FGeometryCollection::TransformGroup))
{
TManagedArray<int32> & RigidBodyId = *RigidBodyIdArray;
TManagedArray<FVector> & CenterOfMass = *CenterOfMassArray;
TManagedArray<FTransform> & Transform = *Collection->GetGeometryCollection()->Transform;
const TArray<ImmediatePhysics::FActorHandle*>& Actors = Scene.GetSimulation()->GetActorHandles();
FTransform InverseComponentTransform = GeometryCollectionComponent->GetComponentTransform().Inverse();
for (int i = 0; i < Collection->GetGeometryCollection()->NumElements(FGeometryCollection::TransformGroup); i++)
{
int32 RigidBodyIndex = RigidBodyId[i];
Transform[i] = TransformMatrix(InverseComponentTransform, Actors[RigidBodyIndex]->GetWorldTransform());
}
GeometryCollectionComponent->SetRenderStateDirty();
}
}
bool AGeometryCollectionActor::RaycastSingle(FVector Start, FVector End, FHitResult& OutHit) const
{
OutHit = FHitResult();
OutHit.TraceStart = Start;
OutHit.TraceEnd = End;
return false;
}
void AGeometryCollectionActor::UpdateKinematicBodiesCallback(FSolverCallbacks::FParticlesType& Particles, const float Dt, const float Time, const int32 Index) {}
void AGeometryCollectionActor::ParameterUpdateCallback(FSolverCallbacks::FParticlesType& Particles, const float Time) {}
void AGeometryCollectionActor::DisableCollisionsCallback(TSet<TTuple<int32, int32>>& CollisionPairs) {}
void AGeometryCollectionActor::AddConstraintCallback(FSolverCallbacks::FParticlesType& Particles, const float Time) {}
void AGeometryCollectionActor::AddForceCallback(FSolverCallbacks::FParticlesType& Particles, const float Dt, const int32 Index) {}
#endif

View File

@@ -0,0 +1,71 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "GeometryCollection/GeometryCollectionCache.h"
#include "GeometryCollection/GeometryCollectionObject.h"
#include "HAL/IConsoleManager.h"
#include "Serialization/ArchiveCountMem.h"
#include "Features/IModularFeatures.h"
DEFINE_LOG_CATEGORY(LogGeometryCollectionCache);
FName UGeometryCollectionCache::TagName_Name = FName("CollectionName");
FName UGeometryCollectionCache::TagName_IdGuid = FName("CollectionIdGuid");
FName UGeometryCollectionCache::TagName_StateGuid = FName("CollectionStateGuid");
void UGeometryCollectionCache::SetFromRawTrack(const FRecordedTransformTrack& InTrack)
{
ProcessRawRecordedDataInternal(InTrack);
CompatibleCollectionState = SupportedCollection ? SupportedCollection->GetStateGuid() : FGuid();
}
void UGeometryCollectionCache::SetFromTrack(const FRecordedTransformTrack& InTrack)
{
RecordedData = InTrack;
CompatibleCollectionState = SupportedCollection ? SupportedCollection->GetStateGuid() : FGuid();
}
void UGeometryCollectionCache::SetSupportedCollection(UGeometryCollection* InCollection)
{
if(InCollection != SupportedCollection)
{
// New collection. Set it and then clear out recorded data
SupportedCollection = InCollection;
RecordedData.Records.Reset();
}
}
void UGeometryCollectionCache::GetAssetRegistryTags(TArray<FAssetRegistryTag>& OutTags) const
{
OutTags.Add(FAssetRegistryTag(TagName_Name, SupportedCollection ? SupportedCollection->GetName() : FString(TEXT("None")), FAssetRegistryTag::TT_Alphabetical));
OutTags.Add(FAssetRegistryTag(TagName_IdGuid, SupportedCollection ? SupportedCollection->GetIdGuid().ToString() : FString(TEXT("INVALID")), FAssetRegistryTag::TT_Hidden));
OutTags.Add(FAssetRegistryTag(TagName_StateGuid, SupportedCollection ? CompatibleCollectionState.ToString() : FString(TEXT("INVALID")), FAssetRegistryTag::TT_Hidden));
}
UGeometryCollectionCache* UGeometryCollectionCache::CreateCacheForCollection(UGeometryCollection* InCollection)
{
UGeometryCollectionCache* ResultCache = nullptr;
if(InCollection)
{
IModularFeatures& ModularFeatures = IModularFeatures::Get();
if(ModularFeatures.IsModularFeatureAvailable(ITargetCacheProvider::GetFeatureName()))
{
ITargetCacheProvider* Provider = &ModularFeatures.GetModularFeature<ITargetCacheProvider>(ITargetCacheProvider::GetFeatureName());
check(Provider);
ResultCache = Provider->GetCacheForCollection(InCollection);
if(ResultCache)
{
ResultCache->SetSupportedCollection(InCollection);
}
}
}
return ResultCache;
}
void UGeometryCollectionCache::ProcessRawRecordedDataInternal(const FRecordedTransformTrack& InTrack)
{
RecordedData = FRecordedTransformTrack::ProcessRawRecordedData(InTrack);
}

View File

@@ -0,0 +1,34 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "GeometryCollection/GeometryCollectionComponentPlugin.h"
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class FGeometryCollectionComponentPlugin : public IGeometryCollectionComponentPlugin
{
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
IMPLEMENT_MODULE( FGeometryCollectionComponentPlugin, GeometryCollectionComponent )
void FGeometryCollectionComponentPlugin::StartupModule()
{
}
void FGeometryCollectionComponentPlugin::ShutdownModule()
{
}

View File

@@ -0,0 +1,12 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Stats/Stats.h"
// You should place include statements to your module's private header files here. You only need to
// add includes for headers that are used in most of your module's source files though.
DECLARE_STATS_GROUP(TEXT("GeometryCollection"), STATGROUP_GeometryCollection, STATCAT_Advanced);

View File

@@ -0,0 +1,494 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "GeometryCollection/GeometryCollectionDebugDrawComponent.h"
#if GEOMETRYCOLLECTION_DEBUG_DRAW
#include "GeometryCollection/GeometryCollectionRenderLevelSetActor.h"
#include "GeometryCollection/GeometryCollectionComponent.h"
#include "GeometryCollection/GeometryCollectionObject.h"
#include "GeometryCollection/GeometryCollectionAlgo.h"
#include "GeometryCollection/GeometryCollectionDebugDrawActor.h"
#include "GeometryCollection/GeometryCollectionPhysicsProxy.h"
#if INCLUDE_CHAOS
#include "PBDRigidsSolver.h"
#endif // #if INCLUDE_CHAOS
#endif // #if GEOMETRYCOLLECTION_DEBUG_DRAW
#include "EngineUtils.h"
#include "HAL/IConsoleManager.h"
DEFINE_LOG_CATEGORY_STATIC(UGCCDD_LOG, All, All);
// Constants
static const FLinearColor DarkerColorFactor(1.0f, 1.0f, 0.7f); // Darker HSV multiplier
static const FLinearColor LighterColorFactor(1.0f, 1.0f, 3.0f); // Lighter HSV multiplier
static const FLinearColor VertexColorDefault(0.2f, 0.4f, 0.6f, 1.0f); // Blue
static const FLinearColor FaceColorDefault(0.4f, 0.2f, 0.6f, 1.0f); // Purple
static const FLinearColor GeometryColorDefault(0.6, 0.4f, 0.2f, 1.0f); // Orange
static const FLinearColor BreakingColorDefault(0.4f, 0.6f, 0.2f, 1.0f); // Green
UGeometryCollectionDebugDrawComponent::UGeometryCollectionDebugDrawComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, GeometryCollectionDebugDrawActor(nullptr)
, GeometryCollectionRenderLevelSet(nullptr)
, bDebugDrawLevelSet(false)
, bRenderLevelSetAtOrigin(false)
, LevelSetIndex(0)
, bDebugDrawTransform(false)
, bDebugDrawTransformIndex(false)
, bDebugDrawBoundingBox(false)
, GeometryColor(GeometryColorDefault)
, bDebugDrawProximity(false)
, bDebugDrawBreakingFace(false)
, bDebugDrawBreakingRegionData(false)
, BreakingColor(BreakingColorDefault)
, bDebugDrawFace(false)
, bDebugDrawFaceIndex(false)
, bDebugDrawFaceNormal(false)
, bDebugDrawSingleFace(false)
, SingleFaceIdx(0)
, FaceColor(FaceColorDefault)
, bDebugDrawVertex(false)
, bDebugDrawVertexIndex(false)
, bDebugDrawVertexNormal(false)
, VertexColor(VertexColorDefault)
, GeometryCollectionComponent(nullptr)
, bLevelSetTextureDirty(false)
, LevelSetTextureTransformIndex(-1)
, BaseVisibilityArray()
{
PrimaryComponentTick.bCanEverTick = true;
bTickInEditor = false;
}
void UGeometryCollectionDebugDrawComponent::BeginPlay()
{
Super::BeginPlay();
DebugDrawBeginPlay();
DebugDrawLevelSetBeginPlay();
}
void UGeometryCollectionDebugDrawComponent::EndPlay(EEndPlayReason::Type ReasonEnd)
{
Super::EndPlay(ReasonEnd);
DebugDrawLevelSetEndPlay();
}
void UGeometryCollectionDebugDrawComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
DebugDrawTick();
DebugDrawLevelSetTick();
}
#if WITH_EDITOR
void UGeometryCollectionDebugDrawComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
#if GEOMETRYCOLLECTION_DEBUG_DRAW
if (GeometryCollectionComponent)
{
const FName PropertyName = PropertyChangedEvent.Property ? PropertyChangedEvent.Property->GetFName(): NAME_None;
if (PropertyName == GET_MEMBER_NAME_CHECKED(UGeometryCollectionDebugDrawComponent, SingleFaceIdx))
{
check(GeometryCollectionComponent->DynamicCollection != nullptr);
check(GeometryCollectionComponent->DynamicCollection->GetGeometryCollection().IsValid());
FGeometryCollection* const Collection = GeometryCollectionComponent->DynamicCollection->GetGeometryCollection().Get();
if (Collection)
{
const int32 NumFaces = Collection->NumElements(FGeometryCollection::FacesGroup);
SingleFaceIdx = FMath::Clamp(SingleFaceIdx, 0, NumFaces - 1);
}
}
}
#endif // #if GEOMETRYCOLLECTION_DEBUG_DRAW
}
#endif // #if WITH_EDITOR
void UGeometryCollectionDebugDrawComponent::DebugDrawLevelSetBeginPlay()
{
#if INCLUDE_CHAOS && GEOMETRYCOLLECTION_DEBUG_DRAW
// Look out for existing render level set actor, or create one when needed
if (!GeometryCollectionRenderLevelSet)
{
UWorld* const world = GetWorld();
check(world);
const TActorIterator<AGeometryCollectionRenderLevelSetActor> ActorIterator(world);
if (ActorIterator)
{
GeometryCollectionRenderLevelSet = *ActorIterator;
}
else
{
FActorSpawnParameters SpawnInfo;
SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
GeometryCollectionRenderLevelSet = world->SpawnActor<AGeometryCollectionRenderLevelSetActor>(SpawnInfo);
if (GeometryCollectionRenderLevelSet)
{
GeometryCollectionRenderLevelSet->SetActorEnableCollision(false);
}
}
}
if (GeometryCollectionComponent && GeometryCollectionComponent->DynamicCollection && GeometryCollectionRenderLevelSet)
{
// For now it makes sense to always initialize our visibility arrays since a user might start with vis debug off, then turn it on
// This logic could change in the future
TManagedArray<bool> &VisibleArray = *GeometryCollectionComponent->DynamicCollection->GetGeometryCollection()->Visible;
BaseVisibilityArray = GeometryCollectionComponent->DynamicCollection->GetGeometryCollection()->AddAttribute<bool>("BaseVisibility", FGeometryCollection::FacesGroup);
(*BaseVisibilityArray).Init(VisibleArray);
bLevelSetTextureDirty = true;
LevelSetTextureTransformIndex = -1;
}
#endif // #if INCLUDE_CHAOS && GEOMETRYCOLLECTION_DEBUG_DRAW
}
void UGeometryCollectionDebugDrawComponent::DebugDrawLevelSetEndPlay()
{
#if INCLUDE_CHAOS && GEOMETRYCOLLECTION_DEBUG_DRAW
if (GeometryCollectionComponent && GeometryCollectionRenderLevelSet)
{
// @note: it might be the case that the user checks and unchecks render level set multiple times, and when they exit it is off
// but we still want to reset the visibility. One solution is to always reset visibility at run time when the check box changes
if (bDebugDrawLevelSet) {
DebugDrawLevelSetResetVisiblity();
}
// turn off rendering
GeometryCollectionRenderLevelSet->SetEnabled(false);
bLevelSetTextureDirty = true;
LevelSetTextureTransformIndex = -1;
}
#endif // #if INCLUDE_CHAOS && GEOMETRYCOLLECTION_DEBUG_DRAW
}
void UGeometryCollectionDebugDrawComponent::DebugDrawLevelSetResetVisiblity()
{
#if INCLUDE_CHAOS && GEOMETRYCOLLECTION_DEBUG_DRAW
check(GeometryCollectionComponent != nullptr);
check(GeometryCollectionComponent->DynamicCollection != nullptr);
check(GeometryCollectionComponent->DynamicCollection->GetGeometryCollection().IsValid());
check(BaseVisibilityArray.IsValid());
// reset visibility array
TManagedArray<bool> &VisibleArray = *GeometryCollectionComponent->DynamicCollection->GetGeometryCollection()->Visible;
VisibleArray.Init(*BaseVisibilityArray);
// if we only have one piece, and all of the faces were hidden, then ensure we set visibility true
if (!GeometryCollectionComponent->IsVisible()) {
GeometryCollectionComponent->SetVisibility(true);
}
else
{
GeometryCollectionComponent->ForceInitRenderData();
}
#endif // #if INCLUDE_CHAOS && GEOMETRYCOLLECTION_DEBUG_DRAW
}
void UGeometryCollectionDebugDrawComponent::DebugDrawLevelSetTick()
{
#if INCLUDE_CHAOS && GEOMETRYCOLLECTION_DEBUG_DRAW
if (!bDebugDrawLevelSet)
{
if (LevelSetTextureTransformIndex != -1 && GeometryCollectionRenderLevelSet && BaseVisibilityArray)
{
// in this case, the user switched from debug draw to not at run time, reset visibility
DebugDrawLevelSetResetVisiblity();
// turn off rendering
GeometryCollectionRenderLevelSet->SetEnabled(false);
bLevelSetTextureDirty = true;
LevelSetTextureTransformIndex = -1;
}
}
else
{
// if the level set index has changed at run time, then reload the volume
// because someone wants to visualize another piece
if (LevelSetTextureTransformIndex != -1 && LevelSetTextureTransformIndex != LevelSetIndex) {
bLevelSetTextureDirty = true;
}
// Error case if the level set renderer, physics proxy, or solver are null
if (!GeometryCollectionRenderLevelSet) {
UE_LOG(UGCCDD_LOG, Warning, TEXT("level set renderer: %s"), *GetFullName());
return;
}
if (!GeometryCollectionComponent) {
UE_LOG(UGCCDD_LOG, Warning, TEXT("no geometry component: %s"), *GetFullName());
return;
}
FGeometryCollectionPhysicsProxy *PhysicsProxy = GeometryCollectionComponent->GetPhysicsProxy();
if (!GeometryCollectionRenderLevelSet || !PhysicsProxy || !PhysicsProxy->GetSolver()) {
UE_LOG(UGCCDD_LOG, Warning, TEXT("No solver context: %s"), *GetFullName());
return;
}
// We must have at least one body to continue
const Chaos::PBDRigidsSolver::FParticlesType &Particles = PhysicsProxy->GetSolver()->GetRigidParticles();
if (Particles.Size() == 0) {
UE_LOG(UGCCDD_LOG, Warning, TEXT("No rbds in solver context: %s"), *GetFullName());
return;
}
// Map the piece index to the rbd index to extract the level set
if (GeometryCollectionComponent->RigidBodyIds.Num() == 0) {
UE_LOG(UGCCDD_LOG, Warning, TEXT("No rbd ids synced: %s"), *GetFullName());
return;
}
// Make sure we have a valid tranform index
if (LevelSetIndex < 0 || LevelSetIndex > GeometryCollectionComponent->RigidBodyIds.Num() - 1) {
UE_LOG(UGCCDD_LOG, Warning, TEXT("Invalid level set index: %s"), *GetFullName());
return;
}
// Make sure we have a valid rbd index
int32 RbdId = GeometryCollectionComponent->RigidBodyIds[LevelSetIndex];
if (RbdId < 0) {
UE_LOG(UGCCDD_LOG, Warning, TEXT("No rbd ids synced: %s"), *GetFullName());
return;
}
Chaos::TImplicitObject<float, 3>* CollisionBase = Particles.Geometry(RbdId);
// Make sure the actual implicit object isn't null
if (CollisionBase == NULL) {
UE_LOG(UGCCDD_LOG, Warning, TEXT("Collision is null for level set visualization: %s"), *GetFullName());
return;
}
// Cast to level set, make sure the type is correct
Chaos::TLevelSet<float, 3>* CollisionLevelSet = CollisionBase->GetObject< Chaos::TLevelSet<float, 3> >();
if (CollisionLevelSet == NULL) {
UE_LOG(UGCCDD_LOG, Warning, TEXT("Incorrect collision type for level set rendering. It must be a level set: %s"), *GetFullName());
return;
}
// Get the transform for the current piece
FTransform CurrTransform = FTransform::Identity;
UGeometryCollection *DynamicCollection = GeometryCollectionComponent->DynamicCollection;
// Update the transform if we are rendering the level set aligned with the simulated geometry
if (!bRenderLevelSetAtOrigin) {
//TManagedArray<FTransform> &TransformArray = DynamicCollection->GetGeometryCollection()->GetAttribute<FTransform>("Transform", FGeometryCollection::TransformGroup).Get();
//CurrTransform = TransformArray[LevelSetIndex];
// @todo: this is slow to recompute the global matrices here. Ideally we'd grab some cached ones from the geom collection component
TArray<FTransform> GlobalMatrices;
GeometryCollectionAlgo::GlobalMatrices(DynamicCollection->GetGeometryCollection().Get(), GlobalMatrices);
CurrTransform = GlobalMatrices[LevelSetIndex];
CurrTransform *= this->GetOwner()->GetTransform();
}
// If we are only updating the transform, or also loading the volume
if (!bLevelSetTextureDirty) {
GeometryCollectionRenderLevelSet->SyncLevelSetTransform(CurrTransform);
}
else {
// Build the volume texture
// @note: we only want to do this once, so we have a state variable on the component to ensure that
bool success = GeometryCollectionRenderLevelSet->SetLevelSetToRender(*CollisionLevelSet, CurrTransform);
// Error case if volume fill didn't work
if (!success) {
UE_LOG(UGCCDD_LOG, Warning, TEXT("Levelset generation failed: %s"), *GetFullName());
return;
}
// hide the original piece
TManagedArray<bool> &VisibleArray = *DynamicCollection->GetGeometryCollection()->Visible;
// reset visibility to original state
// @todo: there is some logic missing here, but also GeometryCollectionComponent doesn't like
// debug rendering flags being set in simulate mode, so we don't switch piece often right now
if (LevelSetTextureTransformIndex != -1) {
VisibleArray.Init(*BaseVisibilityArray);
}
const TManagedArray<int32> &TransformIndexArray = *DynamicCollection->GetGeometryCollection()->TransformIndex;
const TManagedArray<int32> &FaceStartArray = *DynamicCollection->GetGeometryCollection()->FaceStart;
const TManagedArray<int32> &FaceCountArray = *DynamicCollection->GetGeometryCollection()->FaceCount;
const TManagedArray<FIntVector> &Indices = *DynamicCollection->GetGeometryCollection()->Indices;
const TManagedArray<int32>& MaterialIndex = *DynamicCollection->GetGeometryCollection()->MaterialIndex;
// for each geom, check if it is the transform object
// if it is, hide all the faces
int NumHid = 0;
for (int i = 0; i < TransformIndexArray.Num(); ++i) {
const int32 currT = TransformIndexArray[i];
if (currT == LevelSetIndex) {
int32 FaceStart = FaceStartArray[i];
int32 FaceCount = FaceCountArray[i];
// set visibility on faces to false
for (int j = FaceStart; j < FaceStart + FaceCount; ++j) {
VisibleArray[j] = false;
}
NumHid = FaceCount;
}
}
// if we have no visible faces, hide the geometry without changing the collection
// #todo: right now we can't send zero vertices to force the vertex buffer to be empty,
// so we just hide the component.
if (NumHid == VisibleArray.Num())
{
GeometryCollectionComponent->SetVisibility(false);
}
else
{
// init all render data
GeometryCollectionComponent->ForceInitRenderData();
}
// Make sure we know not to refill the texture on subsequent frames
bLevelSetTextureDirty = false;
LevelSetTextureTransformIndex = LevelSetIndex;
// Turn on the volume rendering
GeometryCollectionRenderLevelSet->SetEnabled(true);
}
}
#endif // #if INCLUDE_CHAOS && GEOMETRYCOLLECTION_DEBUG_DRAW
}
void UGeometryCollectionDebugDrawComponent::DebugDrawBeginPlay()
{
#if GEOMETRYCOLLECTION_DEBUG_DRAW
if (!GeometryCollectionDebugDrawActor)
{
// Look out for existing debug draw actor, or create one when needed
UWorld* const world = GetWorld();
check(world);
const TActorIterator<AGeometryCollectionDebugDrawActor> ActorIterator(world);
if (ActorIterator)
{
GeometryCollectionDebugDrawActor = *ActorIterator;
}
else
{
FActorSpawnParameters SpawnInfo;
SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
GeometryCollectionDebugDrawActor = world->SpawnActor<AGeometryCollectionDebugDrawActor>(SpawnInfo);
if (GeometryCollectionDebugDrawActor)
{
GeometryCollectionDebugDrawActor->SetActorEnableCollision(false);
}
}
}
// Make sure to tick the debug draw first, it is required to clear up the persistent lines before drawing a new frame
if (GeometryCollectionDebugDrawActor)
{
AActor* const actor = GetOwner();
check(actor);
GeometryCollectionDebugDrawActor->AddTickPrerequisiteActor(actor);
}
#endif // #if GEOMETRYCOLLECTION_DEBUG_DRAW
}
void UGeometryCollectionDebugDrawComponent::DebugDrawTick()
{
#if GEOMETRYCOLLECTION_DEBUG_DRAW
check(GeometryCollectionDebugDrawActor);
// Only draw when a GeometryCollectionComponent is also attached to the actor (GeometryCollectionComponent is set by AGeometryCollectionActor::AGeometryCollectionActor())
if (!GeometryCollectionComponent)
{
UE_LOG(UGCCDD_LOG, Warning, TEXT("Null geometry component pointer: %s"), *GetFullName());
return;
}
if (!GeometryCollectionComponent->DynamicCollection)
{
UE_LOG(UGCCDD_LOG, Warning, TEXT("Null geometry dynamic collection pointer: %s"), *GetFullName());
return;
}
if (!GeometryCollectionComponent->DynamicCollection->GetGeometryCollection().IsValid())
{
UE_LOG(UGCCDD_LOG, Warning, TEXT("No valid geometry collection: %s"), *GetFullName());
return;
}
// Draw collection
FGeometryCollection* const Collection = GeometryCollectionComponent->DynamicCollection->GetGeometryCollection().Get();
check(Collection);
AActor* const Actor = GetOwner();
check(Actor);
if (bDebugDrawVertex)
{
const FColor Color = VertexColor.ToFColor(false);
GeometryCollectionDebugDrawActor->DrawVertices(Collection, Actor, Color);
}
if (bDebugDrawVertexIndex)
{
const FColor Color = (VertexColor.LinearRGBToHSV() * LighterColorFactor).HSVToLinearRGB().ToFColor(false);
GeometryCollectionDebugDrawActor->DrawVertexIndices(Collection, Actor, Color);
}
if (bDebugDrawVertexNormal)
{
const FColor Color = (VertexColor.LinearRGBToHSV() * DarkerColorFactor).HSVToLinearRGB().ToFColor(false);
GeometryCollectionDebugDrawActor->DrawVertexNormals(Collection, Actor, Color);
}
if (bDebugDrawFace)
{
const FColor Color = FaceColor.ToFColor(false);
GeometryCollectionDebugDrawActor->DrawFaces(Collection, Actor, Color);
}
if (bDebugDrawFaceIndex)
{
const FColor Color = (FaceColor.LinearRGBToHSV() * LighterColorFactor).HSVToLinearRGB().ToFColor(false);
GeometryCollectionDebugDrawActor->DrawFaceIndices(Collection, Actor, Color);
}
if (bDebugDrawSingleFace)
{
const FColor Color = (FaceColor.LinearRGBToHSV() * LighterColorFactor).HSVToLinearRGB().ToFColor(false);
GeometryCollectionDebugDrawActor->DrawSingleFace(Collection, Actor, SingleFaceIdx, Color);
}
if (bDebugDrawFaceNormal)
{
const FColor Color = (FaceColor.LinearRGBToHSV() * DarkerColorFactor).HSVToLinearRGB().ToFColor(false);
GeometryCollectionDebugDrawActor->DrawFaceNormals(Collection, Actor, Color);
}
if (bDebugDrawTransform)
{
GeometryCollectionDebugDrawActor->DrawTransforms(Collection, Actor);
}
if (bDebugDrawTransformIndex)
{
const FColor Color = (GeometryColor.LinearRGBToHSV() * LighterColorFactor).HSVToLinearRGB().ToFColor(false);
GeometryCollectionDebugDrawActor->DrawTransformIndices(Collection, Actor, Color);
}
if (bDebugDrawBoundingBox)
{
const FColor Color = GeometryColor.ToFColor(false);
GeometryCollectionDebugDrawActor->DrawBoundingBoxes(Collection, Actor, Color);
}
if (bDebugDrawProximity)
{
const FColor Color = BreakingColor.ToFColor(false);
GeometryCollectionDebugDrawActor->DrawProximity(Collection, Actor, Color);
}
if (bDebugDrawBreakingFace)
{
const FColor Color = (BreakingColor.LinearRGBToHSV() * LighterColorFactor).HSVToLinearRGB().ToFColor(false);
GeometryCollectionDebugDrawActor->DrawBreakingFaces(Collection, Actor, Color);
}
if (bDebugDrawBreakingRegionData)
{
const FColor Color = (BreakingColor.LinearRGBToHSV() * DarkerColorFactor).HSVToLinearRGB().ToFColor(false);
GeometryCollectionDebugDrawActor->DrawBreakingRegionData(Collection, Actor, Color);
}
#endif // #if GEOMETRYCOLLECTION_DEBUG_DRAW
}

View File

@@ -0,0 +1,219 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "GeometryCollection/GeometryCollectionEngineUtility.h"
#include "GeometryCollection/GeometryCollection.h"
#include "GeometryCollection/GeometryCollectionCache.h"
#include "GeometryCollection/GeometryCollectionAlgo.h"
DEFINE_LOG_CATEGORY_STATIC(LogGeoemtryCollectionClean, Verbose, All);
void GeometryCollectionEngineUtility::PrintDetailedStatistics(const FGeometryCollection* GeometryCollection, const UGeometryCollectionCache* InCache)
{
check(GeometryCollection);
TSharedPtr< TManagedArray<FTransform> > Transform;
TSharedPtr< TManagedArray<FGeometryCollectionBoneNode> > BoneHierarchy;
int32 NumTransforms = GeometryCollection->NumElements(FGeometryCollection::TransformGroup);
int32 NumVertices = GeometryCollection->NumElements(FGeometryCollection::VerticesGroup);
int32 NumFaces = GeometryCollection->NumElements(FGeometryCollection::FacesGroup);
int32 NumGeometries = GeometryCollection->NumElements(FGeometryCollection::GeometryGroup);
int32 NumBreakings = GeometryCollection->NumElements(FGeometryCollection::BreakingGroup);
const TManagedArray<FVector>& VertexArray = *GeometryCollection->Vertex;
const TManagedArray<int32>& BoneMapArray = *GeometryCollection->BoneMap;
TArray<FTransform> GlobalTransformArray;
GeometryCollectionAlgo::GlobalMatrices(GeometryCollection, GlobalTransformArray);
FBox BoundingBox(ForceInitToZero);
for (int32 IdxVertex = 0; IdxVertex < NumVertices; ++IdxVertex)
{
FTransform GlobalTransform = GlobalTransformArray[BoneMapArray[IdxVertex]];
FVector VertexInWorld = GlobalTransform.TransformPosition(VertexArray[IdxVertex]);
BoundingBox += VertexInWorld;
}
FString Buffer;
Buffer += FString::Printf(TEXT("\n\n"));
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
Buffer += FString::Printf(TEXT("TRANSFORM GROUP\n"));
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
Buffer += FString::Printf(TEXT("Number of transforms = %d\n"), NumTransforms);
// Print Transform array
// Print BoneHierarchy array
GeometryCollectionAlgo::PrintParentHierarchy(GeometryCollection);
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
Buffer += FString::Printf(TEXT("VERTICES GROUP\n"));
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
Buffer += FString::Printf(TEXT("Number of vertices = %d\n"), NumVertices);
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
Buffer += FString::Printf(TEXT("FACES GROUP\n"));
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
Buffer += FString::Printf(TEXT("Number of faces = %d\n"), NumFaces);
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
Buffer += FString::Printf(TEXT("GEOMETRY GROUP\n"));
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
Buffer += FString::Printf(TEXT("Number of geometries = %d\n"), NumGeometries);
// Print TransformIndex array
// Print Proximity array
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
Buffer += FString::Printf(TEXT("BREAKING GROUP\n"));
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
Buffer += FString::Printf(TEXT("Number of breakings = %d\n"), NumBreakings);
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
Buffer += FString::Printf(TEXT("BOUNDING BOX\n"));
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
Buffer += FString::Printf(TEXT("Min = (%f, %f, %f)\n"), BoundingBox.Min.X, BoundingBox.Min.Y, BoundingBox.Min.Z);
Buffer += FString::Printf(TEXT("Max = (%f, %f, %f)\n"), BoundingBox.Max.X, BoundingBox.Max.Y, BoundingBox.Max.Z);
Buffer += FString::Printf(TEXT("Center = (%f, %f, %f)\n"), BoundingBox.GetCenter().X, BoundingBox.GetCenter().Y, BoundingBox.GetCenter().Z);
Buffer += FString::Printf(TEXT("Size = (%f, %f, %f)\n"), 2.f * BoundingBox.GetExtent().X, 2.f * BoundingBox.GetExtent().Y, 2.f * BoundingBox.GetExtent().Z);
if(InCache && InCache->GetData())
{
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
Buffer += FString::Printf(TEXT("CACHE INFO\n"));
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
const FRecordedTransformTrack* Track = InCache->GetData();
int32 NumRecords = Track->Records.Num();
if(NumRecords == 0)
{
Buffer += FString::Printf(TEXT("Cache is empty\n"));
}
else
{
float FirstRecordTimestamp = Track->Records[0].Timestamp;
float LastRecordTimestamp = Track->Records[NumRecords - 1].Timestamp;
TMultiMap<int32, int32> TimestampRecordMap;
for(int32 IdxRecord = 0; IdxRecord < NumRecords; ++IdxRecord)
{
TimestampRecordMap.Add(FMath::FloorToInt(Track->Records[IdxRecord].Timestamp), IdxRecord);
}
TArray<int32> NumRecordsPerSecond;
NumRecordsPerSecond.SetNum(FMath::CeilToInt(LastRecordTimestamp));
for(int32 Idx = 0; Idx < FMath::CeilToInt(LastRecordTimestamp); ++Idx)
{
NumRecordsPerSecond[Idx] = TimestampRecordMap.Num(Idx);
}
int32 NumRecordsMin = INT_MAX, NumRecordsMax = INT_MIN;
float NumRecordsAverage = 0.f;
for(int32 Idx = 0; Idx < NumRecordsPerSecond.Num(); ++Idx)
{
if(NumRecordsPerSecond[Idx] < NumRecordsMin)
{
NumRecordsMin = NumRecordsPerSecond[Idx];
}
if(NumRecordsPerSecond[Idx] > NumRecordsMax)
{
NumRecordsMax = NumRecordsPerSecond[Idx];
}
NumRecordsAverage += (float)NumRecordsPerSecond[Idx];
}
NumRecordsAverage /= (float)NumRecordsPerSecond.Num();
Buffer += FString::Printf(TEXT("Cache length [%f - %f]\n"), FirstRecordTimestamp, LastRecordTimestamp);
Buffer += FString::Printf(TEXT("Number of recorded frames = %d\n"), NumRecords);
for(int32 Idx = 0; Idx < NumRecordsPerSecond.Num(); ++Idx)
{
Buffer += FString::Printf(TEXT("Number of recorded frames at %ds = %d\n"), Idx, NumRecordsPerSecond[Idx]);
}
Buffer += FString::Printf(TEXT("Minimum number of recorded frames per second = %d\n"), NumRecordsMin);
Buffer += FString::Printf(TEXT("Maximum number of recorded frames per second = %d\n"), NumRecordsMax);
Buffer += FString::Printf(TEXT("Average number of recorded frames per second = %f\n"), NumRecordsAverage);
TArray<int32> NumCollisionMinPerSecond;
NumCollisionMinPerSecond.Init(0, FMath::CeilToInt(LastRecordTimestamp));
TArray<int32> NumCollisionMaxPerSecond;
NumCollisionMaxPerSecond.Init(0, FMath::CeilToInt(LastRecordTimestamp));
TArray<float> NumCollisionAveragePerSecond;
NumCollisionAveragePerSecond.Init(0.f, FMath::CeilToInt(LastRecordTimestamp));
int32 NumTotalCollisions = 0;
TArray<int32> RecordIdxForOneSecond;
for(int32 IdxSeconds = 0; IdxSeconds < NumRecordsPerSecond.Num(); ++IdxSeconds)
{
RecordIdxForOneSecond.Empty();
TimestampRecordMap.MultiFind(IdxSeconds, RecordIdxForOneSecond);
for(int32 IdxRecord = 0; IdxRecord < RecordIdxForOneSecond.Num(); ++IdxRecord)
{
int32 NumCollisions = Track->Records[RecordIdxForOneSecond[IdxRecord]].Collisions.Num();
if(NumCollisions > 0)
{
if(NumCollisions < NumCollisionMinPerSecond[IdxSeconds])
{
NumCollisionMinPerSecond[IdxSeconds] = NumCollisions;
}
if(NumCollisions > NumCollisionMaxPerSecond[IdxSeconds])
{
NumCollisionMaxPerSecond[IdxSeconds] = NumCollisions;
}
NumCollisionAveragePerSecond[IdxSeconds] += NumCollisions;
NumTotalCollisions += NumCollisions;
}
}
NumCollisionAveragePerSecond[IdxSeconds] /= (float)RecordIdxForOneSecond.Num();
}
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
for(int32 Idx = 0; Idx < NumRecordsPerSecond.Num(); ++Idx)
{
Buffer += FString::Printf(TEXT("Number of min collisions at %ds = %d\n"), Idx, NumCollisionMinPerSecond[Idx]);
Buffer += FString::Printf(TEXT("Number of max collisions at %ds = %d\n"), Idx, NumCollisionMaxPerSecond[Idx]);
Buffer += FString::Printf(TEXT("Number of average collisions at %ds = %f\n"), Idx, NumCollisionAveragePerSecond[Idx]);
}
Buffer += FString::Printf(TEXT("Number of total collisions = %d\n"), NumTotalCollisions);
}
}
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
Buffer += FString::Printf(TEXT("MESH QUALITY\n"));
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n"));
TSet<int32> VertexToDeleteSet;
TMap<int32, int32> CoincidentVerticesMap;
GeometryCollectionAlgo::ComputeCoincidentVertices(GeometryCollection, 1e-2, CoincidentVerticesMap, VertexToDeleteSet);
int32 NumCoincidentVertices = VertexToDeleteSet.Num();
TSet<int32> FaceToDeleteSet;
GeometryCollectionAlgo::ComputeZeroAreaFaces(GeometryCollection, 1e-4, FaceToDeleteSet);
int32 NumZeroAreaFaces = FaceToDeleteSet.Num();
GeometryCollectionAlgo::ComputeHiddenFaces(GeometryCollection, FaceToDeleteSet);
int32 NumHiddenFaces = FaceToDeleteSet.Num();
GeometryCollectionAlgo::ComputeStaleVertices(GeometryCollection, VertexToDeleteSet);
int32 NumStaleVertices = VertexToDeleteSet.Num();
TMap<GeometryCollectionAlgo::FFaceEdge, int32> FaceEdgeMap;
GeometryCollectionAlgo::ComputeEdgeInFaces(GeometryCollection, FaceEdgeMap);
int32 NumBoundaryEdges = 0;
int32 NumDegenerateEdges = 0;
for (auto& Edge : FaceEdgeMap)
{
if (FaceEdgeMap[Edge.Key] == 0)
{
NumBoundaryEdges++;
}
else if (FaceEdgeMap[Edge.Key] > 2)
{
NumDegenerateEdges++;
}
}
Buffer += FString::Printf(TEXT("Number of coincident vertices = %d\n"), NumCoincidentVertices);
Buffer += FString::Printf(TEXT("Number of zero area faces = %d\n"), NumZeroAreaFaces);
Buffer += FString::Printf(TEXT("Number of hidden faces = %d\n"), NumHiddenFaces);
Buffer += FString::Printf(TEXT("Number of stale vertices = %d\n"), NumStaleVertices);
Buffer += FString::Printf(TEXT("Number of boundary edges = %d\n"), NumBoundaryEdges);
Buffer += FString::Printf(TEXT("Number of degenerate edges (included in more than 2 faces) = %d\n"), NumDegenerateEdges);
Buffer += FString::Printf(TEXT("------------------------------------------------------------\n\n"));
UE_LOG(LogGeoemtryCollectionClean, Log, TEXT("%s"), *Buffer);
}

View File

@@ -0,0 +1,165 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
GeometryCollection.cpp: UGeometryCollection methods.
=============================================================================*/
#include "GeometryCollection/GeometryCollectionObject.h"
#include "GeometryCollection/GeometryCollection.h"
#include "GeometryCollection/GeometryCollectionCache.h"
#include "UObject/DestructionObjectVersion.h"
#include "Serialization/ArchiveCountMem.h"
#include "HAL/IConsoleManager.h"
#include "UObject/Package.h"
#include "Materials/MaterialInstance.h"
DEFINE_LOG_CATEGORY_STATIC(UGeometryCollectionLogging, NoLogging, All);
UGeometryCollection::UGeometryCollection(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, GeometryCollection(new FGeometryCollection())
{
check(ObjectInitializer.GetClass() == GetClass());
if (UGeometryCollection* InputComponent = static_cast<UGeometryCollection*>(ObjectInitializer.GetObj()))
{
if (InputComponent->GetGeometryCollection())
{
GeometryCollection = TSharedPtr<FGeometryCollection>(
new FGeometryCollection(*static_cast<UGeometryCollection*>(ObjectInitializer.GetObj())->GetGeometryCollection()));
}
}
PersistentGuid = FGuid::NewGuid();
InvalidateCollection();
}
//** Initialize */
void UGeometryCollection::Initialize(FManagedArrayCollection & CollectionIn)
{
Modify();
GeometryCollection->Initialize(CollectionIn);
InvalidateCollection();
}
/** AppendGeometry */
int32 UGeometryCollection::AppendGeometry(const UGeometryCollection & Element)
{
Modify();
InvalidateCollection();
return GeometryCollection->AppendGeometry(*Element.GetGeometryCollection());
}
/** NumElements */
int32 UGeometryCollection::NumElements(const FName & Group)
{
return GeometryCollection->NumElements(Group);
}
/** RemoveElements */
void UGeometryCollection::RemoveElements(const FName & Group, const TArray<int32>& SortedDeletionList)
{
Modify();
GeometryCollection->RemoveElements(Group, SortedDeletionList);
InvalidateCollection();
}
/** ReindexMaterialSections */
void UGeometryCollection::ReindexMaterialSections()
{
Modify();
GeometryCollection->ReindexMaterials();
InvalidateCollection();
}
void UGeometryCollection::AppendStandardMaterials()
{
// Second to last material is the interior material
// #todo(dmp): This will be replaced when we support multiple internal materials
UMaterialInterface* InteriorMaterial = LoadObject<UMaterialInterface>(NULL, TEXT("/GeometryCollectionPlugin/InMaterial.InMaterial"), NULL, LOAD_None, NULL);
InteriorMaterialIndex = Materials.Add(InteriorMaterial);
// Last Material is the selection one
UMaterialInterface* BoneSelectedMaterial = LoadObject<UMaterialInterface>(NULL, TEXT("/GeometryCollectionPlugin/SelectedGeometryMaterial.SelectedGeometryMaterial"), NULL, LOAD_None, NULL);
BoneSelectedMaterialIndex = Materials.Add(BoneSelectedMaterial);
}
/** Returns true if there is anything to render */
bool UGeometryCollection::HasVisibleGeometry()
{
return GeometryCollection->HasVisibleGeometry();
}
/** Serialize */
void UGeometryCollection::Serialize(FArchive& Ar)
{
Ar.UsingCustomVersion(FDestructionObjectVersion::GUID);
GeometryCollection->Serialize(Ar);
if(Ar.CustomVer(FDestructionObjectVersion::GUID) < FDestructionObjectVersion::AddedTimestampedGeometryComponentCache)
{
if(Ar.IsLoading())
{
// Strip old recorded cache data
int32 DummyNumFrames;
TArray<TArray<FTransform>> DummyTransforms;
Ar << DummyNumFrames;
DummyTransforms.SetNum(DummyNumFrames);
for(int32 Index = 0; Index < DummyNumFrames; ++Index)
{
Ar << DummyTransforms[Index];
}
}
}
else
{
// Push up the chain to hit tagged properties too
// This should have always been in here but because we have saved assets
// from before this line was here it has to be gated
Super::Serialize(Ar);
}
}
void UGeometryCollection::InvalidateCollection()
{
StateGuid = FGuid::NewGuid();
}
FGuid UGeometryCollection::GetIdGuid() const
{
return PersistentGuid;
}
FGuid UGeometryCollection::GetStateGuid() const
{
return StateGuid;
}
#if WITH_EDITOR
void UGeometryCollection::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
{
InvalidateCollection();
}
#endif
bool UGeometryCollection::Modify(bool bAlwaysMarkDirty /*= true*/)
{
bool bSuperResult = Super::Modify(bAlwaysMarkDirty);
UPackage* Package = GetOutermost();
if(Package->IsDirty())
{
InvalidateCollection();
}
return bSuperResult;
}
void UGeometryCollection::PostLoad()
{
Super::PostLoad();
}

View File

@@ -0,0 +1,162 @@
#include "GeometryCollection/GeometryCollectionRenderLevelSetActor.h"
#include "Chaos/ArrayND.h"
#include "Chaos/Vector.h"
using namespace Chaos;
DEFINE_LOG_CATEGORY_STATIC(LSR_LOG, Log, All);
AGeometryCollectionRenderLevelSetActor::AGeometryCollectionRenderLevelSetActor(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer), SurfaceTolerance(0.01f), Isovalue(0.f), Enabled(true), RenderVolumeBoundingBox(false), DynRayMarchMaterial(NULL), StepSizeMult(1.f)
{
PostProcessComponent = CreateDefaultSubobject<UPostProcessComponent>(TEXT("PostProcessComponent0"));
RootComponent = PostProcessComponent;
// set initial values
// @todo: Need to make this work based on if the module is loaded
#if 0
TargetVolumeTexture = LoadObject<UVolumeTexture>(NULL, TEXT("/GeometryCollectionPlugin/VolumeVisualization/Textures/VolumeToRender"), NULL, LOAD_None, NULL);
UMaterialInterface* MaterialInterface = LoadObject<UMaterialInterface>(NULL, TEXT("/GeometryCollectionPlugin/VolumeVisualization/Materials/M_VolumeRenderSphereTracePP"), NULL, LOAD_None, NULL);
RayMarchMaterial = MaterialInterface ? MaterialInterface->GetBaseMaterial() : nullptr;
#else
TargetVolumeTexture = nullptr;
RayMarchMaterial = nullptr;
#endif
}
void AGeometryCollectionRenderLevelSetActor::BeginPlay()
{
Super::BeginPlay();
// make sure to set enabled on the post process
PostProcessComponent->bEnabled = Enabled;
PostProcessComponent->bUnbound = true;
}
#if WITH_EDITOR
void AGeometryCollectionRenderLevelSetActor::PostEditChangeProperty(struct FPropertyChangedEvent& e)
{
Super::PostEditChangeProperty(e);
// sync all rendering properties each time a param changes.
// @todo: optimize to only update parameters when rendering-specific ones are edited
SyncMaterialParameters();
}
#endif
void AGeometryCollectionRenderLevelSetActor::SyncMaterialParameters()
{
if (!RayMarchMaterial)
{
return;
}
// make dynamic material instance if it hasn't been created yet
if (!DynRayMarchMaterial) {
DynRayMarchMaterial = UMaterialInstanceDynamic::Create(RayMarchMaterial, this);
// add the blendable with our post process material
PostProcessComponent->AddOrUpdateBlendable(DynRayMarchMaterial);
}
// Sync all render parameters to our material
DynRayMarchMaterial->SetScalarParameterValue("Surface Tolerance", SurfaceTolerance);
DynRayMarchMaterial->SetScalarParameterValue("Isovalue", Isovalue);
DynRayMarchMaterial->SetScalarParameterValue("Step Size Mult", StepSizeMult);
DynRayMarchMaterial->SetScalarParameterValue("Voxel Size", VoxelSize);
DynRayMarchMaterial->SetVectorParameterValue("Min Bounds", MinBBoxCorner);
DynRayMarchMaterial->SetVectorParameterValue("Max Bounds", MaxBBoxCorner);
DynRayMarchMaterial->SetVectorParameterValue("WorldToLocalc0", FLinearColor(WorldToLocal.GetColumn(0)));
DynRayMarchMaterial->SetVectorParameterValue("WorldToLocalc1", FLinearColor(WorldToLocal.GetColumn(1)));
DynRayMarchMaterial->SetVectorParameterValue("WorldToLocalc2", FLinearColor(WorldToLocal.GetColumn(2)));
DynRayMarchMaterial->SetVectorParameterValue("WorldToLocalTranslation", FLinearColor(WorldToLocal.GetOrigin()));
DynRayMarchMaterial->SetTextureParameterValue("Volume To Render", TargetVolumeTexture);
DynRayMarchMaterial->SetScalarParameterValue("Debug BBox", (float) RenderVolumeBoundingBox);
PostProcessComponent->bEnabled = Enabled;
}
void AGeometryCollectionRenderLevelSetActor::SyncLevelSetTransform(const FTransform &LocalToWorld)
{
if (!RayMarchMaterial)
{
return;
}
WorldToLocal = LocalToWorld.Inverse().ToMatrixWithScale();
DynRayMarchMaterial->SetVectorParameterValue("WorldToLocalc0", FLinearColor(WorldToLocal.GetColumn(0)));
DynRayMarchMaterial->SetVectorParameterValue("WorldToLocalc1", FLinearColor(WorldToLocal.GetColumn(1)));
DynRayMarchMaterial->SetVectorParameterValue("WorldToLocalc2", FLinearColor(WorldToLocal.GetColumn(2)));
DynRayMarchMaterial->SetVectorParameterValue("WorldToLocalTranslation", FLinearColor(WorldToLocal.GetOrigin()));
}
bool AGeometryCollectionRenderLevelSetActor::SetLevelSetToRender(const Chaos::TLevelSet<float, 3> &LevelSet, const FTransform &LocalToWorld)
{
// error case when the target volume texture isn't set
if (TargetVolumeTexture == NULL) {
UE_LOG(LSR_LOG, Warning, TEXT("Target UVolumeTexture is null on %s"), *GetFullName());
return false;
}
// get refs to the grid structures
const TArrayND<float, 3> &LevelSetPhiArray = LevelSet.GetPhiArray();
const TArrayND<TVector<float, 3>, 3> &LevelSetNormalsArray = LevelSet.GetNormalsArray();
const TUniformGrid<float, 3> &LevelSetGrid = LevelSet.GetGrid();
const TVector<int32, 3> &Counts = LevelSetGrid.Counts();
// set bounding box
MinBBoxCorner = LevelSetGrid.MinCorner();
MaxBBoxCorner = LevelSetGrid.MaxCorner();
WorldToLocal = LocalToWorld.Inverse().ToMatrixWithScale();
// @todo: do we need to deal with non square voxels?
VoxelSize = LevelSetGrid.Dx().X;
// Error case when the voxel size is sufficiently small
if (VoxelSize < 1e-5) {
UE_LOG(LSR_LOG, Warning, TEXT("Voxel size is zero on %s"), *GetFullName());
return false;
}
// lambda for querying the level set information
// @note: x and z swap for volume textures to match TlevelSet
// @todo: we could encode voxel ordering more nicely in the UVolumeTexture
auto QueryVoxel = [&](const int32 x, const int32 y, const int32 z, FFloat16 *ret)
{
float sd = LevelSetPhiArray(TVector<int32, 3>(z, y, x));
TVector<float, 3> n = LevelSetNormalsArray(TVector<int32, 3>(z, y, x));
n.Normalize();
// @note: x and z swap for volume textures to render correctly
ret[0] = n.X;
ret[1] = n.Y;
ret[2] = n.Z;
ret[3] = sd;
};
// fill volume texture from level set
// @note: we swap z and x to match level set in world space
bool success = TargetVolumeTexture->UpdateSourceFromFunction(QueryVoxel, Counts.Z, Counts.Y, Counts.X);
if (!success) {
UE_LOG(LSR_LOG, Warning, TEXT("Couldn't create target volume texture from TLevelSet with %s"), *GetFullName());
return false;
}
// set all parameters on our dynamic material instance to sync state
SyncMaterialParameters();
UE_LOG(LSR_LOG, Log, TEXT("Volume Bounds: %s - %s -- Volume Dims: %d %d %d -- Voxel Size: %f -- World To Local: %s"), *MinBBoxCorner.ToString(), *MaxBBoxCorner.ToString(), Counts.X, Counts.Y, Counts.Z, VoxelSize, *WorldToLocal.ToString());
return true;
}

View File

@@ -0,0 +1,119 @@
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
#include "GeometryCollection/GeometryCollectionSQAccelerator.h"
#include "Physics/Experimental/PhysScene_Chaos.h"
#include "Chaos/PBDRigidParticles.h"
#include "GeometryCollection/ManagedArray.h"
#include "GeometryCollection/GeometryCollectionComponent.h"
#include "GeometryCollection/GeometryCollectionActor.h"
#include "Components/BoxComponent.h"
#include "ChaosSolversModule.h"
#include "ChaosStats.h"
#if INCLUDE_CHAOS
bool LowLevelRaycast(const UGeometryCollectionComponent& GeomCollectionComponent, const FVector& Start, const FVector& Dir, float DeltaMag, EHitFlags OutputFlags, FHitRaycast& OutHit)
{
using namespace Chaos;
const TManagedArray<int32>& RigidBodyIdArray = GeomCollectionComponent.GetRigidBodyIdArray();
bool bFound = false;
if (const Chaos::PBDRigidsSolver* Solver = GeomCollectionComponent.ChaosSolverActor != nullptr ? GeomCollectionComponent.ChaosSolverActor->GetSolver() : FPhysScene_Chaos::GetInstance()->GetSolver())
{
const TPBDRigidParticles<float, 3>& Particles = Solver->GetRigidParticles(); //todo(ocohen): should these just get passed in instead of hopping through scene?
for (int32 Idx = 0; Idx < RigidBodyIdArray.Num(); ++Idx)
{
const int32 RigidBodyIdx = RigidBodyIdArray[Idx];
if (RigidBodyIdx == -1) { continue; } //todo(ocohen): managed to avoid this invalid index, but need to investigate a bit more into whether we can always assume it's valid
if (Particles.Disabled(RigidBodyIdx)) { continue; } //disabled particles can actually have stale geometry in them and are clearly not useful anyway
if (!(ensure(!FMath::IsNaN(Particles.X(RigidBodyIdx)[0])) && ensure(!FMath::IsNaN(Particles.X(RigidBodyIdx)[1])) && ensure(!FMath::IsNaN(Particles.X(RigidBodyIdx)[2]))))
{
continue;
}
const TRigidTransform<float, 3> TM(Particles.X(RigidBodyIdx), Particles.R(RigidBodyIdx));
const TVector<float, 3> StartLocal = TM.InverseTransformPositionNoScale(Start);
const TVector<float, 3> DirLocal = TM.InverseTransformVectorNoScale(Dir);
const TVector<float, 3> EndLocal = StartLocal + DirLocal * DeltaMag; //todo(ocohen): apeiron just undoes this later, we should fix the API
const TImplicitObject<float, 3>* Object = Particles.Geometry(RigidBodyIdx); //todo(ocohen): can this ever be null?
Pair<TVector<float, 3>, bool> Result = Object->FindClosestIntersection(StartLocal, EndLocal, /*Thickness=*/0.f);
if (Result.Second) //todo(ocohen): once we do more than just a bool we need to get the closest point
{
#if WITH_PHYSX
//todo(ocohen): check output flags?
const float Distance = (Result.First - StartLocal).Size();
if (!bFound || Distance < OutHit.distance)
{
OutHit.distance = Distance; //todo(ocohen): assuming physx structs for now
OutHit.position = U2PVector(TM.TransformPositionNoScale(Result.First));
const TVector<float, 3> LocalNormal = Object->Normal(Result.First);
OutHit.normal = U2PVector(TM.TransformVectorNoScale(LocalNormal));
SetFlags(OutHit, EHitFlags::Distance | EHitFlags::Normal | EHitFlags::Position);
}
bFound = true;
#endif
}
}
}
return bFound;
}
void FGeometryCollectionSQAccelerator::Raycast(const FVector& Start, const FVector& Dir, FPhysicsHitCallback<FHitRaycast>& HitBuffer, EHitFlags OutputFlags, FQueryFlags QueryFlags, const FCollisionFilterData& QueryFilter, FCollisionQueryFilterCallback& QueryCallback) const
{
// #BGallagher Temp lock semantics. Essentially this guarantees t or t+1 depending on which is closer by stalling
// the physics thread at the next update step so we can perform the query. Long term we want multiple methods for
// queries as t-1 can be made much cheaper for applications where immediate results don't matter.
FChaosScopedPhysicsThreadLock ThreadLock;
SCOPE_CYCLE_COUNTER(STAT_GCRaycast);
#if WITH_PHYSX
for (const UGeometryCollectionComponent* GeomCollectionComponent : Components)
{
FHitRaycast Hit;
if (LowLevelRaycast(*GeomCollectionComponent, Start, Dir, GetCurrentBlockTraceDistance(HitBuffer), OutputFlags, Hit)) //assume all blocking hits for now
{
#if !WITH_IMMEDIATE_PHYSX && PHYSICS_INTERFACE_PHYSX
//todo(ocohen):hack placeholder while we convert over to non physx API
const FPhysicsActorHandle& ActorHandle = GeomCollectionComponent->DummyBoxComponent->BodyInstance.GetPhysicsActorHandle();
PxRigidActor* PRigidActor = ActorHandle.SyncActor;
uint32 PNumShapes = PRigidActor->getNbShapes();
TArray<PxShape*> PShapes;
PShapes.AddZeroed(PNumShapes);
PRigidActor->getShapes(PShapes.GetData(), sizeof(PShapes[0]) * PNumShapes);
SetActor(Hit, ActorHandle.SyncActor);
SetShape(Hit, PShapes[0]);
#else
check(false); //this can't actually return nullptr since higher up API assumes both shape and actor exists in the low level
SetActor(Hit, nullptr);
SetShape(Hit, nullptr); //todo(ocohen): what do we return for apeiron?
#endif
Insert(HitBuffer, Hit, true); //for now assume all blocking hits
}
}
#endif
}
void FGeometryCollectionSQAccelerator::Sweep(const FPhysicsGeometry& QueryGeom, const FTransform& StartTM, const FVector& Dir, FPhysicsHitCallback<FHitSweep>& HitBuffer, EHitFlags OutputFlags, FQueryFlags QueryFlags, const FCollisionFilterData& QueryFilter, FCollisionQueryFilterCallback& QueryCallback) const
{
}
void FGeometryCollectionSQAccelerator::Overlap(const FPhysicsGeometry& QueryGeom, const FTransform& GeomPose, FPhysicsHitCallback<FHitOverlap>& HitBuffer, FQueryFlags QueryFlags, const FCollisionFilterData& QueryFilter, FCollisionQueryFilterCallback& QueryCallback) const
{
}
void FGeometryCollectionSQAccelerator::AddComponent(UGeometryCollectionComponent* Component)
{
Components.Add(Component);
}
void FGeometryCollectionSQAccelerator::RemoveComponent(UGeometryCollectionComponent* Component)
{
Components.Remove(Component);
}
#endif

View File

@@ -0,0 +1,24 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Physics/SQAccelerator.h"
#if INCLUDE_CHAOS
class UGeometryCollectionComponent;
class FGeometryCollectionSQAccelerator : public ISQAccelerator
{
public:
virtual void Raycast(const FVector& Start, const FVector& Dir, FPhysicsHitCallback<FHitRaycast>& HitBuffer, EHitFlags OutputFlags, FQueryFlags QueryFlags, const FCollisionFilterData& QueryFilter, FCollisionQueryFilterCallback& QueryCallback) const override;
virtual void Sweep(const FPhysicsGeometry& QueryGeom, const FTransform& StartTM, const FVector& Dir, FPhysicsHitCallback<FHitSweep>& HitBuffer, EHitFlags OutputFlags, FQueryFlags QueryFlags, const FCollisionFilterData& QueryFilter, FCollisionQueryFilterCallback& QueryCallback) const override;
virtual void Overlap(const FPhysicsGeometry& QueryGeom, const FTransform& GeomPose, FPhysicsHitCallback<FHitOverlap>& HitBuffer, FQueryFlags QueryFlags, const FCollisionFilterData& QueryFilter, FCollisionQueryFilterCallback& QueryCallback) const override;
virtual ~FGeometryCollectionSQAccelerator() {}
void AddComponent(UGeometryCollectionComponent* Component);
void RemoveComponent(UGeometryCollectionComponent* Component);
private:
TSet<UGeometryCollectionComponent*> Components;
};
#endif

View File

@@ -0,0 +1,345 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "GeometryCollection/GeometryCollectionSceneProxy.h"
#include "Async/ParallelFor.h"
#include "Engine/Engine.h"
#include "Materials/Material.h"
#include "GeometryCollection/GeometryCollectionComponent.h"
DEFINE_LOG_CATEGORY_STATIC(FGeometryCollectionSceneProxyLogging, Log, All);
FGeometryCollectionSceneProxy::FGeometryCollectionSceneProxy(UGeometryCollectionComponent* Component)
: FPrimitiveSceneProxy(Component)
, MaterialRelevance(Component->GetMaterialRelevance(GetScene().GetFeatureLevel()))
, NumVertices(0)
, NumIndices(0)
, VertexFactory(GetScene().GetFeatureLevel(), "FGeometryCollectionSceneProxy")
, DynamicData(nullptr)
, ConstantData(nullptr)
, ShowBoneColors(Component->GetShowBoneColors())
, ShowSelectedBones(Component->GetShowSelectedBones())
, BoneSelectionMaterialID(Component->GetBoneSelectedMaterialID())
{
Materials.Empty();
for (int MaterialIndex = 0; MaterialIndex < Component->GetNumMaterials(); MaterialIndex++)
{
Materials.Push(Component->GetMaterial(MaterialIndex));
if (Materials[MaterialIndex] == nullptr)
{
Materials[MaterialIndex] = UMaterial::GetDefaultMaterial(MD_Surface);
}
}
}
FGeometryCollectionSceneProxy::~FGeometryCollectionSceneProxy()
{
ReleaseResources();
if (DynamicData != nullptr)
{
delete DynamicData;
}
if (ConstantData != nullptr)
{
delete ConstantData;
}
}
void FGeometryCollectionSceneProxy::InitResources()
{
check(ConstantData);
NumVertices = ConstantData->Vertices.Num();
NumIndices = ConstantData->Indices.Num()*3;
VertexBuffers.InitWithDummyData(&VertexFactory, GetRequiredVertexCount());
IndexBuffer.NumIndices = GetRequiredIndexCount();
BeginInitResource(&IndexBuffer);
}
void FGeometryCollectionSceneProxy::ReleaseResources()
{
VertexBuffers.PositionVertexBuffer.ReleaseResource();
VertexBuffers.StaticMeshVertexBuffer.ReleaseResource();
VertexBuffers.ColorVertexBuffer.ReleaseResource();
IndexBuffer.ReleaseResource();
VertexFactory.ReleaseResource();
}
void FGeometryCollectionSceneProxy::BuildGeometry( const FGeometryCollectionConstantData* ConstantDataIn, TArray<FDynamicMeshVertex>& OutVertices, TArray<int32>& OutIndices)
{
OutVertices.SetNumUninitialized(ConstantDataIn->Vertices.Num());
ParallelFor(ConstantData->Vertices.Num(), [&](int32 PointIdx)
{
OutVertices[PointIdx] =
FDynamicMeshVertex(
ConstantDataIn->Vertices[PointIdx],
ConstantDataIn->UVs[PointIdx],
ShowBoneColors||ShowSelectedBones ?
ConstantDataIn->BoneColors[PointIdx].ToFColor(true) :
ConstantDataIn->Colors[PointIdx].ToFColor(true)
);
OutVertices[PointIdx].SetTangents(ConstantDataIn->TangentU[PointIdx], ConstantDataIn->TangentV[PointIdx], ConstantDataIn->Normals[PointIdx]);
});
check(ConstantDataIn->Indices.Num() * 3 == NumIndices);
OutIndices.SetNumUninitialized(NumIndices);
ParallelFor (ConstantDataIn->Indices.Num(), [&](int32 IndexIdx)
{
OutIndices[IndexIdx * 3 ] = ConstantDataIn->Indices[IndexIdx].X;
OutIndices[IndexIdx * 3 + 1] = ConstantDataIn->Indices[IndexIdx].Y;
OutIndices[IndexIdx * 3 + 2] = ConstantDataIn->Indices[IndexIdx].Z;
});
}
void FGeometryCollectionSceneProxy::SetConstantData_RenderThread(FGeometryCollectionConstantData* NewConstantData, bool ForceInit)
{
check(IsInRenderingThread());
check(NewConstantData);
if (ConstantData)
{
delete ConstantData;
ConstantData = nullptr;
}
ConstantData = NewConstantData;
if (ConstantData->Vertices.Num() != VertexBuffers.PositionVertexBuffer.GetNumVertices() || ForceInit)
{
ReleaseResources();
InitResources();
}
TArray<int32> Indices;
TArray<FDynamicMeshVertex> Vertices;
BuildGeometry(ConstantData, Vertices, Indices);
check(Vertices.Num() == GetRequiredVertexCount());
check(Indices.Num() == GetRequiredIndexCount());
if (GetRequiredVertexCount())
{
ParallelFor(Vertices.Num(), [&](int32 i)
{
const FDynamicMeshVertex& Vertex = Vertices[i];
VertexBuffers.PositionVertexBuffer.VertexPosition(i) = Vertex.Position;
VertexBuffers.StaticMeshVertexBuffer.SetVertexTangents(i, Vertex.TangentX.ToFVector(), Vertex.GetTangentY(), Vertex.TangentZ.ToFVector());
VertexBuffers.StaticMeshVertexBuffer.SetVertexUV(i, 0, Vertex.TextureCoordinate[0]);
VertexBuffers.ColorVertexBuffer.VertexColor(i) = Vertex.Color;
});
{
auto& VertexBuffer = VertexBuffers.PositionVertexBuffer;
void* VertexBufferData = RHILockVertexBuffer(VertexBuffer.VertexBufferRHI, 0, VertexBuffer.GetNumVertices() * VertexBuffer.GetStride(), RLM_WriteOnly);
FMemory::Memcpy(VertexBufferData, VertexBuffer.GetVertexData(), VertexBuffer.GetNumVertices() * VertexBuffer.GetStride());
RHIUnlockVertexBuffer(VertexBuffer.VertexBufferRHI);
}
{
auto& VertexBuffer = VertexBuffers.ColorVertexBuffer;
void* VertexBufferData = RHILockVertexBuffer(VertexBuffer.VertexBufferRHI, 0, VertexBuffer.GetNumVertices() * VertexBuffer.GetStride(), RLM_WriteOnly);
FMemory::Memcpy(VertexBufferData, VertexBuffer.GetVertexData(), VertexBuffer.GetNumVertices() * VertexBuffer.GetStride());
RHIUnlockVertexBuffer(VertexBuffer.VertexBufferRHI);
}
{
auto& VertexBuffer = VertexBuffers.StaticMeshVertexBuffer;
void* VertexBufferData = RHILockVertexBuffer(VertexBuffer.TangentsVertexBuffer.VertexBufferRHI, 0, VertexBuffer.GetTangentSize(), RLM_WriteOnly);
FMemory::Memcpy(VertexBufferData, VertexBuffer.GetTangentData(), VertexBuffer.GetTangentSize());
RHIUnlockVertexBuffer(VertexBuffer.TangentsVertexBuffer.VertexBufferRHI);
}
{
auto& VertexBuffer = VertexBuffers.StaticMeshVertexBuffer;
void* VertexBufferData = RHILockVertexBuffer(VertexBuffer.TexCoordVertexBuffer.VertexBufferRHI, 0, VertexBuffer.GetTexCoordSize(), RLM_WriteOnly);
FMemory::Memcpy(VertexBufferData, VertexBuffer.GetTexCoordData(), VertexBuffer.GetTexCoordSize());
RHIUnlockVertexBuffer(VertexBuffer.TexCoordVertexBuffer.VertexBufferRHI);
}
{
void* IndexBufferData = RHILockIndexBuffer(IndexBuffer.IndexBufferRHI, 0, Indices.Num() * sizeof(int32), RLM_WriteOnly);
FMemory::Memcpy(IndexBufferData, &Indices[0], Indices.Num() * sizeof(int32));
RHIUnlockIndexBuffer(IndexBuffer.IndexBufferRHI);
}
Sections.Empty();
for (FGeometryCollectionSection Section : ConstantData->Sections)
{
if (Section.NumTriangles > 0)
{
FGeometryCollectionSection NewSection;
NewSection.MaterialID = Section.MaterialID;
NewSection.FirstIndex = Section.FirstIndex;
NewSection.NumTriangles = Section.NumTriangles;
NewSection.MinVertexIndex = Section.MinVertexIndex;
NewSection.MaxVertexIndex = Section.MaxVertexIndex;
Sections.Add(NewSection);
}
}
}
}
void FGeometryCollectionSceneProxy::SetDynamicData_RenderThread(FGeometryCollectionDynamicData* NewDynamicData)
{
check(IsInRenderingThread());
if (GetRequiredVertexCount())
{
if (DynamicData)
{
delete DynamicData;
DynamicData = nullptr;
}
DynamicData = NewDynamicData;
check(VertexBuffers.PositionVertexBuffer.GetNumVertices() == (uint32)ConstantData->Vertices.Num());
ParallelFor(ConstantData->Vertices.Num(), [&](int32 i)
{
VertexBuffers.PositionVertexBuffer.VertexPosition(i) = DynamicData->Transforms[ConstantData->BoneMap[i]].TransformPosition(ConstantData->Vertices[i]);
});
{
auto& VertexBuffer = VertexBuffers.PositionVertexBuffer;
void* VertexBufferData = RHILockVertexBuffer(VertexBuffer.VertexBufferRHI, 0, VertexBuffer.GetNumVertices() * VertexBuffer.GetStride(), RLM_WriteOnly);
FMemory::Memcpy(VertexBufferData, VertexBuffer.GetVertexData(), VertexBuffer.GetNumVertices() * VertexBuffer.GetStride());
RHIUnlockVertexBuffer(VertexBuffer.VertexBufferRHI);
}
}
}
FMaterialRenderProxy* FGeometryCollectionSceneProxy::GetMaterial(FMeshElementCollector& Collector, int32 MaterialIndex) const
{
// material for wireframe
auto WireframeMaterialInstance = new FColoredMaterialRenderProxy(
GEngine->WireframeMaterial ? GEngine->WireframeMaterial->GetRenderProxy(IsSelected()) : nullptr,
FLinearColor(0, 0.5f, 1.f)
);
Collector.RegisterOneFrameMaterialProxy(WireframeMaterialInstance);
// material for colored bones
UMaterial* VertexColorVisualizationMaterial = GEngine->VertexColorMaterial;
auto VertexColorVisualizationMaterialInstance = new FColoredMaterialRenderProxy(
VertexColorVisualizationMaterial->GetRenderProxy(false, false),
GetSelectionColor(FLinearColor::White, false, false)
);
Collector.RegisterOneFrameMaterialProxy(VertexColorVisualizationMaterialInstance);
FMaterialRenderProxy* MaterialProxy = nullptr;
if (ShowBoneColors)
{
MaterialProxy = VertexColorVisualizationMaterialInstance;
}
else
{
MaterialProxy = Materials[MaterialIndex]->GetRenderProxy(IsSelected());
}
if (MaterialProxy == nullptr)
{
MaterialProxy = UMaterial::GetDefaultMaterial(MD_Surface)->GetRenderProxy(IsSelected(), IsHovered());
}
return MaterialProxy;
}
void FGeometryCollectionSceneProxy::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_GeometryCollectionSceneProxy_GetDynamicMeshElements);
if (GetRequiredVertexCount())
{
const bool bWireframe = AllowDebugViewmodes() && ViewFamily.EngineShowFlags.Wireframe;
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
//Grab the material proxies we'll be using for each section
TArray<FMaterialRenderProxy*, TInlineAllocator<32>> MaterialProxies;
for (int SectionIndex = 0; SectionIndex < Sections.Num(); SectionIndex++)
{
const FGeometryCollectionSection& Section = Sections[SectionIndex];
FMaterialRenderProxy* MaterialProxy = GetMaterial(Collector, Section.MaterialID);
MaterialProxies.Add(MaterialProxy);
}
// Render Batches
for (int SectionIndex = 0; SectionIndex < Sections.Num(); SectionIndex++)
{
const FGeometryCollectionSection& Section = Sections[SectionIndex];
if (VisibilityMap & (1 << ViewIndex))
{
const FSceneView* View = Views[ViewIndex];
// Draw the mesh.
FMeshBatch& Mesh = Collector.AllocateMesh();
FMeshBatchElement& BatchElement = Mesh.Elements[0];
BatchElement.IndexBuffer = &IndexBuffer;
Mesh.bWireframe = bWireframe;
Mesh.VertexFactory = &VertexFactory;
Mesh.MaterialRenderProxy = MaterialProxies[SectionIndex];
BatchElement.PrimitiveUniformBuffer = CreatePrimitiveUniformBufferImmediate(GetLocalToWorld(), GetBounds(), GetLocalBounds(), true, UseEditorDepthTest());
BatchElement.FirstIndex = Section.FirstIndex;
BatchElement.NumPrimitives = Section.NumTriangles;
BatchElement.MinVertexIndex = Section.MinVertexIndex;
BatchElement.MaxVertexIndex = Section.MaxVertexIndex;
Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative();
Mesh.Type = PT_TriangleList;
Mesh.DepthPriorityGroup = SDPG_World;
Mesh.bCanApplyViewModeOverrides = false;
Collector.AddMesh(ViewIndex, Mesh);
}
}
// Highlight selected bone using specialized material - when rendering bones as colors we don't need to run this code as the
// bone selection is already contained in the rendered colors
if (ShowBoneColors||ShowSelectedBones)
{
FMaterialRenderProxy* MaterialRenderProxy = Materials[BoneSelectionMaterialID]->GetRenderProxy(IsSelected());
if (VisibilityMap & (1 << ViewIndex))
{
const FSceneView* View = Views[ViewIndex];
FMeshBatch& Mesh = Collector.AllocateMesh();
FMeshBatchElement& BatchElement = Mesh.Elements[0];
BatchElement.IndexBuffer = &IndexBuffer;
Mesh.bWireframe = bWireframe;
Mesh.VertexFactory = &VertexFactory;
Mesh.MaterialRenderProxy = MaterialRenderProxy;
BatchElement.PrimitiveUniformBuffer = CreatePrimitiveUniformBufferImmediate(GetLocalToWorld(), GetBounds(), GetLocalBounds(), true, UseEditorDepthTest());
BatchElement.FirstIndex = 0;
BatchElement.NumPrimitives = GetRequiredIndexCount() / 3;
BatchElement.MinVertexIndex = 0;
BatchElement.MaxVertexIndex = GetRequiredVertexCount();
Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative();
Mesh.Type = PT_TriangleList;
Mesh.DepthPriorityGroup = SDPG_World;
Mesh.bCanApplyViewModeOverrides = false;
Collector.AddMesh(ViewIndex, Mesh);
}
}
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if(VisibilityMap & (1 << ViewIndex))
{
RenderBounds(Collector.GetPDI(ViewIndex), ViewFamily.EngineShowFlags, GetBounds(), IsSelected());
}
#endif
}
}
}
FPrimitiveViewRelevance FGeometryCollectionSceneProxy::GetViewRelevance(const FSceneView* View) const
{
FPrimitiveViewRelevance Result;
Result.bDrawRelevance = IsShown(View);
Result.bShadowRelevance = IsShadowCast(View);
Result.bDynamicRelevance = true;
MaterialRelevance.SetPrimitiveViewRelevance(Result);
return Result;
}

View File

@@ -0,0 +1,134 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "DynamicMeshBuilder.h"
#include "EngineGlobals.h"
#include "PrimitiveViewRelevance.h"
#include "PrimitiveSceneProxy.h"
#include "StaticMeshResources.h"
#include "Rendering/SkinWeightVertexBuffer.h"
class UGeometryCollectionComponent;
struct FGeometryCollectionSection;
/** Index Buffer */
class FGeometryCollectionIndexBuffer : public FIndexBuffer
{
public:
virtual void InitRHI() override
{
FRHIResourceCreateInfo CreateInfo;
IndexBufferRHI = RHICreateIndexBuffer(sizeof(int32), NumIndices * sizeof(int32), BUF_Dynamic, CreateInfo);
}
int32 NumIndices;
};
/** Immutable rendering data (kind of) */
struct FGeometryCollectionConstantData
{
TArray<FVector> Vertices;
TArray<FIntVector> Indices;
TArray<FVector> Normals;
TArray<FVector> TangentU;
TArray<FVector> TangentV;
TArray<FVector2D> UVs;
TArray<FLinearColor> Colors;
TArray<uint16> BoneMap;
TArray<FLinearColor> BoneColors;
TArray<FGeometryCollectionSection> Sections;
};
/** Mutable rendering data */
struct FGeometryCollectionDynamicData
{
TArray<FMatrix> Transforms;
};
/***
* FGeometryCollectionSceneProxy
*
* The FGeometryCollectionSceneProxy manages the interaction between the GeometryCollectionComponent
* on the game thread and the vertex buffers on the render thread.
*
* NOTE : This class is still in flux, and has a few pending todos. Your comments and
* thoughts are appreciated though. The remaining items to address involve:
* - @todo double buffer - The double buffering of the FGeometryCollectionDynamicData.
* - @todo previous state - Saving the previous FGeometryCollectionDynamicData for rendering motion blur.
* - @todo shared memory model - The Asset(or Actor?) should hold the Vertex buffer, and pass the reference to the SceneProxy
* - @todo GPU skin : Make the skinning use the GpuVertexShader
*/
class FGeometryCollectionSceneProxy final : public FPrimitiveSceneProxy
{
TArray<UMaterialInterface*> Materials;
FMaterialRelevance MaterialRelevance;
int32 NumVertices;
int32 NumIndices;
FLocalVertexFactory VertexFactory;
FStaticMeshVertexBuffers VertexBuffers;
FGeometryCollectionIndexBuffer IndexBuffer;
TArray<FGeometryCollectionSection> Sections;
FGeometryCollectionDynamicData* DynamicData;
FGeometryCollectionConstantData* ConstantData;
bool ShowBoneColors;
bool ShowSelectedBones;
int BoneSelectionMaterialID;
public:
SIZE_T GetTypeHash() const override
{
static size_t UniquePointer;
return reinterpret_cast<size_t>(&UniquePointer);
}
FGeometryCollectionSceneProxy(UGeometryCollectionComponent* Component);
/** virtual destructor */
virtual ~FGeometryCollectionSceneProxy();
/** Current number of vertices to render */
int32 GetRequiredVertexCount() const { return NumVertices;}
/** Current number of indices to connect */
int32 GetRequiredIndexCount() const { return NumIndices; }
/** Called on render thread to setup static geometry for rendering */
void SetConstantData_RenderThread(FGeometryCollectionConstantData* NewConstantData, bool ForceInit = false);
/** Called on render thread to setup dynamic geometry for rendering */
void SetDynamicData_RenderThread(FGeometryCollectionDynamicData* NewDynamicData);
/** Called on render thread to construct the vertex definitions */
void BuildGeometry(const FGeometryCollectionConstantData* ConstantDataIn, TArray<FDynamicMeshVertex>& OutVertices, TArray<int32>& OutIndices);
/** Called on render thread to setup dynamic geometry for rendering */
virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override;
/** Manage the view assignment */
virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override;
// @todo allocated size : make this reflect internally allocated memory.
virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
/** Size of the base class */
uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
protected:
/** Create the rendering buffer resources */
void InitResources();
/** Return the rendering buffer resources */
void ReleaseResources();
/** Get material proxy from material ID */
FMaterialRenderProxy* GetMaterial(FMeshElementCollector& Collector, int32 MaterialIndex) const;
};

View File

@@ -0,0 +1,193 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "GeometryCollection/StaticMeshSimulationComponent.h"
#include "Async/ParallelFor.h"
#include "Components/BoxComponent.h"
#include "GeometryCollection/GeometryCollectionSimulationTypes.h"
#include "GeometryCollection/StaticMeshSolverCallbacks.h"
#include "Physics/Experimental/PhysScene_Chaos.h"
#include "Chaos/DebugDrawQueue.h"
#include "DrawDebugHelpers.h"
#include "GeometryCollection/StaticMeshSimulationComponentPhysicsProxy.h"
#include "Modules/ModuleManager.h"
#include "ChaosSolversModule.h"
#include "Components/StaticMeshComponent.h"
#include "Engine/StaticMesh.h"
DEFINE_LOG_CATEGORY_STATIC(UStaticMeshSimulationComponentLogging, NoLogging, All);
UStaticMeshSimulationComponent::UStaticMeshSimulationComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, Simulating(false)
, ObjectType(EObjectTypeEnum::Chaos_Object_Dynamic)
, Mass(1.0)
, CollisionType(ECollisionTypeEnum::Chaos_Surface_Volumetric)
, InitialVelocityType(EInitialVelocityTypeEnum::Chaos_Initial_Velocity_User_Defined)
, Friction(0.8)
, Bouncyness(0.0)
, ChaosSolverActor(nullptr)
{
}
void UStaticMeshSimulationComponent::BeginPlay()
{
Super::BeginPlay();
#if INCLUDE_CHAOS
// #BG TODO - Find a better place for this - something that gets hit once on scene begin.
FChaosSolversModule* ChaosModule = FModuleManager::Get().GetModulePtr<FChaosSolversModule>("ChaosSolvers");
Chaos::PBDRigidsSolver* Solver = ChaosSolverActor != nullptr ? ChaosSolverActor->GetSolver() : FPhysScene_Chaos::GetInstance()->GetSolver();
ChaosModule->GetDispatcher()->EnqueueCommand(Solver,
[InFriction = Friction
, InRestitution = Bouncyness
, InCollisionIters = ChaosSolverActor != nullptr ? ChaosSolverActor->CollisionIterations : 5
, InPushOutIters = ChaosSolverActor != nullptr ? ChaosSolverActor->PushOutIterations : 1
, InPushOutPairIters = ChaosSolverActor != nullptr ? ChaosSolverActor->PushOutPairIterations : 1
, InCollisionDataSizeMax = ChaosSolverActor != nullptr ? ChaosSolverActor->CollisionDataSizeMax : 1024
, InCollisionDataTimeWindow = ChaosSolverActor != nullptr ? ChaosSolverActor->CollisionDataTimeWindow : 0.1
, InHasFloor = ChaosSolverActor != nullptr ? ChaosSolverActor->HasFloor : true
, InFloorHeight = ChaosSolverActor != nullptr ? ChaosSolverActor->FloorHeight : 0.f]
(Chaos::PBDRigidsSolver* InSolver)
{
InSolver->SetFriction(InFriction);
InSolver->SetRestitution(InRestitution);
InSolver->SetIterations(InCollisionIters);
InSolver->SetPushOutIterations(InPushOutIters);
InSolver->SetPushOutPairIterations(InPushOutPairIters);
InSolver->SetMaxCollisionDataSize(InCollisionDataSizeMax);
InSolver->SetCollisionDataTimeWindow(InCollisionDataTimeWindow);
InSolver->SetHasFloor(InHasFloor);
InSolver->SetFloorHeight(InFloorHeight);
InSolver->SetEnabled(true);
});
#endif
}
#if INCLUDE_CHAOS
Chaos::PBDRigidsSolver* GetSolver(const UStaticMeshSimulationComponent& StaticMeshSimulationComponent)
{
return StaticMeshSimulationComponent.ChaosSolverActor != nullptr ? StaticMeshSimulationComponent.ChaosSolverActor->GetSolver() : FPhysScene_Chaos::GetInstance()->GetSolver();
}
#endif
void UStaticMeshSimulationComponent::EndPlay(EEndPlayReason::Type ReasonEnd)
{
#if INCLUDE_CHAOS
// @todo : This needs to be removed from the component.
Chaos::PBDRigidsSolver* Solver = GetSolver(*this);
ensure(Solver);
FChaosSolversModule* ChaosModule = FModuleManager::Get().GetModulePtr<FChaosSolversModule>("ChaosSolvers");
ChaosModule->GetDispatcher()->EnqueueCommand(Solver, [](Chaos::PBDRigidsSolver* InSolver)
{
InSolver->Reset();
});
#endif
Super::EndPlay(ReasonEnd);
}
void UStaticMeshSimulationComponent::OnCreatePhysicsState()
{
// Skip the chain - don't care about body instance setup
UActorComponent::OnCreatePhysicsState();
#if INCLUDE_CHAOS
const bool bValidWorld = GetWorld() && GetWorld()->IsGameWorld();
// Need to see if we actually have a target for the component
AActor* OwningActor = GetOwner();
UStaticMeshComponent* TargetComponent = OwningActor->FindComponentByClass<UStaticMeshComponent>();
if(bValidWorld && TargetComponent)
{
auto InitFunc = [this, TargetComponent](FStaticMeshSolverCallbacks::Params& InParams)
{
GetPathName(this, InParams.Name);
InParams.InitialTransform = GetOwner()->GetTransform();
if(InitialVelocityType == EInitialVelocityTypeEnum::Chaos_Initial_Velocity_User_Defined)
{
InParams.InitialLinearVelocity = InitialLinearVelocity;
InParams.InitialAngularVelocity = InitialAngularVelocity;
}
InParams.Mass = Mass;
InParams.ObjectType = ObjectType;
UStaticMesh* StaticMesh = TargetComponent->GetStaticMesh();
if(StaticMesh)
{
FStaticMeshVertexBuffers& VB = StaticMesh->RenderData->LODResources[0].VertexBuffers;
const int32 NumVerts = VB.PositionVertexBuffer.GetNumVertices();
InParams.MeshVertexPositions.Reset(NumVerts);
for(int32 VertexIndex = 0; VertexIndex < NumVerts; ++VertexIndex)
{
InParams.MeshVertexPositions.Add(VB.PositionVertexBuffer.VertexPosition(VertexIndex));
}
if(NumVerts > 0)
{
TargetComponent->SetMobility(EComponentMobility::Movable);
InParams.bSimulating = Simulating;
}
}
};
auto SyncFunc = [TargetComponent](const FTransform& InTransform)
{
TargetComponent->SetWorldTransform(InTransform);
};
PhysicsProxy = new FStaticMeshSimulationComponentPhysicsProxy(InitFunc, SyncFunc);
TSharedPtr<FPhysScene_Chaos> Scene = GetPhysicsScene();
Scene->AddProxy(PhysicsProxy);
}
#endif
}
void UStaticMeshSimulationComponent::OnDestroyPhysicsState()
{
UActorComponent::OnDestroyPhysicsState();
#if INCLUDE_CHAOS
if(PhysicsProxy)
{
// Handle scene remove, right now we rely on the reset of EndPlay to clean up
TSharedPtr<FPhysScene_Chaos> Scene = GetPhysicsScene();
Scene->RemoveProxy(PhysicsProxy);
// Discard the pointer
PhysicsProxy = nullptr;
}
#endif
}
bool UStaticMeshSimulationComponent::ShouldCreatePhysicsState() const
{
return true;
}
bool UStaticMeshSimulationComponent::HasValidPhysicsState() const
{
return PhysicsProxy != nullptr;
}
#if INCLUDE_CHAOS
const TSharedPtr<FPhysScene_Chaos> UStaticMeshSimulationComponent::GetPhysicsScene() const
{
if (ChaosSolverActor)
{
return ChaosSolverActor->GetPhysicsScene();
}
else
{
return FPhysScene_Chaos::GetInstance();
}
}
#endif

View File

@@ -0,0 +1,71 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#pragma once
/** This class represents an GeometryCollection Actor. */
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "GeometryCollection/GeometryCollection.h"
#include "GeometryCollection/GeometryCollectionComponent.h"
#include "GeometryCollection/GeometryCollectionDebugDrawComponent.h"
#include "Physics/Experimental/PhysScene_Chaos.h"
#include "Physics/Experimental/PhysScene_LLImmediate.h"
#include "Physics/ImmediatePhysics/ImmediatePhysicsActorHandle.h"
#include "UObject/ObjectMacros.h"
#include "GeometryCollectionActor.generated.h"
UCLASS()
class GEOMETRYCOLLECTIONENGINE_API AGeometryCollectionActor: public AActor
{
GENERATED_UCLASS_BODY()
public:
/* Game state callback */
virtual void Tick(float DeltaSeconds) override;
/* GeometryCollectionComponent */
UPROPERTY(VisibleAnywhere, Category = Destruction, meta = (ExposeFunctionCategories = "Components|GeometryCollection", AllowPrivateAccess = "true"))
UGeometryCollectionComponent* GeometryCollectionComponent;
UGeometryCollectionComponent* GetGeometryCollectionComponent() const { return GeometryCollectionComponent; }
UPROPERTY(VisibleAnywhere, Category = Destruction, meta = (ExposeFunctionCategories = "Components|GeometryCollection", AllowPrivateAccess = "true"))
UGeometryCollectionDebugDrawComponent* GeometryCollectionDebugDrawComponent;
UGeometryCollectionDebugDrawComponent* GetGeometryCollectionDebugDrawComponent() const { return GeometryCollectionDebugDrawComponent; }
UFUNCTION(BlueprintCallable, Category = "Physics")
bool RaycastSingle(FVector Start, FVector End, FHitResult& OutHit) const;
#if ! INCLUDE_CHAOS
/// Stub support for Immediate mode.
public:
void StartFrameCallback(float EndFrame);
void CreateRigidBodyCallback(FSolverCallbacks::FParticlesType& Particles);
void EndFrameCallback(float EndFrame);
void UpdateKinematicBodiesCallback(FSolverCallbacks::FParticlesType& Particles, const float Dt, const float Time, const int32 Index);
void ParameterUpdateCallback(FSolverCallbacks::FParticlesType& Particles, const float Time);
void DisableCollisionsCallback(TSet<TTuple<int32, int32>>& CollisionPairs);
void AddConstraintCallback(FSolverCallbacks::FParticlesType& Particles, const float Time);
void AddForceCallback(FSolverCallbacks::FParticlesType& Particles, const float Dt, const int32 Index);
private:
FPhysScene_LLImmediate Scene;
bool bInitializedState;
TSharedRef< TManagedArray<int32> > RigidBodyIdArray;
TSharedRef< TManagedArray<FVector> > CenterOfMassArray;
#endif
};

View File

@@ -0,0 +1,79 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GeometryCollection/RecordedTransformTrack.h"
#include "GeometryCollectionCache.generated.h"
class UGeometryCollection;
GEOMETRYCOLLECTIONENGINE_API DECLARE_LOG_CATEGORY_EXTERN(LogGeometryCollectionCache, Log, All);
UCLASS(Experimental)
class GEOMETRYCOLLECTIONENGINE_API UGeometryCollectionCache : public UObject
{
GENERATED_BODY()
public:
/** Tagnames for asset registry tags */
static FName TagName_Name; // Name of the cache
static FName TagName_IdGuid; // ID GUID for the cache - never changes for a given cache
static FName TagName_StateGuid; // State GUID - changes when an edit is made to
/**
* Given a raw track with transforms per-particle on each frame record, set to this cache
* and strip out any data we don't need (transform repeats and disabled particles etc.)
*/
void SetFromRawTrack(const FRecordedTransformTrack& InTrack);
/** Set directly from a track, does not do any data stripping. */
void SetFromTrack(const FRecordedTransformTrack& InTrack);
/** Sets the geometry collection that this cache supports, empties the recorded data in this cache */
void SetSupportedCollection(UGeometryCollection* InCollection);
/** UObject Interface */
virtual void GetAssetRegistryTags(TArray<FAssetRegistryTag>& OutTags) const override;
/** End UObject Interface */
/** Access the recorded tracks */
const FRecordedTransformTrack* GetData() const { return &RecordedData; }
/** Given a collection, create an empty compatible cache for it */
static UGeometryCollectionCache* CreateCacheForCollection(UGeometryCollection* InCollection);
/** Get the GUID for the state of the supported collection when this cache was last recorded to. */
FGuid GetCompatibleStateGuid() const { return CompatibleCollectionState; }
private:
void ProcessRawRecordedDataInternal(const FRecordedTransformTrack& InTrack);
/** The recorded data from the simulation */
UPROPERTY()
FRecordedTransformTrack RecordedData;
/** The collection that we recorded the data from */
UPROPERTY()
UGeometryCollection* SupportedCollection;
/** Guid pulled from the collection when the recording was last saved */
UPROPERTY()
FGuid CompatibleCollectionState;
};
/**
* Provider for target caches when recording is requested but we don't have a target cache
* Initial purpose is to allow an opaque way to call some editor system to generate new assets
* but this could be expanded later for runtime recording and playback if the need arises
*/
class GEOMETRYCOLLECTIONENGINE_API ITargetCacheProvider : public IModularFeature
{
public:
static FName GetFeatureName() { return "GeometryCollectionTargetCacheProvider"; }
virtual UGeometryCollectionCache* GetCacheForCollection(UGeometryCollection* InCollection) = 0;
};

View File

@@ -0,0 +1,419 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Components/MeshComponent.h"
#include "Chaos/ChaosSolverActor.h"
#include "Field/FieldSystem.h"
#include "Field/FieldSystemActor.h"
#include "GameFramework/Actor.h"
#include "GeometryCollection/GeometryCollection.h"
#include "GeometryCollection/GeometryCollectionSimulationTypes.h"
#include "GeometryCollection/GeometryCollectionSolverCallbacks.h"
#include "Physics/Experimental/PhysScene_Chaos.h"
#include "Physics/Experimental/PhysScene_LLImmediate.h"
#include "GeometryCollectionComponent.generated.h"
struct FGeometryCollectionConstantData;
struct FGeometryCollectionDynamicData;
class FGeometryCollectionPhysicsProxy;
class UGeometryCollectionComponent;
class UBoxComponent;
class UGeometryCollectionCache;
namespace GeometryCollection
{
enum class ESelectionMode : uint8
{
None = 0,
AllGeometry,
InverseGeometry
};
}
USTRUCT()
struct FGeomComponentCacheParameters
{
GENERATED_BODY()
FGeomComponentCacheParameters();
// Cache mode, whether disabled, playing or recording
UPROPERTY(EditAnywhere, Category = Cache)
EGeometryCollectionCacheType CacheMode;
// The cache to target when recording or playing
UPROPERTY(EditAnywhere, Category = Cache)
UGeometryCollectionCache* TargetCache;
// Cache mode, whether disabled, playing or recording
UPROPERTY(EditAnywhere, Category = Cache)
float ReverseCacheBeginTime;
// Whether to buffer collisions during recording
UPROPERTY(EditAnywhere, Category = Cache)
bool SaveCollisionData;
// Maximum size of the collision buffer
UPROPERTY(EditAnywhere, Category = Cache)
int32 CollisionDataMaxSize;
// Spatial hash collision data
UPROPERTY(EditAnywhere, Category = Cache)
bool DoCollisionDataSpatialHash;
// Spatial hash radius for collision data
UPROPERTY(EditAnywhere, Category = Cache)
float SpatialHashRadius;
// Maximum number of collisions per cell
UPROPERTY(EditAnywhere, Category = Cache)
int32 MaxCollisionPerCell;
// Whether to buffer trailing during recording
UPROPERTY(EditAnywhere, Category = Cache)
bool SaveTrailingData;
// Maximum size of the trailing buffer
UPROPERTY(EditAnywhere, Category = Cache)
int32 TrailingDataSizeMax;
// Minimum speed to record trailing
UPROPERTY(EditAnywhere, Category = Cache)
float TrailingMinSpeedThreshold;
// Minimum volume to record trailing
UPROPERTY(EditAnywhere, Category = Cache)
float TrailingMinVolumeThreshold;
};
/**
* FGeometryCollectionEdit
* Structured RestCollection access where the scope
* of the object controls serialization back into the
* dynamic collection
*
* This will force any simulating geometry collection out of the
* solver so it can be edited and afterwards will recreate the proxy
*/
class GEOMETRYCOLLECTIONENGINE_API FGeometryCollectionEdit
{
public:
FGeometryCollectionEdit(UGeometryCollectionComponent * InComponent, bool InUpdate = true);
~FGeometryCollectionEdit();
UGeometryCollection* GetRestCollection();
private:
UGeometryCollectionComponent * Component;
const bool bUpdate;
bool bHadPhysicsState;
};
class GEOMETRYCOLLECTIONENGINE_API FScopedColorEdit
{
public:
FScopedColorEdit(UGeometryCollectionComponent* InComponent);
~FScopedColorEdit();
void SetShowBoneColors(bool ShowBoneColorsIn);
bool GetShowBoneColors() const;
void SetShowSelectedBones(bool ShowSelectedBonesIn);
bool GetShowSelectedBones() const;
bool IsBoneSelected(int BoneIndex) const;
void SetSelectedBones(const TArray<int32>& SelectedBonesIn);
void AppendSelectedBones(const TArray<int32>& SelectedBonesIn);
void AddSelectedBone(int32 BoneIndex);
void ClearSelectedBone(int32 BoneIndex);
const TArray<int32>& GetSelectedBones() const;
void ResetBoneSelection();
void SelectBones(GeometryCollection::ESelectionMode SelectionMode);
bool IsBoneHighlighted(int BoneIndex) const;
void SetHighlightedBones(const TArray<int32>& HighlightedBonesIn);
void AddHighlightedBone(int32 BoneIndex);
const TArray<int32>& GetHighlightedBones() const;
void ResetHighlightedBones();
void SetLevelViewMode(int ViewLevel);
int GetViewLevel();
private:
void UpdateBoneColors();
UGeometryCollectionComponent * Component;
static TArray<FLinearColor> RandomColors;
};
/**
* GeometryCollectionComponent
*/
UCLASS(meta = (BlueprintSpawnableComponent))
class GEOMETRYCOLLECTIONENGINE_API UGeometryCollectionComponent : public UMeshComponent
{
GENERATED_UCLASS_BODY()
friend class FGeometryCollectionEdit;
friend class FScopedColorEdit;
friend class FGeometryCollectionCommands;
public:
//~ Begin UActorComponent Interface.
virtual void CreateRenderState_Concurrent() override;
virtual void SendRenderDynamicData_Concurrent() override;
FORCEINLINE void SetRenderStateDirty() { bRenderStateDirty = true; }
virtual void BeginPlay() override;
virtual void EndPlay(EEndPlayReason::Type ReasonEnd) override;
//~ Begin UActorComponent Interface.
//~ Begin USceneComponent Interface.
virtual FBoxSphereBounds CalcBounds(const FTransform& LocalToWorld) const override;
virtual bool HasAnySockets() const override { return false; }
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
//~ Begin USceneComponent Interface.
//~ Begin UPrimitiveComponent Interface.
virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
virtual void OnRegister() override;
//~ End UPrimitiveComponent Interface.
//~ Begin UMeshComponent Interface.
// #todo(dmp): Is OverrideMaterials the correct thing to query here?
// #todo(dmp): for backwards compatibility with existing maps, we need to have a default of 3 materials. Otherwise
// some existing test scenes will crash
FORCEINLINE virtual int32 GetNumMaterials() const override { return OverrideMaterials.Num() == 0 ? 3 : OverrideMaterials.Num(); }
//~ End UMeshComponent Interface.
/** Chaos RBD Solver */
UPROPERTY(EditAnywhere, Category = "ChaosPhysics", meta = (DisplayName = "Chaos Solver"))
AChaosSolverActor* ChaosSolverActor;
/** RestCollection */
void SetRestCollection(UGeometryCollection * RestCollectionIn);
FORCEINLINE const UGeometryCollection* GetRestCollection() const { return RestCollection; }
FORCEINLINE FGeometryCollectionEdit EditRestCollection(bool Update = true) { return FGeometryCollectionEdit(this, Update); }
FORCEINLINE FScopedColorEdit EditBoneSelection() { return FScopedColorEdit(this); }
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ChaosPhysics")
UGeometryCollection* RestCollection;
/** DynamicCollection */
UPROPERTY(Transient, BlueprintReadOnly, Category = "ChaosPhysics")
UGeometryCollection* DynamicCollection;
FORCEINLINE UGeometryCollection* GetDynamicCollection() { return DynamicCollection; }
FORCEINLINE const UGeometryCollection* GetDynamicCollection() const { return DynamicCollection; }
/* FieldSystem */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "ChaosPhysics")
AFieldSystemActor * FieldSystem;
/**
* When Simulating is enabled the Component will initialize its rigid bodies within the solver.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|General")
bool Simulating;
/*
* ObjectType defines how to initialize the rigid objects state, Kinematic, Sleeping, Dynamic.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|General")
EObjectTypeEnum ObjectType;
/*
* CollisionType defines how to initialize the rigid collision structures.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Clustering")
bool EnableClustering;
/**
* Maximum level for cluster breaks
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Clustering")
int32 MaxClusterLevel;
/**
* Damage threshold for clusters at differnet levels.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Clustering")
TArray<float> DamageThreshold;
/*
* CollisionType defines how to initialize the rigid collision structures.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Collisions")
ECollisionTypeEnum CollisionType;
/*
* CollisionType defines how to initialize the rigid collision structures.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Collisions")
EImplicitTypeEnum ImplicitType;
/*
* Resolution on the smallest axes for the level set. (def: 5)
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Collisions")
int32 MinLevelSetResolution;
/*
* Resolution on the smallest axes for the level set. (def: 10)
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Collisions")
int32 MaxLevelSetResolution;
/**
* Mass As Density (def:false)
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Collisions")
bool MassAsDensity;
/**
* Total Mass of Collection (def : 1.0)
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Collisions")
float Mass;
/**
* Smallest allowable mass (def:0.1)
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Collisions")
float MinimumMassClamp;
/**
* Number of particles on the triangulated surface to use for collisions.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Collisions")
float CollisionParticlesFraction;
/**
* Uniform Friction
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Collisions")
float Friction;
/**
* Coefficient of Restitution (aka Bouncyness)
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Collisions")
float Bouncyness;
/**
* Uniform Friction
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Collisions")
float LinearSleepingThreshold;
/**
* Coefficient of Restitution (aka Bouncyness)
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Collisions")
float AngularSleepingThreshold;
/**
*
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Initial Velocity")
EInitialVelocityTypeEnum InitialVelocityType;
/**
*
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Initial Velocity")
FVector InitialLinearVelocity;
/**
*
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ChaosPhysics|Initial Velocity")
FVector InitialAngularVelocity;
UPROPERTY(EditAnywhere, Category = "ChaosPhysics|Caching", meta=(ShowOnlyInnerProperties))
FGeomComponentCacheParameters CacheParameters;
/**
*
*/
/* ---------------------------------------------------------------------------------------- */
void SetShowBoneColors(bool ShowBoneColorsIn);
bool GetShowBoneColors() const { return ShowBoneColors; }
bool GetShowSelectedBones() const { return ShowSelectedBones; }
// Init the material slots on the component. Note that this will also add the slots for internal
// materials and the selection material
void InitializeMaterials(const TArray<UMaterialInterface*> &Materials, int32 InteriorMaterialIndex, int32 BoneSelectedMaterialIndex);
// #todo(dmp): Do we want to call these "ID" or "index". They are used differently in some places, but they
// do represent the index into the material slots array on the component
int GetInteriorMaterialID() { return InteriorMaterialID; }
int GetBoneSelectedMaterialID() { return BoneSelectedMaterialID; }
FORCEINLINE const TArray<int32>& GetSelectedBones() const { return SelectedBones; }
FORCEINLINE const TArray<int32>& GetHighlightedBones() const { return HighlightedBones; }
void ForceInitRenderData();
FGeometryCollectionPhysicsProxy* GetPhysicsProxy() { return PhysicsProxy; }
#if INCLUDE_CHAOS
const TSharedPtr<FPhysScene_Chaos> GetPhysicsScene() const;
#endif
/**/
const TManagedArray<int32>& GetRigidBodyIdArray() const { return RigidBodyIds; }
UPROPERTY(transient)
UBoxComponent* DummyBoxComponent;
virtual void OnCreatePhysicsState() override;
virtual void OnDestroyPhysicsState() override;
virtual bool ShouldCreatePhysicsState() const override;
virtual bool HasValidPhysicsState() const override;
// Mirrored from the proxy on a sync
TManagedArray<int32> RigidBodyIds;
protected:
/** Populate the static geometry structures for the render thread. */
void InitConstantData(FGeometryCollectionConstantData* ConstantData);
/** Populate the dynamic particle data for the render thread. */
void InitDynamicData(FGeometryCollectionDynamicData* ConstantData);
/** Reset the dynamic collection from the current rest state. */
void ResetDynamicCollection();
private:
bool bRenderStateDirty;
bool ShowBoneColors;
bool ShowSelectedBones;
int ViewLevel;
UPROPERTY()
int InteriorMaterialID;
UPROPERTY()
int BoneSelectedMaterialID;
TArray<int32> SelectedBones;
TArray<int32> HighlightedBones;
FGeometryCollectionPhysicsProxy* PhysicsProxy;
#if WITH_EDITORONLY_DATA
// Tracked editor actor that owns the original component so we can write back recorded caches
// from PIE.
UPROPERTY(Transient)
AActor* EditorActor;
#endif
};

Some files were not shown because too many files have changed in this diff Show More