[ChaosVD] Added Cluster Union support and improved performance when playing back recordings with large amount of geometry and particles.

- Updated the CVD geometry builder code to recognize properly Clustered unions
- Decoupled the code that creates meshes based on the implicit meshes, from the one that creates mesh components.
- Added a new CVD macro to invalidate geometry when is modified, which will make sure the changes get recorded
- Create a pool system for the mesh components to avoid constantly create/destroy them as geometry changes
- Fixed an issue where when mesh components were generated for all objects in a ImplicitClustered objects resulted in multiples components with the same name. This caused issues like the component not being added to the actor.
- Fixed an issue where Particle color options where not applied to all mesh components in some situations
- Fixed an issue where disabled particles might not get hidden when the option to do so was enabled
- Removed the need to copy particle data each frame to each particle from the recording to the CVDParticle Actor (this is a considerable perf boost on recordings with a huge number of particles).
- Added a new Particle Data wrapper for Clustered particles. Now if we are recording a clustered particle, we will record its data.
- Updated CVD to set the hierarchy on cluster union particles as they were recorded.
- Now that we have the data, I added a small proof of concept to debug draw the connectivity data. A better implementation of this will be done when we move particle data visualization to the new system already in use for debug draw of collision data.
- Refactored how geometry is instanced and handled to use instanced static mesh components when possible
- Created a new interface to handle geometry in CVD that allows us to make changes we need regardless if it is backed by a Static Mesh component or if it is an instance on a Instanced Static Mesh Component
- Refactored how selection feedback works to take into account the fact that now when you clic in the viewport, that geometry might not be part of the actor you want to select (as it is just an instance on a Instanced Static Mesh component). If it is the later, CVD will figure out and select all the mesh instances that are representing the particle.
- Refactored how Updates to geometry are done to use the new interface that allows us to use Instanced Static mesh component
- Refactored how position updates are applied to the particles. Now we just update the transform of the mesh instances instead of moving the particle actor
- Added support to enable the flag that allows to see the triangle edges, making the unlit view mode way more useful
- Created new materials that allows us to update the colors of specific instances within a Instanced static mesh component using custom data floats. This is needed to keep the particle colors feature working with the new system


#jira UE-201792 UE-193758 UE-189695 UE-185206

#rb Benn.Gallagher


#virtualized

[CL 30549135 by sergio gardeazabal in ue5-main branch]
This commit is contained in:
sergio gardeazabal
2024-01-10 16:15:42 -05:00
parent af9045c4a6
commit d9a080e855
47 changed files with 3005 additions and 848 deletions

View File

@@ -78275,8 +78275,10 @@
<File Name="Engine/Plugins/Experimental/ChaosSolverPlugin/Resources/ChaosVehicles_64.svg" Hash="9d9a9b29a03e890f0b17c2529853f95a163e0e42" />
<File Name="Engine/Plugins/Experimental/ChaosSolverPlugin/Resources/Icon128.png" Hash="d77c572b66b158204f284cc6a58a5b1c7910f88c" />
<File Name="Engine/Plugins/Experimental/ChaosVD/Content/BP_CVD_SkySphere.uasset" Hash="2fa589ae4688cfa47d7cca977dbba6983388a9e6" />
<File Name="Engine/Plugins/Experimental/ChaosVD/Content/Materials/ChaosVDQueryOnlyMesh.uasset" Hash="a4035c2528b0e06c3d186a6e00837e491df8f94e" />
<File Name="Engine/Plugins/Experimental/ChaosVD/Content/Materials/ChasoVDSimMesh.uasset" Hash="e0a382740364a10ba55ab731260fbb06f14d98b3" />
<File Name="Engine/Plugins/Experimental/ChaosVD/Content/Materials/ChaosVDInstanced.uasset" Hash="e3dfb225d94fab00db6659765477999233720efa" />
<File Name="Engine/Plugins/Experimental/ChaosVD/Content/Materials/ChaosVDInstancedQueryOnly.uasset" Hash="79b3b5c420b66c588c6f8fdccb2a95df38e8e201" />
<File Name="Engine/Plugins/Experimental/ChaosVD/Content/Materials/ChaosVDQueryOnlyMesh.uasset" Hash="06f0d6c6606cc37bf55e7c308397fcb572c007a7" />
<File Name="Engine/Plugins/Experimental/ChaosVD/Content/Materials/ChasoVDSimMesh.uasset" Hash="4dbfd9020f6d04ec2f2016ae13f05bad8846e547" />
<File Name="Engine/Plugins/Experimental/ChaosVD/Resources/CircleBox2.png" Hash="2b026bfed47c3e7730b5c34a8188b611462d1e81" />
<File Name="Engine/Plugins/Experimental/ChaosVD/Resources/Connection.svg" Hash="a0968646d00e47980fd09c9406bc86c306c24569" />
<File Name="Engine/Plugins/Experimental/ChaosVD/Resources/Details.svg" Hash="2efa65af5868c486f2701455c4bee1be50c4a343" />
@@ -110344,6 +110346,7 @@
<Blob Hash="06edd589fab28aeddeac1b379f255253701f6225" Size="284" PackHash="01a7ef3bb3f5235cb97b2bb0a57b8f4abd5463e5" PackOffset="1683883" />
<Blob Hash="06ede05b4ba74eeea5ed21ea96615cadbf37ce53" Size="7300" PackHash="ab3d993f79975671cc4d365c43c1ad5a27c71c15" PackOffset="1379433" />
<Blob Hash="06f0c5cf6f53fff9a04ad0aadf740fb46f9c9a2c" Size="6342" PackHash="3289db73d3b084866c09945a9fc0a9c2565fb54b" PackOffset="746375" />
<Blob Hash="06f0d6c6606cc37bf55e7c308397fcb572c007a7" Size="12330" PackHash="ececc6427ed03f23a571eec8284669eb13f39870" PackOffset="36491" />
<Blob Hash="06f1b0de642132260c8067744cd6dd119c1a5ed2" Size="288" PackHash="8fd163c1f9dc9bf11ad958c41b095830489b938c" PackOffset="2096711" />
<Blob Hash="06f203f34b17a7856bdab093dd615648033055ed" Size="10627" PackHash="0e277d806d39dbcce9b919f84ab6b2152111f867" PackOffset="8" />
<Blob Hash="06f234778ce7cd1a37ad27b3437cd371aa7751b4" Size="145" PackHash="65192995f97dd44252dee38ab898e7395b12ab16" PackOffset="140674" />
@@ -128436,6 +128439,7 @@
<Blob Hash="4dbd61d064c4425eca0e223b1fd84b102d7f5218" Size="191832548" PackHash="518fe84282fe84cd6de31fe1e22e982defbd5193" PackOffset="8" />
<Blob Hash="4dbe2e3b1c11e17f21e01fa7cce3606a3705ae18" Size="17408" PackHash="6c8ba6a7691c7b6a2286a6751613ec6125ab0695" PackOffset="1334607" />
<Blob Hash="4dbe6d90cfa9025e0ea2e5861f30fef0d216e29d" Size="6307" PackHash="746500f21eb5968df45d4f69bbc90075c6c81ae5" PackOffset="936528" />
<Blob Hash="4dbfd9020f6d04ec2f2016ae13f05bad8846e547" Size="12455" PackHash="ececc6427ed03f23a571eec8284669eb13f39870" PackOffset="48821" />
<Blob Hash="4dc1e89604318c69b7ab84937403ab53a86c47bd" Size="31872" PackHash="5529170518971e4dd15cf3c70e0c78c5197bc95a" PackOffset="2061856" />
<Blob Hash="4dc362e2141e23b37f60506aafda4288f1a23ad2" Size="21152" PackHash="f8fec4ecd651841a1a70c6dd2676f95c864cc071" PackOffset="21272" />
<Blob Hash="4dc36575d2eada57a3b9d34e945ecc7b957f6457" Size="1032" PackHash="19c2ff59a8330a24911c1ce906227d5874b0be57" PackOffset="1405" />
@@ -139551,6 +139555,7 @@
<Blob Hash="79ae4a84ea04d433ca4be8830d8e70130a0a31d8" Size="5250" PackHash="c510d87fa25e08cfc906714d8386d61f61843278" PackOffset="331559" />
<Blob Hash="79af1f1db3ba8c4c1aa84354a96fc1d50a2c1796" Size="4858" PackHash="a59a07b4baff35e7e3f4b6b062c843b014be71cb" PackOffset="738114" />
<Blob Hash="79b02228b1748efe3fe6b5b4b52c8a571c677e71" Size="1837" PackHash="8bc75bd4505a1f80a7175d450f79a911efd38b2e" PackOffset="1057309" />
<Blob Hash="79b3b5c420b66c588c6f8fdccb2a95df38e8e201" Size="17944" PackHash="ececc6427ed03f23a571eec8284669eb13f39870" PackOffset="18547" />
<Blob Hash="79b455f88ecf7c89b95548a9e1b159b52292df63" Size="6373" PackHash="43648df1079ccfe00da4e7783a61e5d01866f290" PackOffset="8" />
<Blob Hash="79b6502549c4190ea51513a26a960ba867385340" Size="1396" PackHash="af1b8ed2ea380d3a32c07432e1bf77c839e8b779" PackOffset="2053893" />
<Blob Hash="79b8000bc83dcaf0aabe9aa0aa5c960696e62919" Size="200" PackHash="9d2366d5b602e26aad5d274b20f81284507f4cc2" PackOffset="1291086" />
@@ -150253,7 +150258,6 @@
<Blob Hash="a3fdbcad6e1e5d3c5f2d68f01837b8b540df3398" Size="817" PackHash="1aa81c6c9b18f04c75ed64f2cfb02c1bea6bfaa9" PackOffset="8" />
<Blob Hash="a3fe94b7496c2ba62e35d5894690a3dfef9fead4" Size="20" PackHash="0876f67d0c57a555e3172bac286ad7d0c8a19f92" PackOffset="1843311" />
<Blob Hash="a3ff50800d141279b083d3a0d31f6005321af086" Size="397920" PackHash="286660322f6f97f81a992e8f22a7bc4b35f75842" PackOffset="1639232" />
<Blob Hash="a4035c2528b0e06c3d186a6e00837e491df8f94e" Size="9173" PackHash="0646e645a9420dbc3a3c8340d1da5c1e4789ef67" PackOffset="8" />
<Blob Hash="a403af3337e6207d144b998b9c3bed439af562a9" Size="74508" PackHash="715cfed5d4e061acb58b3c494ea53ea0791f8d07" PackOffset="1040593" />
<Blob Hash="a403dc99f9acaf88d784ba21b5b19eb5a5a8802b" Size="1277" PackHash="fb553cf74129944989a77ed6aca140d410d4afa4" PackOffset="1726490" />
<Blob Hash="a404ac068355457f2e36f7ad36b8d63172af0a64" Size="1580" PackHash="0d1a8db8ecac47de71532ff5913a517c64111ce7" PackOffset="1370369" />
@@ -165901,7 +165905,6 @@
<Blob Hash="e09f34b99ad172b2b3c507aa62d7cc9d13ab628d" Size="26480" PackHash="79a9001a38f727edb403f35a95361eac45cfa0dd" PackOffset="657884" />
<Blob Hash="e09f6d71cec3c9a35d59599c1dfeac76baec87ce" Size="1002" PackHash="c8af9fec46e6a7ca54af3c703c58007f843e4444" PackOffset="134837" />
<Blob Hash="e0a0f38279c586f5256097a2e3c4febe1d8dbfd9" Size="15776" PackHash="d2865393d758cf1418c786711d61ba37e9d69de6" PackOffset="610992" />
<Blob Hash="e0a382740364a10ba55ab731260fbb06f14d98b3" Size="9580" PackHash="0646e645a9420dbc3a3c8340d1da5c1e4789ef67" PackOffset="9181" />
<Blob Hash="e0a4adc0db3be6a75af3129a3719ca9a9885242b" Size="62976" PackHash="f3e94d5576b76b90efa00e074c6e822f0c483c55" PackOffset="1867784" />
<Blob Hash="e0a57b0b5deba9bf6e818ee2a3d112d5eb9de7e5" Size="1075488" PackHash="f3725a7c4ad413532ff4dd01dbc84ddba28bfb98" PackOffset="8" />
<Blob Hash="e0a6002261f26fd8241738bd24bd5043e192665e" Size="6539806" PackHash="9b5cedec6b3f0f8e6c9b66493330d5a0ebcd3f14" PackOffset="8" />
@@ -166710,6 +166713,7 @@
<Blob Hash="e3de412fbe220d8fca2013c62262402c1903abc6" Size="3503" PackHash="19c2ff59a8330a24911c1ce906227d5874b0be57" PackOffset="154020" />
<Blob Hash="e3df745ba4453e35b554aa9e6347932259da2c35" Size="3352" PackHash="6a89511cf835165c263aa997eeb91bdcc72098e5" PackOffset="1424198" />
<Blob Hash="e3df9b21e3c4558fd8265fa01b76847ede736d52" Size="16280" PackHash="55a3291c683b0735721a39a3f89bd0fa7a6a711e" PackOffset="1963528" />
<Blob Hash="e3dfb225d94fab00db6659765477999233720efa" Size="18539" PackHash="ececc6427ed03f23a571eec8284669eb13f39870" PackOffset="8" />
<Blob Hash="e3e188c9543dd892aad45639bfc627374e1fe151" Size="19456" PackHash="b07adaa749eb8febf8ea2937e799f6d36f6627ec" PackOffset="919560" />
<Blob Hash="e3e5759a0b14da38062af074d5aeed540def18df" Size="32528" PackHash="238d7403460da32700f868e83ac217da7c178254" PackOffset="2006461" />
<Blob Hash="e3e7308a54b11f90e82dfbb0cefc1b2717bf4050" Size="1374" PackHash="24aac461ee54420b2fbb50c17fba330abdd085e0" PackOffset="670505" />
@@ -173948,7 +173952,6 @@
<Pack Hash="0634ae5b3be4c2f1faaa4c6b9407dee2ae05747b" Size="2252432" CompressedSize="151545" RemotePath="UnrealEngine-30221548" />
<Pack Hash="0635d101c167fd42e5e59ee17f76057442b0323a" Size="606778" CompressedSize="175331" RemotePath="UnrealEngine-25357016" />
<Pack Hash="063ff37bdde43ac78b062e2bd382455ca17bcaa1" Size="7956" CompressedSize="2565" RemotePath="UnrealEngine-25357016" />
<Pack Hash="0646e645a9420dbc3a3c8340d1da5c1e4789ef67" Size="18761" CompressedSize="9164" RemotePath="UnrealEngine-27942556" />
<Pack Hash="0649824c7b11091665bd2c385d3c4986e1c9f904" Size="965021" CompressedSize="518263" RemotePath="UnrealEngine-25357016" />
<Pack Hash="064e33442f12c52eed004a2e3a509e3923c1fd05" Size="36771" CompressedSize="7074" RemotePath="UnrealEngine-25328963" />
<Pack Hash="0679fb8e78f647b6d46d4462eca4f9f38c9b1f93" Size="6891327" CompressedSize="6889746" RemotePath="UnrealEngine-25357016" />
@@ -181253,6 +181256,7 @@
<Pack Hash="ece22a8960028a495fdb8a7778954041ea6f2db4" Size="402324" CompressedSize="152970" RemotePath="UnrealEngine-25357016" />
<Pack Hash="ece5f359cf8e587430d8263f0dee2ff7886eee20" Size="2096023" CompressedSize="395953" RemotePath="UnrealEngine-30221548" />
<Pack Hash="ece82ce44339046fa1cf28fc4e9b68191b4da005" Size="5419735" CompressedSize="5418871" RemotePath="UnrealEngine-25357016" />
<Pack Hash="ececc6427ed03f23a571eec8284669eb13f39870" Size="61276" CompressedSize="20168" RemotePath="UnrealEngine-30549135" />
<Pack Hash="ecf67eb2a5bd9220c935a5e7b91c0224549ff9af" Size="15944" CompressedSize="1958" RemotePath="UnrealEngine-25328963" />
<Pack Hash="ecfa415f37d3838ecdcbc2eef742afb2c3b34152" Size="2097072" CompressedSize="450835" RemotePath="UnrealEngine-30299789" />
<Pack Hash="ecfb1f6be53964ca147e773a7283f56e7ad5876b" Size="35631" CompressedSize="11959" RemotePath="UnrealEngine-25328963" />

View File

@@ -1,4 +1,6 @@
[/Script/ChaosVD.ChaosVDEditorSettings]
QueryOnlyMeshesMaterial=/ChaosVD/Materials/ChaosVDQueryOnlyMesh.ChaosVDQueryOnlyMesh
SimOnlyMeshesMaterial=/ChaosVD/Materials/ChasoVDSimMesh.ChasoVDSimMesh
InstancedMeshesMaterial=/ChaosVD/Materials/ChaosVDInstanced.ChaosVDInstanced
InstancedMeshesQueryOnlyMaterial=/ChaosVD/Materials/ChaosVDInstancedQueryOnly.ChaosVDInstancedQueryOnly
SkySphereActorClass=/ChaosVD/BP_CVD_SkySphere.BP_CVD_SkySphere_C

View File

@@ -0,0 +1,14 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "ChaosVDExtractedGeometryDataHandle.h"
#include "Chaos/ImplicitObject.h"
FName FChaosVDExtractedGeometryDataHandle::GetName() const
{
using namespace Chaos;
static FName InvalidName = TEXT("Invalid");
return ImplicitObject ? GetImplicitObjectTypeName(GetInnerType(ImplicitObject->GetType())) : InvalidName;
}

View File

@@ -0,0 +1,89 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "ChaosVDMeshComponentPool.h"
#include "ChaosVDGeometryDataComponent.h"
#include "ChaosVDModule.h"
#include "UObject/Package.h"
bool FChaosVDMeshComponentPool::bUseComponentsPool = true;
FAutoConsoleVariableRef FChaosVDMeshComponentPool::CVarUseComponentsPool(TEXT("p.Chaos.VD.Tool.UseComponentsPool"), FChaosVDMeshComponentPool::bUseComponentsPool, TEXT("Set to false to disable the use of a pool system for Mesh Components."));
void FChaosVDMeshComponentPool::AddReferencedObjects(FReferenceCollector& Collector)
{
Collector.AddReferencedObjects(PooledDynamicMeshComponent);
Collector.AddReferencedObjects(PooledInstancedStaticMeshComponent);
Collector.AddReferencedObjects(PooledStaticMeshComponent);
}
void FChaosVDMeshComponentPool::DisposeMeshComponent(UMeshComponent* MeshComponent)
{
if (!MeshComponent)
{
return;
}
if (!bUseComponentsPool)
{
MeshComponent->DestroyComponent();
return;
}
ResetMeshComponent(MeshComponent);
if (UInstancedStaticMeshComponent* AsISMC = Cast<UInstancedStaticMeshComponent>(MeshComponent))
{
PooledInstancedStaticMeshComponent.Add(AsISMC);
}
else if (UStaticMeshComponent* AsSMC = Cast<UStaticMeshComponent>(MeshComponent))
{
PooledStaticMeshComponent.Add(AsSMC);
}
else if (UDynamicMeshComponent* AsDMC = Cast<UDynamicMeshComponent>(MeshComponent))
{
PooledDynamicMeshComponent.Add(AsDMC);
}
else
{
UE_LOG(LogChaosVDEditor, Warning, TEXT("[%s] Unable top dispose Mesh component [%s] | Incompatible mesh type used [%s]"), ANSI_TO_TCHAR(__FUNCTION__), *GetNameSafe(MeshComponent), *GetNameSafe(MeshComponent->GetClass()));
}
const FString NewName = MeshComponent->GetName() + TEXT("_POOLED_") + FGuid::NewGuid().ToString();
MeshComponent->Rename(*NewName, GetTransientPackage(), REN_NonTransactional | REN_DoNotDirty | REN_ForceNoResetLoaders | REN_SkipGeneratedClasses | REN_DontCreateRedirectors);
}
void FChaosVDMeshComponentPool::ResetMeshComponent(UMeshComponent* MeshComponent)
{
if (!MeshComponent)
{
return;
}
if (UDynamicMeshComponent* DynamicMeshComponent = Cast<UDynamicMeshComponent>(MeshComponent))
{
DynamicMeshComponent->SetDynamicMesh(nullptr);
}
else if (UInstancedStaticMeshComponent* InstancedStaticMeshComponent = Cast<UInstancedStaticMeshComponent>(MeshComponent))
{
InstancedStaticMeshComponent->SetStaticMesh(nullptr);
InstancedStaticMeshComponent->ClearInstances();
}
else if (UStaticMeshComponent* StaticMeshComponent = Cast<UStaticMeshComponent>(MeshComponent))
{
StaticMeshComponent->SetStaticMesh(nullptr);
}
MeshComponent->SetRelativeTransform(FTransform::Identity);
if (IChaosVDGeometryComponent* DataComponent = Cast<IChaosVDGeometryComponent>(MeshComponent))
{
DataComponent->Reset();
}
MeshComponent->UnregisterComponent();
if (AActor* Owner = MeshComponent->GetOwner())
{
Owner->RemoveOwnedComponent(MeshComponent);
}
}

View File

@@ -19,6 +19,15 @@
DEFINE_LOG_CATEGORY(LogChaosVDEditor);
FAutoConsoleCommand ChaosVDSpawnNewCVDInstance(
TEXT("p.Chaos.VD.SpawnNewCVDInstance"),
TEXT("Opens a new CVD windows wothout closing an existing one"),
FConsoleCommandWithArgsDelegate::CreateLambda([](const TArray<FString>& Args)
{
FChaosVDModule::Get().SpawnCVDTab();
})
);
FChaosVDModule& FChaosVDModule::Get()
{
return FModuleManager::Get().LoadModuleChecked<FChaosVDModule>(TEXT("ChaosVD"));
@@ -47,6 +56,11 @@ void FChaosVDModule::ShutdownModule()
FChaosVDStyle::Shutdown();
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(FChaosVDTabID::ChaosVisualDebuggerTab);
for (const FName TabID : CreatedExtraTabSpawnersIDs)
{
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(TabID);
}
FCoreDelegates::OnEnginePreExit.RemoveAll(this);
@@ -62,6 +76,22 @@ void FChaosVDModule::RegisterClassesCustomDetails() const
PropertyModule.RegisterCustomPropertyTypeLayout("ChaosVDParticleDataWrapper", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FChaosVDParticleDataWrapperCustomization::MakeInstance));
}
void FChaosVDModule::SpawnCVDTab()
{
// Registering new tab spawners with random names is not the best idea to spawn new tabs, but it is good enough to test we can run multiple instances of CVD withing the editor.
// This is also why spawning new tabs it is only exposed via console commands for now.
// When this feature is deemed stable and exposed in the UI I will investigate a more correct way of implementing this
const FName NewTabID = FName(FChaosVDTabID::ChaosVisualDebuggerTab.ToString() + FGuid::NewGuid().ToString());
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(NewTabID, FOnSpawnTab::CreateRaw(this, &FChaosVDModule::SpawnMainTab))
.SetDisplayName(LOCTEXT("VisualDebuggerTabTitle", "Chaos Visual Debugger"))
.SetTooltipText(LOCTEXT("VisualDebuggerTabDesc", "Opens the Chaos Visual Debugger window"));
FGlobalTabmanager::Get()->TryInvokeTab(NewTabID);
CreatedExtraTabSpawnersIDs.Add(NewTabID);
}
TSharedRef<SDockTab> FChaosVDModule::SpawnMainTab(const FSpawnTabArgs& Args)
{
TSharedRef<SDockTab> MainTabInstance =

View File

@@ -2,10 +2,16 @@
#include "ChaosVDParticleActorCustomization.h"
#include "ChaosVDModule.h"
#include "ChaosVDParticleActor.h"
#include "DetailCategoryBuilder.h"
#include "DetailLayoutBuilder.h"
#include "DetailWidgetRow.h"
#include "IStructureDetailsView.h"
#include "DataWrappers/ChaosVDParticleDataWrapper.h"
#include "DetailsCustomizations/ChaosVDDetailsCustomizationUtils.h"
#define LOCTEXT_NAMESPACE "ChaosVisualDebugger"
FChaosVDParticleActorCustomization::FChaosVDParticleActorCustomization()
{
@@ -13,6 +19,14 @@ FChaosVDParticleActorCustomization::FChaosVDParticleActorCustomization()
AllowedCategories.Add(FChaosVDParticleActorCustomization::ChaosVDVisualizationCategoryName);
}
FChaosVDParticleActorCustomization::~FChaosVDParticleActorCustomization()
{
if (CurrentObservedActor.Get())
{
CurrentObservedActor->OnParticleDataUpdated().Unbind();
}
}
TSharedRef<IDetailCustomization> FChaosVDParticleActorCustomization::MakeInstance()
{
return MakeShareable( new FChaosVDParticleActorCustomization );
@@ -24,5 +38,54 @@ void FChaosVDParticleActorCustomization::CustomizeDetails(IDetailLayoutBuilder&
FChaosVDDetailsCustomizationUtils::HideAllCategories(DetailBuilder, AllowedCategories);
DetailBuilder.EditCategory(ChaosVDCategoryName).InitiallyCollapsed(false);
// We keep the particle data we need to visualize as a shared ptr because copying it each frame we advance/rewind to to an struct that lives in the particle actor it is not cheap.
// Having a struct details view to which we set that pointer data each time the data in the particle is updated (meaning we assigned another ptr from the recording)
// seems to be more expensive because it has to rebuild the entire layout from scratch.
// So a middle ground I found is to have a Particle Data struct in this customization instance, which we add as external property. Then each time the particle data is updated we copy the data over.
// This allow us to only perform the copy just for the particle that is being inspected and not every particle updated in that frame.
IDetailCategoryBuilder& CVDMainCategoryBuilder = DetailBuilder.EditCategory(ChaosVDCategoryName).InitiallyCollapsed(false);
TArray<TWeakObjectPtr<UObject>> SelectedObjects;
DetailBuilder.GetObjectsBeingCustomized(SelectedObjects);
if (SelectedObjects.Num() > 0)
{
//TODO: Add support for multi-selection.
if (!ensure(SelectedObjects.Num() == 1))
{
UE_LOG(LogChaosVDEditor, Warning, TEXT("[%s] [%d] objects were selectioned but this customization panel only support single object selection."), ANSI_TO_TCHAR(__FUNCTION__), SelectedObjects.Num())
}
if (AChaosVDParticleActor* CurrentActor = CurrentObservedActor.Get())
{
CurrentParticleDataCopy = FChaosVDParticleDataWrapper();
CurrentActor->OnParticleDataUpdated().Unbind();
CurrentActor = nullptr;
}
if (AChaosVDParticleActor* ParticleActor = Cast<AChaosVDParticleActor>(SelectedObjects[0]))
{
CurrentObservedActor = ParticleActor;
CurrentObservedActor->OnParticleDataUpdated().BindRaw(this, &FChaosVDParticleActorCustomization::HandleParticleDataUpdated);
HandleParticleDataUpdated();
const TSharedPtr<FStructOnScope> ParticleDataView = MakeShared<FStructOnScope>(FChaosVDParticleDataWrapper::StaticStruct(), reinterpret_cast<uint8*>(&CurrentParticleDataCopy));
TArray<TSharedPtr<IPropertyHandle>> Handles = CVDMainCategoryBuilder.AddAllExternalStructureProperties(ParticleDataView.ToSharedRef(), EPropertyLocation::Default, nullptr);
}
}
}
void FChaosVDParticleActorCustomization::HandleParticleDataUpdated()
{
if (const FChaosVDParticleDataWrapper* ParticleDataPtr = CurrentObservedActor.Get() ? CurrentObservedActor->GetParticleData() : nullptr)
{
CurrentParticleDataCopy = *ParticleDataPtr;
}
else
{
CurrentParticleDataCopy = FChaosVDParticleDataWrapper();
}
}
#undef LOCTEXT_NAMESPACE

View File

@@ -18,6 +18,7 @@
#include "UnrealWidget.h"
#include "Actors/ChaosVDSolverInfoActor.h"
#include "Components/ChaosVDSolverCollisionDataComponent.h"
#include "Components/InstancedStaticMeshComponent.h"
#include "Visualizers/ChaosVDDebugDrawUtils.h"
#include "Widgets/SChaosVDMainTab.h"
@@ -32,8 +33,10 @@ FChaosVDPlaybackViewportClient::FChaosVDPlaybackViewportClient(const TSharedPtr<
if (UChaosVDEditorSettings* Settings = GetMutableDefault<UChaosVDEditorSettings>())
{
OverrideFarClipPlane(Settings->FarClippingOverride);
Settings->OnFarClippingOverrideChanged().AddRaw(this, &FChaosVDPlaybackViewportClient::HandleFarClippingOverrideSettingsChanged);
Settings->OnFarClippingOverrideChanged().AddRaw(this, &FChaosVDPlaybackViewportClient::HandleViewportSettingsChanged);
Settings->OnVisibilitySettingsChanged().AddRaw(this, &FChaosVDPlaybackViewportClient::HandleViewportSettingsChanged);
HandleViewportSettingsChanged(Settings);
}
}
@@ -55,6 +58,7 @@ FChaosVDPlaybackViewportClient::~FChaosVDPlaybackViewportClient()
if (UChaosVDEditorSettings* Settings = GetMutableDefault<UChaosVDEditorSettings>())
{
Settings->OnFarClippingOverrideChanged().RemoveAll(this);
Settings->OnVisibilitySettingsChanged().RemoveAll(this);
}
}
@@ -89,6 +93,32 @@ void FChaosVDPlaybackViewportClient::ProcessClick(FSceneView& View, HHitProxy* H
bClickHandled = Visualizer->VisProxyHandleClick(this, ComponentVisProxy, Click);
}
const IChaosVDGeometryComponent* AsCVDGeometryComponent = nullptr;
int32 MeshInstanceIndex = INDEX_NONE;
if (const HInstancedStaticMeshInstance* InstancedStaticMeshProxy = HitProxyCast<HInstancedStaticMeshInstance>(HitProxy))
{
AsCVDGeometryComponent = Cast<IChaosVDGeometryComponent>(InstancedStaticMeshProxy->Component);
MeshInstanceIndex = InstancedStaticMeshProxy->InstanceIndex;
}
else if (const HActor* ActorHitProxy = HitProxyCast<HActor>(HitProxy))
{
AsCVDGeometryComponent = Cast<IChaosVDGeometryComponent>(ActorHitProxy->PrimComponent.Get());
MeshInstanceIndex = 0;
}
if (AsCVDGeometryComponent && MeshInstanceIndex != INDEX_NONE)
{
if (const TSharedPtr<FChaosVDMeshDataInstanceHandle> MeshDataHandle = AsCVDGeometryComponent->GetMeshDataInstanceHandle(MeshInstanceIndex))
{
if (AChaosVDParticleActor* ClickedActor = ScenePtr->GetParticleActor(MeshDataHandle->GetOwningSolverID(), MeshDataHandle->GetOwningParticleID()))
{
ScenePtr->SetSelectedObject(ClickedActor);
bClickHandled = true;
}
}
}
if (bClickHandled)
{
return;
@@ -138,11 +168,13 @@ void FChaosVDPlaybackViewportClient::HandleActorMoving(AActor* MovedActor) const
}
}
void FChaosVDPlaybackViewportClient::HandleFarClippingOverrideSettingsChanged(UChaosVDEditorSettings* SettingsObject)
void FChaosVDPlaybackViewportClient::HandleViewportSettingsChanged(UChaosVDEditorSettings* SettingsObject)
{
if (SettingsObject)
{
OverrideFarClipPlane(SettingsObject->FarClippingOverride);
EngineShowFlags.SetMeshEdges(EnumHasAnyFlags(static_cast<EChaosVDGeometryVisibilityFlags>(SettingsObject->GeometryVisibilityFlags), EChaosVDGeometryVisibilityFlags::ShowTriangleEdges));
Invalidate();
}
}

View File

@@ -51,6 +51,8 @@ void FChaosVDScene::Initialize()
PhysicsVDWorld = CreatePhysicsVDWorld();
GeometryGenerator = MakeShared<FChaosVDGeometryBuilder>();
GeometryGenerator->Initialize(AsWeak());
StreamableManager = MakeShared<FStreamableManager>();
@@ -60,6 +62,8 @@ void FChaosVDScene::Initialize()
// Jira for tracking UE-191639
StreamableManager->RequestSyncLoad(Settings->QueryOnlyMeshesMaterial.ToSoftObjectPath());
StreamableManager->RequestSyncLoad(Settings->SimOnlyMeshesMaterial.ToSoftObjectPath());
StreamableManager->RequestSyncLoad(Settings->InstancedMeshesMaterial.ToSoftObjectPath());
StreamableManager->RequestSyncLoad(Settings->InstancedMeshesQueryOnlyMaterial.ToSoftObjectPath());
Settings->OnVisibilitySettingsChanged().AddRaw(this, &FChaosVDScene::HandleVisibilitySettingsChanged);
Settings->OnColorSettingsChanged().AddRaw(this, &FChaosVDScene::HandleColorSettingsChanged);
@@ -133,7 +137,7 @@ void FChaosVDScene::UpdateFromRecordedStepData(const int32 SolverID, const FStri
UpdatingSceneSlowTask.MakeDialogDelayed(ChaosVDSceneUIOptions::DelayToShowProgressDialogThreshold, ChaosVDSceneUIOptions::bShowCancelButton, ChaosVDSceneUIOptions::bAllowInPIE);
// Go over existing Particle VD Instances and update them or create them if needed
for (const FChaosVDParticleDataWrapper& Particle : InRecordedStepData.RecordedParticlesData)
for (const TSharedPtr<FChaosVDParticleDataWrapper>& Particle : InRecordedStepData.RecordedParticlesData)
{
const int32 ParticleVDInstanceID = GetIDForRecordedParticleData(Particle);
ParticlesIDsInRecordedStepData.Add(ParticleVDInstanceID);
@@ -301,6 +305,10 @@ Chaos::FConstImplicitObjectPtr FChaosVDScene::GetUpdatedGeometry(int32 GeometryI
{
return *Geometry;
}
else
{
UE_LOG(LogChaosVDEditor, Warning, TEXT("Geometry for key [%d] is not loaded in the recording yet"), GeometryID);
}
}
return nullptr;
@@ -337,33 +345,28 @@ bool FChaosVDScene::IsSolverForServer(int32 SolverID) const
return false;
}
AChaosVDParticleActor* FChaosVDScene::SpawnParticleFromRecordedData(const FChaosVDParticleDataWrapper& InParticleData, const FChaosVDSolverFrameData& InFrameData)
AChaosVDParticleActor* FChaosVDScene::SpawnParticleFromRecordedData(const TSharedPtr<FChaosVDParticleDataWrapper>& InParticleData, const FChaosVDSolverFrameData& InFrameData)
{
using namespace Chaos;
if (!InParticleData.IsValid())
{
return nullptr;
}
FActorSpawnParameters Params;
Params.Name = *InParticleData.DebugName;
Params.Name = *InParticleData->DebugName;
Params.NameMode = FActorSpawnParameters::ESpawnActorNameMode::Requested;
if (AChaosVDParticleActor* NewActor = PhysicsVDWorld->SpawnActor<AChaosVDParticleActor>(Params))
{
NewActor->SetIsActive(true);
NewActor->SetScene(AsShared());
NewActor->SetIsServerParticle(IsSolverForServer(InParticleData->SolverID));
NewActor->UpdateFromRecordedParticleData(InParticleData, InFrameData.SimulationTransform);
if (!InParticleData.DebugName.IsEmpty())
{
NewActor->SetActorLabel(InParticleData.DebugName);
}
NewActor->SetScene(AsShared());
if (ensure(LoadedRecording.IsValid()))
{
if (const Chaos::FConstImplicitObjectPtr* Geometry = LoadedRecording->GetGeometryMap().Find(InParticleData.GeometryHash))
{
NewActor->UpdateGeometry(*Geometry);
}
}
const bool bHasDebugName = !InParticleData->DebugName.IsEmpty();
NewActor->SetActorLabel(bHasDebugName ? InParticleData->DebugName : TEXT("Unnamed Particle - ID : ") + FString::FromInt(InParticleData->ParticleIndex));
return NewActor;
}
@@ -371,9 +374,9 @@ AChaosVDParticleActor* FChaosVDScene::SpawnParticleFromRecordedData(const FChaos
return nullptr;
}
int32 FChaosVDScene::GetIDForRecordedParticleData(const FChaosVDParticleDataWrapper& InParticleData) const
int32 FChaosVDScene::GetIDForRecordedParticleData(const TSharedPtr<FChaosVDParticleDataWrapper>& InParticleData) const
{
return InParticleData.ParticleIndex;
return InParticleData ? InParticleData->ParticleIndex : INDEX_NONE;
}
void FChaosVDScene::CreateBaseLights(UWorld* TargetWorld) const
@@ -412,6 +415,16 @@ void FChaosVDScene::CreateBaseLights(UWorld* TargetWorld) const
}
}
AActor* FChaosVDScene::CreateMeshComponentsContainer(UWorld* TargetWorld)
{
const FName GeometryFolderPath("ChaosVisualDebugger/GeneratedMeshComponents");
MeshComponentContainerActor = TargetWorld->SpawnActor<AActor>();
MeshComponentContainerActor->SetFolderPath(GeometryFolderPath);
return MeshComponentContainerActor;
}
UWorld* FChaosVDScene::CreatePhysicsVDWorld()
{
const FName UniqueWorldName = FName(FGuid::NewGuid().ToString());
@@ -433,6 +446,7 @@ UWorld* FChaosVDScene::CreatePhysicsVDWorld()
);
CreateBaseLights(NewWorld);
CreateMeshComponentsContainer(NewWorld);
ActorDestroyedHandle = NewWorld->AddOnActorDestroyedHandler(FOnActorDestroyed::FDelegate::CreateRaw(this, &FChaosVDScene::HandleActorDestroyed));
@@ -522,13 +536,16 @@ void FChaosVDScene::InitializeSelectionSets()
SelectionSet = NewObject<UTypedElementSelectionSet>(GetTransientPackage(), NAME_None, RF_Transactional);
SelectionSet->AddToRoot();
ActorSelection = USelection::CreateActorSelection(GetTransientPackage(), TEXT("CVDSelectedActors"), RF_Transactional);
FString ActorSelectionObjectName = FString::Printf(TEXT("CVDSelectedActors-%s"), *FGuid::NewGuid().ToString());
ActorSelection = USelection::CreateActorSelection(GetTransientPackage(), *ActorSelectionObjectName, RF_Transactional);
ActorSelection->SetElementSelectionSet(SelectionSet);
ComponentSelection = USelection::CreateComponentSelection(GetTransientPackage(), TEXT("CVDSelectedComponents"), RF_Transactional);
FString ComponentSelectionObjectName = FString::Printf(TEXT("CVDSelectedComponents-%s"), *FGuid::NewGuid().ToString());
ComponentSelection = USelection::CreateComponentSelection(GetTransientPackage(), *ComponentSelectionObjectName, RF_Transactional);
ComponentSelection->SetElementSelectionSet(SelectionSet);
ObjectSelection = USelection::CreateObjectSelection(GetTransientPackage(), TEXT("CVDSelectedObjects"), RF_Transactional);
FString ObjectSelectionObjectName = FString::Printf(TEXT("CVDSelectedObjects-%s"), *FGuid::NewGuid().ToString());
ObjectSelection = USelection::CreateObjectSelection(GetTransientPackage(), *ObjectSelectionObjectName, RF_Transactional);
ObjectSelection->SetElementSelectionSet(SelectionSet);
SelectionSet->OnPreChange().AddRaw(this, &FChaosVDScene::HandlePreSelectionChange);

View File

@@ -2,28 +2,262 @@
#include "Components/ChaosVDInstancedStaticMeshComponent.h"
void UChaosVDInstancedStaticMeshComponent::UpdateVisibility()
#include "ChaosVDModule.h"
#include "Materials/MaterialInterface.h"
#include "Materials/MaterialInstanceDynamic.h"
void UChaosVDInstancedStaticMeshComponent::UpdateInstanceVisibility(const TSharedPtr<FChaosVDMeshDataInstanceHandle>& InInstanceHandle, bool bIsVisible)
{
UpdateVisibility_Internal(CollisionData, Cast<UMeshComponent>(this));
if (!InInstanceHandle.IsValid())
{
UE_LOG(LogChaosVDEditor, Warning, TEXT("[%s] Attempted to update a mesh instance using an invalid handle. No instances were updated"), ANSI_TO_TCHAR(__FUNCTION__));
return;
}
if (InInstanceHandle->GetMeshComponent() != this)
{
UE_LOG(LogChaosVDEditor, Error, TEXT("[%s] Attempted to update a mesh instance using a handle from another component. No instances were updated | Handle Component [%s] | Current Component [%s]"), ANSI_TO_TCHAR(__FUNCTION__), *GetNameSafe(InInstanceHandle->GetMeshComponent()), *GetNameSafe(this));
return;
}
const int32 InstanceIndex = InInstanceHandle->GetMeshInstanceIndex();
FTransform Transform = InInstanceHandle->GetWorldTransform();
if (!bIsVisible)
{
// Setting the scale to 0 will hide this instance while keeping it on the component
Transform.SetScale3D(FVector::ZeroVector);
}
constexpr bool bIsWorldSpaceTransform = true;
constexpr bool bMarkRenderDirty = true;
constexpr bool bTeleport = true;
UpdateInstanceTransform(InstanceIndex, Transform, bIsWorldSpaceTransform, bMarkRenderDirty, bTeleport);
}
void UChaosVDInstancedStaticMeshComponent::UpdateDataFromShapeArray(const TArray<FChaosVDShapeCollisionData>& InShapeArray)
void UChaosVDInstancedStaticMeshComponent::SetIsSelected(const TSharedPtr<FChaosVDMeshDataInstanceHandle>& InInstanceHandle, bool bIsSelected)
{
UpdateDataFromShapeArray_Internal(InShapeArray, CollisionData, this);
if (!InInstanceHandle.IsValid())
{
UE_LOG(LogChaosVDEditor, Warning, TEXT("[%s] Attempted to update a mesh instance using an invalid handle. No instances were updated"), ANSI_TO_TCHAR(__FUNCTION__));
return;
}
if (InInstanceHandle->GetMeshComponent() != this)
{
UE_LOG(LogChaosVDEditor, Error, TEXT("[%s] Attempted to update a mesh instance using a handle from another component. No instances were updated | Handle Component [%s] | Current Component [%s]"), ANSI_TO_TCHAR(__FUNCTION__), *GetNameSafe(InInstanceHandle->GetMeshComponent()), *GetNameSafe(this));
return;
}
const int32 InstanceIndex = InInstanceHandle->GetMeshInstanceIndex();
NotifySMInstanceSelectionChanged({this, InstanceIndex}, bIsSelected);
}
void UChaosVDInstancedStaticMeshComponent::SetImplicitObject(const Chaos::FImplicitObject* InImplicitObject)
void UChaosVDInstancedStaticMeshComponent::UpdateInstanceColor(const TSharedPtr<FChaosVDMeshDataInstanceHandle>& InInstanceHandle, FLinearColor NewColor)
{
SetImplicitObject_Internal(InImplicitObject);
if (CurrentMaterial == nullptr)
{
CurrentMaterial = GetMaterial(0);
bool bIsSolidColor = FMath::IsNearlyEqual(NewColor.A, 1.0f);
UMaterialInterface* DesiredMaterial = InInstanceHandle->GetCachedMaterialInstance( bIsSolidColor ? EChaosVDMaterialType::Instanced : EChaosVDMaterialType::InstancedQueryOnly);
if (CurrentMaterial != DesiredMaterial)
{
SetMaterial(0, DesiredMaterial);
CurrentMaterial = DesiredMaterial;
}
}
SetNumCustomDataFloats(4);
SetCustomData(InInstanceHandle->GetMeshInstanceIndex(), TArrayView<float>(reinterpret_cast<float*>(&NewColor), 4));
}
void UChaosVDInstancedStaticMeshComponent::UpdateColors()
void UChaosVDInstancedStaticMeshComponent::UpdateInstanceWorldTransform(const TSharedPtr<FChaosVDMeshDataInstanceHandle>& InInstanceHandle, const FTransform& InTransform)
{
UpdateColors_Internal(this);
if (!InInstanceHandle.IsValid())
{
UE_LOG(LogChaosVDEditor, Warning, TEXT("[%s] Attempted to update a mesh instance using an invalid handle. No instances were updated"), ANSI_TO_TCHAR(__FUNCTION__));
return;
}
if (InInstanceHandle->GetMeshComponent() != this)
{
UE_LOG(LogChaosVDEditor, Error, TEXT("[%s] Attempted to update a mesh instance using a handle from another component. No instances were updated | Handle Component [%s] | Current Component [%s]"), ANSI_TO_TCHAR(__FUNCTION__), *GetNameSafe(InInstanceHandle->GetMeshComponent()), *GetNameSafe(this));
return;
}
const int32 InstanceIndex = InInstanceHandle->GetMeshInstanceIndex();
FTransform NewTransform = InTransform;
if (!InInstanceHandle->GetVisibility())
{
NewTransform.SetScale3D(FVector::ZeroVector);
}
constexpr bool bIsWorldSpaceTransform = true;
constexpr bool bMarkRenderDirty = true;
constexpr bool bTeleport = true;
UpdateInstanceTransform(InstanceIndex, NewTransform, bIsWorldSpaceTransform, bMarkRenderDirty, bTeleport);
}
void UChaosVDInstancedStaticMeshComponent::SetRootImplicitObject(const Chaos::FConstImplicitObjectPtr& InImplicitObject)
TArrayView<TSharedPtr<FChaosVDMeshDataInstanceHandle>> UChaosVDInstancedStaticMeshComponent::GetMeshDataInstanceHandles()
{
RootImplicitObject = InImplicitObject;
return CurrentInstanceHandles;
}
void UChaosVDInstancedStaticMeshComponent::Reset()
{
bIsMeshReady = false;
MeshReadyDelegate = FChaosVDMeshReadyDelegate();
ComponentEmptyDelegate = FChaosVDMeshComponentEmptyDelegate();
CurrentMaterial = nullptr;
CurrentInstanceHandles.Reset();
CurrentGeometryKey = 0;
}
bool UChaosVDInstancedStaticMeshComponent::UpdateGeometryKey(const uint32 NewHandleGeometryKey)
{
if (CurrentGeometryKey != 0 && CurrentGeometryKey != NewHandleGeometryKey)
{
ensure(false);
UE_LOG(LogChaosVDEditor, Warning, TEXT("[%s] Attempted to add a mesh instance belonging to another geometry key. No instance was added | CurrentKey [%u] | New Key [%u]"), ANSI_TO_TCHAR(__FUNCTION__), CurrentGeometryKey, NewHandleGeometryKey);
return false;
}
else
{
CurrentGeometryKey = NewHandleGeometryKey;
}
return true;
}
TSharedPtr<FChaosVDMeshDataInstanceHandle> UChaosVDInstancedStaticMeshComponent::AddMeshInstance(const FTransform InstanceTransform, bool bIsWorldSpace, const TSharedPtr<FChaosVDExtractedGeometryDataHandle>& InGeometryHandle, int32 ParticleID, int32 SolverID)
{
int32 InstanceIndex = AddInstance(InstanceTransform, bIsWorldSpace);
check(InstanceIndex != INDEX_NONE);
const TSharedPtr<FChaosVDMeshDataInstanceHandle> InstanceHandle = MakeShared<FChaosVDMeshDataInstanceHandle>(InstanceIndex, this, ParticleID, SolverID);
InstanceHandle->SetGeometryHandle(InGeometryHandle);
const uint32 NewHandleGeometryKey = InGeometryHandle->GetGeometryKey();
if (!UpdateGeometryKey(NewHandleGeometryKey))
{
return nullptr;
}
CurrentInstanceHandles.Add(InstanceHandle);
return InstanceHandle;
}
void UChaosVDInstancedStaticMeshComponent::AddMeshInstanceForHandle(TSharedPtr<FChaosVDMeshDataInstanceHandle> MeshDataHandle, const FTransform InstanceTransform, bool bIsWorldSpace, const TSharedPtr<FChaosVDExtractedGeometryDataHandle>& InGeometryHandle, int32 ParticleID, int32 SolverID)
{
const int32 InstanceIndex = AddInstance(InstanceTransform, bIsWorldSpace);
check(InstanceIndex != INDEX_NONE);
const uint32 NewHandleGeometryKey = InGeometryHandle->GetGeometryKey();
if (!UpdateGeometryKey(NewHandleGeometryKey))
{
return;
}
MeshDataHandle->SetMeshInstanceIndex(InstanceIndex);
MeshDataHandle->SetMeshComponent(this);
CurrentInstanceHandles.Add(MeshDataHandle);
}
void UChaosVDInstancedStaticMeshComponent::RemoveMeshInstance(TSharedPtr<FChaosVDMeshDataInstanceHandle> InHandleToRemove)
{
if (!InHandleToRemove.IsValid())
{
UE_LOG(LogChaosVDEditor, Warning, TEXT("[%s] Attempted to remove a mesh instace using an invalid handle. No instanced were removed"), ANSI_TO_TCHAR(__FUNCTION__));
return;
}
if (InHandleToRemove->GetMeshComponent() != this)
{
UE_LOG(LogChaosVDEditor, Error, TEXT("[%s] Attempted to remove a mesh instace using a handle from another component. No instanced were removed | Handle Component [%s] | Current Component [%s]"), ANSI_TO_TCHAR(__FUNCTION__), *GetNameSafe(InHandleToRemove->GetMeshComponent()), *GetNameSafe(this));
return;
}
if (!ensure(InHandleToRemove->GetMeshInstanceIndex() != INDEX_NONE))
{
return;
}
{
const int32 CurrentInstanceCount = GetInstanceCount();
if (InHandleToRemove->GetMeshInstanceIndex() > CurrentInstanceCount - 1)
{
ensure(false);
UE_LOG(LogChaosVDEditor, Error, TEXT("[%s] Mesh Data Handle has an invalid instance index. No instanced were removed | Handle Instance Index [%d] | Current Instance Count [%d]"), ANSI_TO_TCHAR(__FUNCTION__), InHandleToRemove->GetMeshInstanceIndex(), CurrentInstanceCount);
return;
}
}
RemoveInstance(InHandleToRemove->GetMeshInstanceIndex());
auto FindPredicate = [InHandleToRemove](const TSharedPtr<FChaosVDMeshDataInstanceHandle>& InstanceHandle)
{
return InstanceHandle->GetMeshInstanceIndex() == InHandleToRemove->GetMeshInstanceIndex();
};
// TODO: Evaluate if keeping the instance handles array sorted on any change is worth the cost to allow a binary search here. Same question for a Set
const int32 InstanceHandleIndex = CurrentInstanceHandles.IndexOfByPredicate(FindPredicate);
if (InstanceHandleIndex != INDEX_NONE)
{
CurrentInstanceHandles.RemoveAtSwap(InstanceHandleIndex);
}
// If the component becomes "empty", allow it to go back to the pool
if (GetInstanceCount() == 0)
{
ComponentEmptyDelegate.Broadcast(this);
}
}
bool UChaosVDInstancedStaticMeshComponent::Modify(bool bAlwaysMarkDirty)
{
// CVD Mesh Components are not saved to any assets or require undo
return false;
}
bool UChaosVDInstancedStaticMeshComponent::IsNavigationRelevant() const
{
return false;
}
uint32 UChaosVDInstancedStaticMeshComponent::GetGeometryKey() const
{
return CurrentGeometryKey;
}
TSharedPtr<FChaosVDMeshDataInstanceHandle> UChaosVDInstancedStaticMeshComponent::GetMeshDataInstanceHandle(int32 InstanceIndex) const
{
auto FindPredicate = [InstanceIndex](const TSharedPtr<FChaosVDMeshDataInstanceHandle>& InstanceHandle)
{
return InstanceHandle->GetMeshInstanceIndex() == InstanceIndex;
};
if (const TSharedPtr<FChaosVDMeshDataInstanceHandle>* FoundHandle = CurrentInstanceHandles.FindByPredicate(FindPredicate))
{
return *FoundHandle;
}
return nullptr;
}

View File

@@ -2,28 +2,170 @@
#include "Components/ChaosVDStaticMeshComponent.h"
void UChaosVDStaticMeshComponent::UpdateVisibility()
#include "ChaosVDModule.h"
#include "MaterialDomain.h"
#include "Materials/Material.h"
#include "Materials/MaterialInstanceDynamic.h"
uint32 UChaosVDStaticMeshComponent::GetGeometryKey() const
{
UpdateVisibility_Internal(CollisionData, Cast<UMeshComponent>(this));
return CurrentGeometryKey;
}
void UChaosVDStaticMeshComponent::UpdateDataFromShapeArray(const TArray<FChaosVDShapeCollisionData>& InShapeArray)
void UChaosVDStaticMeshComponent::UpdateInstanceVisibility(const TSharedPtr<FChaosVDMeshDataInstanceHandle>& InInstanceHandle, bool bIsVisible)
{
UpdateDataFromShapeArray_Internal(InShapeArray, CollisionData, this);
if (!InInstanceHandle.IsValid())
{
UE_LOG(LogChaosVDEditor, Warning, TEXT("[%s] Attempted to update a mesh instance using an invalid handle. No instances were updated"), ANSI_TO_TCHAR(__FUNCTION__));
return;
}
if (InInstanceHandle->GetMeshComponent() != this)
{
UE_LOG(LogChaosVDEditor, Error, TEXT("[%s] Attempted to update a mesh instance using a handle from another component. No instances were updated | Handle Component [%s] | Current Component [%s]"), ANSI_TO_TCHAR(__FUNCTION__), *GetNameSafe(InInstanceHandle->GetMeshComponent()), *GetNameSafe(this));
return;
}
SetVisibility(bIsVisible);
}
void UChaosVDStaticMeshComponent::SetImplicitObject(const Chaos::FImplicitObject* InImplicitObject)
void UChaosVDStaticMeshComponent::SetIsSelected(const TSharedPtr<FChaosVDMeshDataInstanceHandle>& InInstanceHandle, bool bIsSelected)
{
SetImplicitObject_Internal(InImplicitObject);
bIsOwningParticleSelected = bIsSelected;
PushSelectionToProxy();
}
void UChaosVDStaticMeshComponent::UpdateColors()
bool UChaosVDStaticMeshComponent::ShouldRenderSelected() const
{
UpdateColors_Internal(this);
return bIsOwningParticleSelected;
}
void UChaosVDStaticMeshComponent::SetRootImplicitObject(const Chaos::FConstImplicitObjectPtr& InImplicitObject)
void UChaosVDStaticMeshComponent::UpdateInstanceColor(const TSharedPtr<FChaosVDMeshDataInstanceHandle>& InInstanceHandle, FLinearColor NewColor)
{
RootImplicitObject = InImplicitObject;
if (!InInstanceHandle.IsValid())
{
UE_LOG(LogChaosVDEditor, Warning, TEXT("[%s] Attempted to update a mesh instance using an invalid handle. No instances were updated"), ANSI_TO_TCHAR(__FUNCTION__));
return;
}
if (InInstanceHandle->GetMeshComponent() != this)
{
UE_LOG(LogChaosVDEditor, Error, TEXT("[%s] Attempted to update a mesh instance using a handle from another component. No instances were updated | Handle Component [%s] | Current Component [%s]"), ANSI_TO_TCHAR(__FUNCTION__), *GetNameSafe(InInstanceHandle->GetMeshComponent()), *GetNameSafe(this));
return;
}
bool bIsSolidColor = FMath::IsNearlyEqual(NewColor.A, 1.0f);
if (UMaterialInstanceDynamic* MaterialToApply = bIsSolidColor ? InInstanceHandle->GetCachedMaterialInstance(EChaosVDMaterialType::SimOnlyMaterial) : InInstanceHandle->GetCachedMaterialInstance(EChaosVDMaterialType::QueryOnlyMaterial))
{
MaterialToApply->SetVectorParameterValue(TEXT("BaseColor"), NewColor);
InInstanceHandle->GetMeshComponent()->SetMaterial(0, MaterialToApply);
}
else
{
ensure(false);
UE_LOG(LogChaosVDEditor, Error, TEXT("[%s] Failed to get Query Only material for, applying the default mesh to all geometry"), ANSI_TO_TCHAR(__FUNCTION__));
InInstanceHandle->GetMeshComponent()->SetMaterial(0, UMaterial::GetDefaultMaterial(EMaterialDomain::MD_Surface));
}
}
void UChaosVDStaticMeshComponent::UpdateInstanceWorldTransform(const TSharedPtr<FChaosVDMeshDataInstanceHandle>& InInstanceHandle, const FTransform& InTransform)
{
if (!InInstanceHandle.IsValid())
{
UE_LOG(LogChaosVDEditor, Warning, TEXT("[%s] Attempted to update a mesh instance using an invalid handle. No instances were updated"), ANSI_TO_TCHAR(__FUNCTION__));
return;
}
if (InInstanceHandle->GetMeshComponent() != this)
{
UE_LOG(LogChaosVDEditor, Error, TEXT("[%s] Attempted to update a mesh instance using a handle from another component. No instances were updated | Handle Component [%s] | Current Component [%s]"), ANSI_TO_TCHAR(__FUNCTION__), *GetNameSafe(InInstanceHandle->GetMeshComponent()), *GetNameSafe(this));
return;
}
SetWorldTransform(InTransform);
}
void UChaosVDStaticMeshComponent::Reset()
{
bIsMeshReady = false;
MeshReadyDelegate = FChaosVDMeshReadyDelegate();
ComponentEmptyDelegate = FChaosVDMeshComponentEmptyDelegate();
CurrentMeshDataHandle = nullptr;
CurrentGeometryKey = 0;
}
TSharedPtr<FChaosVDMeshDataInstanceHandle> UChaosVDStaticMeshComponent::AddMeshInstance(const FTransform InstanceTransform, bool bIsWorldSpace, const TSharedPtr<FChaosVDExtractedGeometryDataHandle>& InGeometryHandle, int32 ParticleID, int32 SolverID)
{
// Static meshes only have one instance
constexpr int32 StaticMeshInstanceIndex = 0;
CurrentMeshDataHandle = MakeShared<FChaosVDMeshDataInstanceHandle>(StaticMeshInstanceIndex, this, ParticleID, SolverID);
CurrentMeshDataHandle->SetGeometryHandle(InGeometryHandle);
const uint32 NewHandleGeometryKey = InGeometryHandle->GetGeometryKey();
if (!UpdateGeometryKey(NewHandleGeometryKey))
{
return nullptr;
}
CurrentMeshDataHandle->SetWorldTransform(InstanceTransform);
return CurrentMeshDataHandle;
}
void UChaosVDStaticMeshComponent::AddMeshInstanceForHandle(TSharedPtr<FChaosVDMeshDataInstanceHandle> MeshDataHandle, const FTransform InstanceTransform, bool bIsWorldSpace, const TSharedPtr<FChaosVDExtractedGeometryDataHandle>& InGeometryHandle, int32 ParticleID, int32 SolverID)
{
// Static meshes only have one instance
constexpr int32 StaticMeshInstanceIndex = 0;
const uint32 NewHandleGeometryKey = InGeometryHandle->GetGeometryKey();
if (!UpdateGeometryKey(NewHandleGeometryKey))
{
return;
}
MeshDataHandle->SetMeshInstanceIndex(StaticMeshInstanceIndex);
MeshDataHandle->SetMeshComponent(this);
CurrentMeshDataHandle->SetWorldTransform(InstanceTransform);
}
void UChaosVDStaticMeshComponent::RemoveMeshInstance(TSharedPtr<FChaosVDMeshDataInstanceHandle> InHandleToRemove)
{
SetStaticMesh(nullptr);
CurrentMeshDataHandle = nullptr;
ComponentEmptyDelegate.Broadcast(this);
}
bool UChaosVDStaticMeshComponent::UpdateGeometryKey(uint32 NewHandleGeometryKey)
{
if (CurrentGeometryKey != 0 && CurrentGeometryKey != NewHandleGeometryKey)
{
ensure(false);
UE_LOG(LogChaosVDEditor, Warning, TEXT("[%s] Attempted to add a mesh instance belonging to another geometry key. No instance was added | CurrentKey [%u] | New Key [%u]"), ANSI_TO_TCHAR(__FUNCTION__), CurrentGeometryKey, NewHandleGeometryKey);
return false;
}
else
{
CurrentGeometryKey = NewHandleGeometryKey;
}
return true;
}
TSharedPtr<FChaosVDMeshDataInstanceHandle> UChaosVDStaticMeshComponent::GetMeshDataInstanceHandle(int32 InstanceIndex) const
{
return CurrentMeshDataHandle;
}
TArrayView<TSharedPtr<FChaosVDMeshDataInstanceHandle>> UChaosVDStaticMeshComponent::GetMeshDataInstanceHandles()
{
return TArrayView<TSharedPtr<FChaosVDMeshDataInstanceHandle>>(&CurrentMeshDataHandle, 1);
}

View File

@@ -29,6 +29,7 @@ void FChaosVDParticleDataWrapperCustomization::CustomizeChildren(TSharedRef<IPro
ParticleDataViewersNames.Add(GET_MEMBER_NAME_CHECKED(FChaosVDParticleDataWrapper, ParticleDynamics));
ParticleDataViewersNames.Add(GET_MEMBER_NAME_CHECKED(FChaosVDParticleDataWrapper, ParticleDynamicsMisc));
ParticleDataViewersNames.Add(GET_MEMBER_NAME_CHECKED(FChaosVDParticleDataWrapper, ParticleMassProps));
ParticleDataViewersNames.Add(GET_MEMBER_NAME_CHECKED(FChaosVDParticleDataWrapper, ParticleCluster));
for (uint32 ChildIndex = 0; ChildIndex < NumChildren; ++ChildIndex)
{

View File

@@ -0,0 +1,9 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "ObjectsWaitingGeometryList.h"
int32 FChaosVDWailingObjectListCVars::NumOfGTTaskToProcessPerTick = 200;
FAutoConsoleVariableRef FChaosVDWailingObjectListCVars::CVarChaosVDGeometryToProcessPerTick(
TEXT("p.Chaos.VD.Tool.GeometryToProcessPerTick"),
FChaosVDWailingObjectListCVars::NumOfGTTaskToProcessPerTick,
TEXT("Number of generated geometry to process each tick when loading a teace file in the CVD tool."));

View File

@@ -24,15 +24,15 @@ bool FChaosVDTraceParticleDataProcessor::ProcessRawData(const TArray<uint8>& InD
Chaos::FChaosArchive Ar(MemeReader);
FChaosVDParticleDataWrapper ParticleData;
ParticleData.Serialize(Ar);
TSharedPtr<FChaosVDParticleDataWrapper> ParticleData = MakeShared<FChaosVDParticleDataWrapper>();
ParticleData->Serialize(Ar);
// This can be null if the recording started Mid-Frame. In this case we just discard the data for now
if (FChaosVDSolverFrameData* FrameData = ProviderSharedPtr->GetCurrentSolverFrame(ParticleData.SolverID))
if (FChaosVDSolverFrameData* FrameData = ProviderSharedPtr->GetCurrentSolverFrame(ParticleData->SolverID))
{
if (ensureMsgf(FrameData->SolverSteps.Num() > 0, TEXT("A particle was traced without a valid step scope")))
{
FrameData->SolverSteps.Last().RecordedParticlesData.Add(MoveTemp(ParticleData));
FrameData->SolverSteps.Last().RecordedParticlesData.Add(ParticleData);
}
}

View File

@@ -148,6 +148,27 @@ void FChaosVDDebugDrawUtils::DrawBox(FPrimitiveDrawInterface* PDI, const FVector
}
}
void FChaosVDDebugDrawUtils::DrawLine(FPrimitiveDrawInterface* PDI, const FVector& InStartPosition, const FVector& InEndPosition, const FColor& InColor, FStringView DebugText, ESceneDepthPriorityGroup DepthPriority)
{
if (!PDI)
{
return;
}
constexpr float Thickness = 2.0f;
constexpr float DepthBias = 0;
constexpr bool bScreenSpace = Thickness > 0;
PDI->DrawLine(InStartPosition, InEndPosition, InColor, DepthPriority, Thickness, DepthBias, bScreenSpace);
if (!DebugText.IsEmpty())
{
// Draw the text in the middle of the line
const FVector TextWorldPosition = InStartPosition + ((InEndPosition - InStartPosition) * 0.5f);
DrawText(DebugText, TextWorldPosition, InColor);
}
}
void FChaosVDDebugDrawUtils::DrawCanvas(FViewport& InViewport, FSceneView& View, FCanvas& Canvas)
{
if (!GEngine)

View File

@@ -4,6 +4,8 @@
#include "ChaosVDEditorSettings.h"
#include "ChaosVDModule.h"
#include "ChaosVDParticleActor.h"
#include "ChaosVDScene.h"
#include "DataWrappers/ChaosVDParticleDataWrapper.h"
#include "Visualizers/ChaosVDDebugDrawUtils.h"
@@ -79,4 +81,29 @@ void FChaosVDParticleDataVisualizer::DrawVisualization(const FSceneView* View, F
FChaosVDDebugDrawUtils::DrawArrowVector(PDI, OwnerCoMLocation, OwnerCoMLocation + AngImpScale * ParticleDataViewer->ParticleDynamics.MAngularImpulseVelocity, TEXT("Angular Implulse Velocity"), FColor::Emerald);
}
}
// TODO: This is a Proof of concept to test how debug draw connectivity data will look
// This will get re-implemented when we move particle data visualization to the new visualization system currently used for Collision Data
if (ParticleDataViewer->ParticleCluster.HasValidData())
{
if (EnumHasAnyFlags(VisualizationFlagsToUse, EChaosVDParticleDataVisualizationFlags::ClusterConnectivityEdge))
{
for (const FChaosVDConnectivityEdge& ConnectivityEdge : ParticleDataViewer->ParticleCluster.ConnectivityEdges)
{
if (TSharedPtr<FChaosVDScene> ScenePtr = VisualizationContext.CVDScene.Pin())
{
if (AChaosVDParticleActor* SiblingParticle = ScenePtr->GetParticleActor(VisualizationContext.SolverID, ConnectivityEdge.SiblingParticleID))
{
if (const FChaosVDParticleDataWrapper* SiblingParticleData = SiblingParticle->GetParticleData())
{
FVector BoxExtents(2,2,2);
FTransform BoxTransform(ParticleDataViewer->ParticlePositionRotation.MR, ParticleDataViewer->ParticlePositionRotation.MX);
FChaosVDDebugDrawUtils::DrawBox(PDI, BoxExtents, FColor::Black, BoxTransform, nullptr, ESceneDepthPriorityGroup::SDPG_Foreground);
FChaosVDDebugDrawUtils::DrawLine(PDI, ParticleDataViewer->ParticlePositionRotation.MX, SiblingParticleData->ParticlePositionRotation.MX, FColor::Blue, FString::Printf(TEXT("Strain [%f]"), ConnectivityEdge.Strain), ESceneDepthPriorityGroup::SDPG_Foreground);
}
}
}
}
}
}
}

View File

@@ -207,8 +207,10 @@ void FChaosVDSolverCollisionDataComponentVisualizer::DrawMidPhaseData(const UAct
PDI->SetHitProxy(new HChaosVDContactPointProxy(Component, HitPRoxyDataFinder));
const FTransform& WorldActorTransform1 = CVDParticleActor1->GetTransform();
const FTransform& WorldActorTransform0 = CVDParticleActor0->GetTransform();
const FChaosVDParticleDataWrapper* ParticleDataActor1 = CVDParticleActor1->GetParticleData();
const FChaosVDParticleDataWrapper* ParticleDataActor0 = CVDParticleActor0->GetParticleData();
const FTransform WorldActorTransform1 = ParticleDataActor1 && ParticleDataActor1->ParticlePositionRotation.HasValidData() ? FTransform(ParticleDataActor1->ParticlePositionRotation.MR, ParticleDataActor1->ParticlePositionRotation.MX) : FTransform();
const FTransform WorldActorTransform0 = ParticleDataActor0 && ParticleDataActor0->ParticlePositionRotation.HasValidData() ? FTransform(ParticleDataActor0->ParticlePositionRotation.MR, ParticleDataActor0->ParticlePositionRotation.MX) : FTransform();
constexpr int32 ContactPlaneOwner = 1;
constexpr int32 ContactPointOwner = 1 - ContactPlaneOwner;
@@ -299,7 +301,6 @@ void FChaosVDSolverCollisionDataComponentVisualizer::DrawMidPhaseData(const UAct
if (ManifoldPoint.InitialPhi != 0)
{
FChaosVDDebugDrawUtils::DrawCircle(PDI, WorldPlaneLocation + ManifoldPoint.InitialPhi * WorldPlaneNormal, 0.25f * DebugDrawSettings.ContactCircleRadius, CircleSegments, InitialPhiColor, LinesThickness, Axes.GetUnitAxis(EAxis::Y), Axes.GetUnitAxis(EAxis::Z), TEXT("Contact : Manifold Initial Phi"), DebugDrawSettings.DepthPriority);
}
}

View File

@@ -115,7 +115,7 @@ void SChaosVDCollisionDataInspector::SetCollisionDataProviderObjectToInspect(ICh
return;
}
CurrentObjectBeingInspectedName = CollisionDataProvider->GetName();
CurrentObjectBeingInspectedName = CollisionDataProvider->GetProviderName();
TArray<TSharedPtr<FName>> NewCollisionDataEntriesNameList;
TArray<TSharedPtr<FChaosVDCollisionDataFinder>> FoundCollisionData;

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