2019-12-27 09:26:59 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-10-01 20:41:42 -04:00
2021-06-12 14:30:22 -04:00
# include "Components/DynamicMeshComponent.h"
2019-10-01 20:41:42 -04:00
# include "PrimitiveSceneProxy.h"
# include "MaterialShared.h"
# include "Engine/CollisionProfile.h"
2022-10-26 12:57:32 -04:00
# include "Engine/World.h"
2019-10-01 20:41:42 -04:00
# include "Materials/Material.h"
2020-04-18 18:42:59 -04:00
# include "Async/Async.h"
2024-03-28 11:32:35 -04:00
# include "HAL/UESemaphore.h"
2021-06-20 18:12:30 -04:00
# include "Engine/CollisionProfile.h"
2024-02-23 14:43:16 -05:00
# include "PhysicsEngine/PhysicsSettings.h"
2019-10-01 20:41:42 -04:00
2021-06-13 00:36:02 -04:00
# include "DynamicMesh/DynamicMeshAttributeSet.h"
# include "DynamicMesh/MeshNormals.h"
2019-10-01 20:41:42 -04:00
# include "MeshDescriptionToDynamicMesh.h"
2022-06-15 16:49:13 -04:00
# include "Util/ColorConstants.h"
2019-10-01 20:41:42 -04:00
# include "Changes/MeshVertexChange.h"
# include "Changes/MeshChange.h"
2021-06-13 00:36:02 -04:00
# include "DynamicMesh/MeshTransforms.h"
2019-10-01 20:41:42 -04:00
2023-07-18 10:07:19 -04:00
# include "UObject/UE5ReleaseStreamObjectVersion.h"
2019-10-01 20:41:42 -04:00
// default proxy for this component
2021-06-12 14:30:22 -04:00
# include "Components/DynamicMeshSceneProxy.h"
2019-10-01 20:41:42 -04:00
2022-09-24 13:57:58 -04:00
# include UE_INLINE_GENERATED_CPP_BY_NAME(DynamicMeshComponent)
2021-03-09 19:33:56 -04:00
using namespace UE : : Geometry ;
2019-10-01 20:41:42 -04:00
2024-03-04 18:02:09 -05:00
static TAutoConsoleVariable < int32 > CVarDynamicMeshComponent_MaxComplexCollisionTriCount (
TEXT ( " geometry.DynamicMesh.MaxComplexCollisionTriCount " ) ,
250000 ,
TEXT ( " If a DynamicMeshCompnent's UDynamicMesh has a larger triangle count than this value, it will not be passed to the Physics system to be used as Complex Collision geometry. A negative value indicates no limit. " )
) ;
2021-01-28 01:46:53 -04:00
namespace
{
// probably should be something defined for the whole tool framework...
# if WITH_EDITOR
2021-06-12 14:30:22 -04:00
static EAsyncExecution DynamicMeshComponentAsyncExecTarget = EAsyncExecution : : LargeThreadPool ;
2021-01-28 01:46:53 -04:00
# else
2021-06-12 14:30:22 -04:00
static EAsyncExecution DynamicMeshComponentAsyncExecTarget = EAsyncExecution : : ThreadPool ;
2021-01-28 01:46:53 -04:00
# endif
}
2019-10-01 20:41:42 -04:00
2022-06-20 22:42:51 -04:00
namespace UELocal
{
static EMeshRenderAttributeFlags ConvertChangeFlagsToUpdateFlags ( EDynamicMeshAttributeChangeFlags ChangeFlags )
{
EMeshRenderAttributeFlags UpdateFlags = EMeshRenderAttributeFlags : : None ;
if ( ( ChangeFlags & EDynamicMeshAttributeChangeFlags : : VertexPositions ) ! = EDynamicMeshAttributeChangeFlags : : Unknown )
{
UpdateFlags | = EMeshRenderAttributeFlags : : Positions ;
}
if ( ( ChangeFlags & EDynamicMeshAttributeChangeFlags : : NormalsTangents ) ! = EDynamicMeshAttributeChangeFlags : : Unknown )
{
UpdateFlags | = EMeshRenderAttributeFlags : : VertexNormals ;
}
if ( ( ChangeFlags & EDynamicMeshAttributeChangeFlags : : VertexColors ) ! = EDynamicMeshAttributeChangeFlags : : Unknown )
{
UpdateFlags | = EMeshRenderAttributeFlags : : VertexColors ;
}
if ( ( ChangeFlags & EDynamicMeshAttributeChangeFlags : : UVs ) ! = EDynamicMeshAttributeChangeFlags : : Unknown )
{
UpdateFlags | = EMeshRenderAttributeFlags : : VertexUVs ;
}
return UpdateFlags ;
}
}
2019-10-01 20:41:42 -04:00
2021-06-12 14:30:22 -04:00
UDynamicMeshComponent : : UDynamicMeshComponent ( const FObjectInitializer & ObjectInitializer )
2019-10-01 20:41:42 -04:00
: Super ( ObjectInitializer )
{
PrimaryComponentTick . bCanEverTick = false ;
SetCollisionProfileName ( UCollisionProfile : : NoCollision_ProfileName ) ;
2021-06-10 18:37:57 -04:00
MeshObject = CreateDefaultSubobject < UDynamicMesh > ( TEXT ( " DynamicMesh " ) ) ;
//MeshObject->SetFlags(RF_Transactional);
2021-06-12 14:30:22 -04:00
MeshObjectChangedHandle = MeshObject - > OnMeshChanged ( ) . AddUObject ( this , & UDynamicMeshComponent : : OnMeshObjectChanged ) ;
2021-06-10 18:37:57 -04:00
2024-03-27 14:27:24 -04:00
DistanceFieldComputeQueue . OnComputeCompleted = [ this ] ( TUniquePtr < FDistanceFieldVolumeData > NewData )
{
OnNewDistanceFieldData_Async ( MoveTemp ( NewData ) ) ;
} ;
2021-06-11 22:42:32 -04:00
ResetProxy ( ) ;
2021-06-10 18:37:57 -04:00
}
2023-07-18 10:07:19 -04:00
void UDynamicMeshComponent : : Serialize ( FArchive & Ar )
{
Super : : Serialize ( Ar ) ;
Ar . UsingCustomVersion ( FUE5ReleaseStreamObjectVersion : : GUID ) ;
}
2021-06-10 18:37:57 -04:00
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : PostLoad ( )
2021-06-10 18:37:57 -04:00
{
Super : : PostLoad ( ) ;
2023-07-18 10:07:19 -04:00
const int32 UE5ReleaseStreamObjectVersion = GetLinkerCustomVersion ( FUE5ReleaseStreamObjectVersion : : GUID ) ;
if ( UE5ReleaseStreamObjectVersion < FUE5ReleaseStreamObjectVersion : : DynamicMeshComponentsDefaultUseExternalTangents )
{
// Set the old default value
if ( TangentsType = = EDynamicMeshComponentTangentsMode : : Default )
{
TangentsType = EDynamicMeshComponentTangentsMode : : NoTangents ;
}
}
2023-01-11 20:55:38 -05:00
// The intention here is that MeshObject is never nullptr, however we cannot guarantee this as a subclass
// may have set it to null, and/or some type of serialization issue has caused it to fail to save/load.
// Avoid immediate crashes by creating a new UDynamicMesh here in such cases
if ( ensure ( MeshObject ! = nullptr ) = = false )
{
MeshObject = NewObject < UDynamicMesh > ( this , TEXT ( " DynamicMesh " ) ) ;
}
2021-06-12 14:30:22 -04:00
MeshObjectChangedHandle = MeshObject - > OnMeshChanged ( ) . AddUObject ( this , & UDynamicMeshComponent : : OnMeshObjectChanged ) ;
2021-06-10 18:37:57 -04:00
ResetProxy ( ) ;
2021-06-20 18:12:30 -04:00
2021-09-13 14:56:25 -04:00
// This is a fixup for existing UDynamicMeshComponents that did not have the correct flags
// on the Instanced UBodySetup, these flags are now set in GetBodySetup() on new instances
if ( MeshBodySetup & & IsTemplate ( ) )
{
MeshBodySetup - > SetFlags ( RF_Public | RF_ArchetypeObject ) ;
}
2021-06-20 18:12:30 -04:00
// make sure BodySetup is created
GetBodySetup ( ) ;
2024-03-27 14:27:24 -04:00
// Note we don't serialize the distance field, so recompute on load (and below in PostEditImport, on duplicate/copy)
// (Note if we do switch to serializing it, it is DDC cache data and not versioned, so must be checked vs its DDC key and potentially invalidated)
if ( CurrentDistanceField . IsValid ( ) ! = ( DistanceFieldMode ! = EDynamicMeshComponentDistanceFieldMode : : NoDistanceField ) )
{
OnNewDistanceFieldMode ( ) ;
}
2019-10-01 20:41:42 -04:00
}
2024-03-27 14:27:24 -04:00
void UDynamicMeshComponent : : PostEditImport ( )
{
Super : : PostEditImport ( ) ;
if ( CurrentDistanceField . IsValid ( ) ! = ( DistanceFieldMode ! = EDynamicMeshComponentDistanceFieldMode : : NoDistanceField ) )
{
OnNewDistanceFieldMode ( ) ;
}
}
2019-10-01 20:41:42 -04:00
2021-06-20 18:12:30 -04:00
# if WITH_EDITOR
void UDynamicMeshComponent : : PostEditChangeProperty ( FPropertyChangedEvent & PropertyChangedEvent )
{
Super : : PostEditChangeProperty ( PropertyChangedEvent ) ;
const FName PropName = PropertyChangedEvent . GetPropertyName ( ) ;
2023-07-18 10:07:19 -04:00
if ( PropName = = GET_MEMBER_NAME_CHECKED ( UDynamicMeshComponent , TangentsType ) )
{
InvalidateAutoCalculatedTangents ( ) ;
}
else if ( ( PropName = = GET_MEMBER_NAME_CHECKED ( UDynamicMeshComponent , bEnableComplexCollision ) ) | |
2021-06-20 18:12:30 -04:00
( PropName = = GET_MEMBER_NAME_CHECKED ( UDynamicMeshComponent , CollisionType ) ) | |
( PropName = = GET_MEMBER_NAME_CHECKED ( UDynamicMeshComponent , bDeferCollisionUpdates ) ) )
{
if ( bDeferCollisionUpdates )
{
InvalidatePhysicsData ( ) ;
}
else
{
RebuildPhysicsData ( ) ;
}
}
}
# endif
2021-06-11 22:42:32 -04:00
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : SetMesh ( UE : : Geometry : : FDynamicMesh3 & & MoveMesh )
2021-06-11 22:42:32 -04:00
{
2023-11-28 09:50:36 -05:00
if ( ensureMsgf ( IsEditable ( ) , TEXT ( " Attempted to modify the internal mesh of a UDynamicMeshComponent that is not editable " ) ) )
{
MeshObject - > SetMesh ( MoveTemp ( MoveMesh ) ) ;
}
2021-06-11 22:42:32 -04:00
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : ProcessMesh (
2021-06-11 22:42:32 -04:00
TFunctionRef < void ( const UE : : Geometry : : FDynamicMesh3 & ) > ProcessFunc ) const
{
MeshObject - > ProcessMesh ( ProcessFunc ) ;
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : EditMesh ( TFunctionRef < void ( UE : : Geometry : : FDynamicMesh3 & ) > EditFunc ,
2021-06-11 22:42:32 -04:00
EDynamicMeshComponentRenderUpdateMode UpdateMode )
{
2023-11-28 09:50:36 -05:00
if ( ensureMsgf ( IsEditable ( ) , TEXT ( " Attempted to modify the internal mesh of a UDynamicMeshComponent that is not editable " ) ) )
2021-06-11 22:42:32 -04:00
{
2023-11-28 09:50:36 -05:00
MeshObject - > EditMesh ( EditFunc ) ;
if ( UpdateMode ! = EDynamicMeshComponentRenderUpdateMode : : NoUpdate )
{
NotifyMeshUpdated ( ) ;
}
2021-06-11 22:42:32 -04:00
}
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : SetRenderMeshPostProcessor ( TUniquePtr < IRenderMeshPostProcessor > Processor )
2021-06-11 22:42:32 -04:00
{
RenderMeshPostProcessor = MoveTemp ( Processor ) ;
if ( RenderMeshPostProcessor )
{
if ( ! RenderMesh )
{
RenderMesh = MakeUnique < FDynamicMesh3 > ( * GetMesh ( ) ) ;
}
}
else
{
// No post processor, no render mesh
RenderMesh = nullptr ;
}
}
2021-06-12 14:30:22 -04:00
FDynamicMesh3 * UDynamicMeshComponent : : GetRenderMesh ( )
2020-11-05 19:18:40 -04:00
{
if ( RenderMeshPostProcessor & & RenderMesh )
{
return RenderMesh . Get ( ) ;
}
else
{
2021-06-10 18:37:57 -04:00
return GetMesh ( ) ;
2020-11-05 19:18:40 -04:00
}
}
2021-06-12 14:30:22 -04:00
const FDynamicMesh3 * UDynamicMeshComponent : : GetRenderMesh ( ) const
2020-11-05 19:18:40 -04:00
{
if ( RenderMeshPostProcessor & & RenderMesh )
{
return RenderMesh . Get ( ) ;
}
else
{
2021-06-10 18:37:57 -04:00
return GetMesh ( ) ;
2020-11-05 19:18:40 -04:00
}
}
2019-10-01 20:41:42 -04:00
2020-06-23 18:40:00 -04:00
2022-01-29 14:37:53 -05:00
void UDynamicMeshComponent : : ApplyTransform ( const FTransform3d & Transform , bool bInvert )
2020-04-18 18:42:59 -04:00
{
2023-11-28 09:50:36 -05:00
if ( ensureMsgf ( IsEditable ( ) , TEXT ( " Attempted to modify the internal mesh of a UDynamicMeshComponent that is not editable " ) ) )
2020-04-18 18:42:59 -04:00
{
2023-11-28 09:50:36 -05:00
MeshObject - > EditMesh ( [ & ] ( FDynamicMesh3 & EditMesh )
2019-10-01 20:41:42 -04:00
{
2023-11-28 09:50:36 -05:00
if ( bInvert )
{
MeshTransforms : : ApplyTransformInverse ( EditMesh , Transform , true ) ;
}
else
{
MeshTransforms : : ApplyTransform ( EditMesh , Transform , true ) ;
}
} , EDynamicMeshChangeType : : DeformationEdit ) ;
}
2019-10-01 20:41:42 -04:00
}
2021-09-15 21:24:22 -04:00
bool UDynamicMeshComponent : : ValidateMaterialSlots ( bool bCreateIfMissing , bool bDeleteExtraSlots )
{
int32 MaxMeshMaterialID = 0 ;
MeshObject - > ProcessMesh ( [ & ] ( const FDynamicMesh3 & EditMesh )
{
if ( EditMesh . HasAttributes ( ) & & EditMesh . Attributes ( ) - > HasMaterialID ( ) & & EditMesh . Attributes ( ) - > GetMaterialID ( ) ! = nullptr )
{
const FDynamicMeshMaterialAttribute * MaterialIDs = EditMesh . Attributes ( ) - > GetMaterialID ( ) ;
for ( int TriangleID : EditMesh . TriangleIndicesItr ( ) )
{
MaxMeshMaterialID = FMath : : Max ( MaxMeshMaterialID , MaterialIDs - > GetValue ( TriangleID ) ) ;
}
}
} ) ;
int32 NumRequiredMaterials = MaxMeshMaterialID + 1 ;
int32 NumMaterials = GetNumMaterials ( ) ;
if ( bCreateIfMissing & & NumMaterials < NumRequiredMaterials )
{
for ( int32 k = NumMaterials ; k < NumRequiredMaterials ; + + k )
{
SetMaterial ( k , nullptr ) ;
}
}
NumMaterials = GetNumMaterials ( ) ;
if ( bDeleteExtraSlots & & NumMaterials > NumRequiredMaterials )
{
SetNumMaterials ( NumRequiredMaterials ) ;
}
NumMaterials = GetNumMaterials ( ) ;
return ( NumMaterials = = NumRequiredMaterials ) ;
}
2024-04-30 01:03:41 -04:00
void UDynamicMeshComponent : : ConfigureMaterialSet ( const TArray < UMaterialInterface * > & NewMaterialSet , bool bDeleteExtraSlots )
2021-09-15 21:24:22 -04:00
{
for ( int k = 0 ; k < NewMaterialSet . Num ( ) ; + + k )
{
SetMaterial ( k , NewMaterialSet [ k ] ) ;
}
2024-04-30 01:03:41 -04:00
if ( bDeleteExtraSlots )
{
SetNumMaterials ( NewMaterialSet . Num ( ) ) ;
}
2021-09-15 21:24:22 -04:00
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : SetTangentsType ( EDynamicMeshComponentTangentsMode NewTangentsType )
2021-06-11 22:42:32 -04:00
{
if ( NewTangentsType ! = TangentsType )
{
TangentsType = NewTangentsType ;
InvalidateAutoCalculatedTangents ( ) ;
}
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : InvalidateAutoCalculatedTangents ( )
2021-06-11 22:42:32 -04:00
{
bAutoCalculatedTangentsValid = false ;
}
2021-06-12 14:30:22 -04:00
const UE : : Geometry : : FMeshTangentsf * UDynamicMeshComponent : : GetAutoCalculatedTangents ( )
2021-06-11 22:42:32 -04:00
{
2023-07-18 10:07:19 -04:00
if ( GetTangentsType ( ) = = EDynamicMeshComponentTangentsMode : : AutoCalculated & & GetDynamicMesh ( ) - > GetMeshRef ( ) . HasAttributes ( ) )
2021-06-11 22:42:32 -04:00
{
UpdateAutoCalculatedTangents ( ) ;
return ( bAutoCalculatedTangentsValid ) ? & AutoCalculatedTangents : nullptr ;
}
return nullptr ;
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : UpdateAutoCalculatedTangents ( )
2021-06-11 22:42:32 -04:00
{
2023-07-18 10:07:19 -04:00
if ( GetTangentsType ( ) = = EDynamicMeshComponentTangentsMode : : AutoCalculated & & bAutoCalculatedTangentsValid = = false )
2021-06-11 22:42:32 -04:00
{
GetDynamicMesh ( ) - > ProcessMesh ( [ & ] ( const FDynamicMesh3 & Mesh )
{
2021-09-08 21:47:47 -04:00
if ( Mesh . HasAttributes ( ) )
{
const FDynamicMeshUVOverlay * UVOverlay = Mesh . Attributes ( ) - > PrimaryUV ( ) ;
const FDynamicMeshNormalOverlay * NormalOverlay = Mesh . Attributes ( ) - > PrimaryNormals ( ) ;
if ( UVOverlay & & NormalOverlay )
{
AutoCalculatedTangents . SetMesh ( & Mesh ) ;
AutoCalculatedTangents . ComputeTriVertexTangents ( NormalOverlay , UVOverlay , FComputeTangentsOptions ( ) ) ;
AutoCalculatedTangents . SetMesh ( nullptr ) ;
2024-02-16 19:01:54 -05:00
bAutoCalculatedTangentsValid = true ;
2021-09-08 21:47:47 -04:00
}
}
2021-06-11 22:42:32 -04:00
} ) ;
}
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : UpdateLocalBounds ( )
2019-10-01 20:41:42 -04:00
{
2021-06-10 18:37:57 -04:00
LocalBounds = GetMesh ( ) - > GetBounds ( true ) ;
if ( LocalBounds . MaxDim ( ) < = 0 )
{
2021-10-05 13:22:31 -04:00
// If bbox is empty, set a very small bbox to avoid log spam/etc in other engine systems.
// The check used is generally IsNearlyZero(), which defaults to KINDA_SMALL_NUMBER, so set
// a slightly larger box here to be above that threshold
LocalBounds = FAxisAlignedBox3d ( FVector3d : : Zero ( ) , ( double ) ( KINDA_SMALL_NUMBER + SMALL_NUMBER ) ) ;
2021-06-10 18:37:57 -04:00
}
2019-10-01 20:41:42 -04:00
}
2021-06-12 14:30:22 -04:00
FDynamicMeshSceneProxy * UDynamicMeshComponent : : GetCurrentSceneProxy ( )
2021-06-10 18:37:57 -04:00
{
if ( bProxyValid )
{
2021-06-12 14:30:22 -04:00
return ( FDynamicMeshSceneProxy * ) SceneProxy ;
2021-06-10 18:37:57 -04:00
}
return nullptr ;
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : ResetProxy ( )
2019-10-01 20:41:42 -04:00
{
2020-12-03 17:40:22 -04:00
bProxyValid = false ;
2021-06-11 22:42:32 -04:00
InvalidateAutoCalculatedTangents ( ) ;
2020-12-03 17:40:22 -04:00
2019-10-01 20:41:42 -04:00
// Need to recreate scene proxy to send it over
MarkRenderStateDirty ( ) ;
2021-06-10 18:37:57 -04:00
UpdateLocalBounds ( ) ;
2019-10-01 20:41:42 -04:00
UpdateBounds ( ) ;
2021-06-10 18:37:57 -04:00
// this seems speculative, ie we may not actually have a mesh update, but we currently ResetProxy() in lots
// of places where that is what it means
GetDynamicMesh ( ) - > PostRealtimeUpdate ( ) ;
2019-10-01 20:41:42 -04:00
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : NotifyMeshUpdated ( )
2020-11-05 19:18:40 -04:00
{
if ( RenderMeshPostProcessor )
{
2021-06-10 18:37:57 -04:00
RenderMeshPostProcessor - > ProcessMesh ( * GetMesh ( ) , * RenderMesh ) ;
2020-11-05 19:18:40 -04:00
}
ResetProxy ( ) ;
}
2023-06-15 22:53:04 -04:00
void UDynamicMeshComponent : : NotifyMeshModified ( )
{
NotifyMeshUpdated ( ) ;
}
2019-10-01 20:41:42 -04:00
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : FastNotifyColorsUpdated ( )
2019-10-01 20:41:42 -04:00
{
2020-12-03 17:40:22 -04:00
// should not be using fast paths if we have to run mesh postprocessor
if ( ensure ( ! RenderMeshPostProcessor ) = = false )
2020-11-05 19:18:40 -04:00
{
2021-06-10 18:37:57 -04:00
RenderMeshPostProcessor - > ProcessMesh ( * GetMesh ( ) , * RenderMesh ) ;
2020-12-03 17:40:22 -04:00
ResetProxy ( ) ;
return ;
2020-11-05 19:18:40 -04:00
}
2021-06-12 14:30:22 -04:00
FDynamicMeshSceneProxy * Proxy = GetCurrentSceneProxy ( ) ;
2024-03-20 11:50:05 -04:00
if ( Proxy & & AllowFastUpdate ( ) )
2019-10-01 20:41:42 -04:00
{
2024-04-16 14:28:43 -04:00
if ( HasTriangleColorFunction ( ) & & Proxy - > MeshRenderBufferSetConverter . bUsePerTriangleColor = = false )
2019-12-19 18:07:47 -05:00
{
2024-04-16 14:28:43 -04:00
Proxy - > MeshRenderBufferSetConverter . bUsePerTriangleColor = true ;
Proxy - > MeshRenderBufferSetConverter . PerTriangleColorFunc = [ this ] ( const FDynamicMesh3 * MeshIn , int TriangleID ) { return GetTriangleColor ( MeshIn , TriangleID ) ; } ;
2019-12-19 18:07:47 -05:00
}
2024-04-16 14:28:43 -04:00
else if ( ! HasTriangleColorFunction ( ) & & Proxy - > MeshRenderBufferSetConverter . bUsePerTriangleColor = = true )
2019-12-19 18:07:47 -05:00
{
2024-04-16 14:28:43 -04:00
Proxy - > MeshRenderBufferSetConverter . bUsePerTriangleColor = false ;
Proxy - > MeshRenderBufferSetConverter . PerTriangleColorFunc = nullptr ;
2019-12-19 18:07:47 -05:00
}
2024-04-16 14:28:43 -04:00
if ( HasVertexColorRemappingFunction ( ) & & Proxy - > MeshRenderBufferSetConverter . bApplyVertexColorRemapping = = false )
2023-05-17 11:12:48 -04:00
{
2024-04-16 14:28:43 -04:00
Proxy - > MeshRenderBufferSetConverter . bApplyVertexColorRemapping = true ;
Proxy - > MeshRenderBufferSetConverter . VertexColorRemappingFunc = [ this ] ( FVector4f & Color ) { RemapVertexColor ( Color ) ; } ;
2023-05-17 11:12:48 -04:00
}
2024-04-16 14:28:43 -04:00
else if ( ! HasVertexColorRemappingFunction ( ) & & Proxy - > MeshRenderBufferSetConverter . bApplyVertexColorRemapping = = true )
2023-05-17 11:12:48 -04:00
{
2024-04-16 14:28:43 -04:00
Proxy - > MeshRenderBufferSetConverter . bApplyVertexColorRemapping = false ;
Proxy - > MeshRenderBufferSetConverter . VertexColorRemappingFunc = nullptr ;
2023-05-17 11:12:48 -04:00
}
2020-01-27 20:11:15 -05:00
Proxy - > FastUpdateVertices ( false , false , true , false ) ;
2019-12-19 18:07:47 -05:00
//MarkRenderDynamicDataDirty();
2019-10-01 20:41:42 -04:00
}
else
{
2020-11-05 19:18:40 -04:00
ResetProxy ( ) ;
2019-10-01 20:41:42 -04:00
}
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : FastNotifyPositionsUpdated ( bool bNormals , bool bColors , bool bUVs )
2019-10-01 20:41:42 -04:00
{
2020-12-03 17:40:22 -04:00
// should not be using fast paths if we have to run mesh postprocessor
if ( ensure ( ! RenderMeshPostProcessor ) = = false )
2020-11-05 19:18:40 -04:00
{
2021-06-10 18:37:57 -04:00
RenderMeshPostProcessor - > ProcessMesh ( * GetMesh ( ) , * RenderMesh ) ;
2020-12-03 17:40:22 -04:00
ResetProxy ( ) ;
return ;
2020-11-05 19:18:40 -04:00
}
2021-06-12 14:30:22 -04:00
FDynamicMeshSceneProxy * Proxy = GetCurrentSceneProxy ( ) ;
2024-03-20 11:50:05 -04:00
if ( Proxy & & AllowFastUpdate ( ) )
2019-10-01 20:41:42 -04:00
{
2021-01-28 01:46:53 -04:00
// calculate bounds while we are updating vertices
TFuture < void > UpdateBoundsCalc ;
2021-06-12 14:30:22 -04:00
UpdateBoundsCalc = Async ( DynamicMeshComponentAsyncExecTarget , [ this ] ( )
2021-01-28 01:46:53 -04:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastPositionsUpdate_AsyncBoundsUpdate ) ;
2021-06-10 18:37:57 -04:00
UpdateLocalBounds ( ) ;
2021-01-28 01:46:53 -04:00
} ) ;
2020-01-27 20:11:15 -05:00
GetCurrentSceneProxy ( ) - > FastUpdateVertices ( true , bNormals , bColors , bUVs ) ;
2021-06-10 18:37:57 -04:00
2019-12-19 18:07:47 -05:00
//MarkRenderDynamicDataDirty();
MarkRenderTransformDirty ( ) ;
2021-01-28 01:46:53 -04:00
UpdateBoundsCalc . Wait ( ) ;
2019-12-19 18:07:47 -05:00
UpdateBounds ( ) ;
2021-06-10 18:37:57 -04:00
GetDynamicMesh ( ) - > PostRealtimeUpdate ( ) ;
2019-10-01 20:41:42 -04:00
}
else
{
2020-11-05 19:18:40 -04:00
ResetProxy ( ) ;
2019-10-01 20:41:42 -04:00
}
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : FastNotifyVertexAttributesUpdated ( bool bNormals , bool bColors , bool bUVs )
2020-01-27 20:11:15 -05:00
{
2020-12-03 17:40:22 -04:00
// should not be using fast paths if we have to run mesh postprocessor
if ( ensure ( ! RenderMeshPostProcessor ) = = false )
2020-11-05 19:18:40 -04:00
{
2021-06-10 18:37:57 -04:00
RenderMeshPostProcessor - > ProcessMesh ( * GetMesh ( ) , * RenderMesh ) ;
2020-12-03 17:40:22 -04:00
ResetProxy ( ) ;
return ;
2020-11-05 19:18:40 -04:00
}
2021-06-12 14:30:22 -04:00
FDynamicMeshSceneProxy * Proxy = GetCurrentSceneProxy ( ) ;
2024-03-20 11:50:05 -04:00
if ( Proxy & & ensure ( bNormals | | bColors | | bUVs ) & & AllowFastUpdate ( ) )
2020-01-27 20:11:15 -05:00
{
2020-04-18 18:42:59 -04:00
GetCurrentSceneProxy ( ) - > FastUpdateVertices ( false , bNormals , bColors , bUVs ) ;
2020-01-27 20:11:15 -05:00
//MarkRenderDynamicDataDirty();
2020-04-18 18:42:59 -04:00
//MarkRenderTransformDirty();
2021-06-10 18:37:57 -04:00
GetDynamicMesh ( ) - > PostRealtimeUpdate ( ) ;
2020-01-27 20:11:15 -05:00
}
else
{
2020-11-05 19:18:40 -04:00
ResetProxy ( ) ;
2020-01-27 20:11:15 -05:00
}
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : FastNotifyVertexAttributesUpdated ( EMeshRenderAttributeFlags UpdatedAttributes )
2020-04-18 18:42:59 -04:00
{
2020-12-03 17:40:22 -04:00
// should not be using fast paths if we have to run mesh postprocessor
if ( ensure ( ! RenderMeshPostProcessor ) = = false )
2020-11-05 19:18:40 -04:00
{
2021-06-10 18:37:57 -04:00
RenderMeshPostProcessor - > ProcessMesh ( * GetMesh ( ) , * RenderMesh ) ;
2020-12-03 17:40:22 -04:00
ResetProxy ( ) ;
return ;
2020-11-05 19:18:40 -04:00
}
2021-06-12 14:30:22 -04:00
FDynamicMeshSceneProxy * Proxy = GetCurrentSceneProxy ( ) ;
2024-03-20 11:50:05 -04:00
if ( Proxy & & ensure ( UpdatedAttributes ! = EMeshRenderAttributeFlags : : None ) & & AllowFastUpdate ( ) )
2020-04-18 18:42:59 -04:00
{
bool bPositions = ( UpdatedAttributes & EMeshRenderAttributeFlags : : Positions ) ! = EMeshRenderAttributeFlags : : None ;
2021-01-28 01:46:53 -04:00
// calculate bounds while we are updating vertices
TFuture < void > UpdateBoundsCalc ;
if ( bPositions )
{
2021-06-12 14:30:22 -04:00
UpdateBoundsCalc = Async ( DynamicMeshComponentAsyncExecTarget , [ this ] ( )
2021-01-28 01:46:53 -04:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastVertexAttribUpdate_AsyncBoundsUpdate ) ;
2021-06-10 18:37:57 -04:00
UpdateLocalBounds ( ) ;
2021-01-28 01:46:53 -04:00
} ) ;
}
2020-04-18 18:42:59 -04:00
GetCurrentSceneProxy ( ) - > FastUpdateVertices ( bPositions ,
( UpdatedAttributes & EMeshRenderAttributeFlags : : VertexNormals ) ! = EMeshRenderAttributeFlags : : None ,
( UpdatedAttributes & EMeshRenderAttributeFlags : : VertexColors ) ! = EMeshRenderAttributeFlags : : None ,
( UpdatedAttributes & EMeshRenderAttributeFlags : : VertexUVs ) ! = EMeshRenderAttributeFlags : : None ) ;
if ( bPositions )
{
MarkRenderTransformDirty ( ) ;
2021-01-28 01:46:53 -04:00
UpdateBoundsCalc . Wait ( ) ;
2020-04-18 18:42:59 -04:00
UpdateBounds ( ) ;
}
2021-06-10 18:37:57 -04:00
GetDynamicMesh ( ) - > PostRealtimeUpdate ( ) ;
2020-04-18 18:42:59 -04:00
}
else
{
2020-11-05 19:18:40 -04:00
ResetProxy ( ) ;
2020-04-18 18:42:59 -04:00
}
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : FastNotifyUVsUpdated ( )
2020-04-18 18:42:59 -04:00
{
2020-04-20 16:42:20 -04:00
FastNotifyVertexAttributesUpdated ( EMeshRenderAttributeFlags : : VertexUVs ) ;
2020-04-18 18:42:59 -04:00
}
2023-06-15 22:53:04 -04:00
void UDynamicMeshComponent : : NotifyMeshVertexAttributesModified ( bool bPositions , bool bNormals , bool bUVs , bool bColors )
{
EMeshRenderAttributeFlags Flags = EMeshRenderAttributeFlags : : None ;
if ( bPositions )
{
Flags | = EMeshRenderAttributeFlags : : Positions ;
}
if ( bNormals )
{
Flags | = EMeshRenderAttributeFlags : : VertexNormals ;
}
if ( bUVs )
{
Flags | = EMeshRenderAttributeFlags : : VertexUVs ;
}
if ( bColors )
{
Flags | = EMeshRenderAttributeFlags : : VertexColors ;
}
if ( Flags = = EMeshRenderAttributeFlags : : None )
{
return ;
}
FastNotifyVertexAttributesUpdated ( Flags ) ;
}
2020-01-27 20:11:15 -05:00
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : FastNotifySecondaryTrianglesChanged ( )
2020-01-27 20:11:15 -05:00
{
2020-12-03 17:40:22 -04:00
// should not be using fast paths if we have to run mesh postprocessor
if ( ensure ( ! RenderMeshPostProcessor ) = = false )
2020-11-05 19:18:40 -04:00
{
2021-06-10 18:37:57 -04:00
RenderMeshPostProcessor - > ProcessMesh ( * GetMesh ( ) , * RenderMesh ) ;
2020-12-03 17:40:22 -04:00
ResetProxy ( ) ;
return ;
2020-11-05 19:18:40 -04:00
}
2021-06-12 14:30:22 -04:00
FDynamicMeshSceneProxy * Proxy = GetCurrentSceneProxy ( ) ;
2024-03-20 11:50:05 -04:00
if ( Proxy & & AllowFastUpdate ( ) )
2020-01-27 20:11:15 -05:00
{
GetCurrentSceneProxy ( ) - > FastUpdateAllIndexBuffers ( ) ;
2021-06-10 18:37:57 -04:00
GetDynamicMesh ( ) - > PostRealtimeUpdate ( ) ;
2020-01-27 20:11:15 -05:00
}
else
{
2020-11-05 19:18:40 -04:00
ResetProxy ( ) ;
2020-01-27 20:11:15 -05:00
}
}
2019-10-01 20:41:42 -04:00
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : FastNotifyTriangleVerticesUpdated ( const TArray < int32 > & Triangles , EMeshRenderAttributeFlags UpdatedAttributes )
2020-04-18 18:42:59 -04:00
{
2020-12-03 17:40:22 -04:00
// should not be using fast paths if we have to run mesh postprocessor
if ( ensure ( ! RenderMeshPostProcessor ) = = false )
2020-04-18 18:42:59 -04:00
{
2021-06-10 18:37:57 -04:00
RenderMeshPostProcessor - > ProcessMesh ( * GetMesh ( ) , * RenderMesh ) ;
2020-12-03 17:40:22 -04:00
ResetProxy ( ) ;
return ;
2020-11-05 19:18:40 -04:00
}
2021-01-24 16:05:21 -04:00
bool bUpdateSecondarySort = ( SecondaryTriFilterFunc ) & &
( ( UpdatedAttributes & EMeshRenderAttributeFlags : : SecondaryIndexBuffers ) ! = EMeshRenderAttributeFlags : : None ) ;
2021-06-12 14:30:22 -04:00
FDynamicMeshSceneProxy * Proxy = GetCurrentSceneProxy ( ) ;
2024-03-20 11:50:05 -04:00
if ( ! Proxy | | ! AllowFastUpdate ( ) )
2020-11-05 19:18:40 -04:00
{
ResetProxy ( ) ;
2020-04-18 18:42:59 -04:00
}
else if ( ! Decomposition )
{
FastNotifyVertexAttributesUpdated ( UpdatedAttributes ) ;
2021-01-24 16:05:21 -04:00
if ( bUpdateSecondarySort )
{
Proxy - > FastUpdateAllIndexBuffers ( ) ;
}
2021-06-10 18:37:57 -04:00
GetDynamicMesh ( ) - > PostRealtimeUpdate ( ) ;
2020-04-18 18:42:59 -04:00
}
else
{
2021-01-28 01:46:53 -04:00
// compute list of sets to update
2020-04-18 18:42:59 -04:00
TArray < int32 > UpdatedSets ;
{
2021-01-28 01:46:53 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastVertexUpdate_FindSets ) ;
for ( int32 tid : Triangles )
{
int32 SetID = Decomposition - > GetGroupForTriangle ( tid ) ;
UpdatedSets . AddUnique ( SetID ) ;
}
2020-04-18 18:42:59 -04:00
}
bool bPositions = ( UpdatedAttributes & EMeshRenderAttributeFlags : : Positions ) ! = EMeshRenderAttributeFlags : : None ;
2021-01-28 01:46:53 -04:00
// calculate bounds while we are updating vertices
TFuture < void > UpdateBoundsCalc ;
if ( bPositions )
{
2021-06-12 14:30:22 -04:00
UpdateBoundsCalc = Async ( DynamicMeshComponentAsyncExecTarget , [ this ] ( )
2021-01-28 01:46:53 -04:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastVertexUpdate_AsyncBoundsUpdate ) ;
2021-06-10 18:37:57 -04:00
UpdateLocalBounds ( ) ;
2021-01-28 01:46:53 -04:00
} ) ;
}
// update the render buffers
{
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastVertexUpdate_ApplyUpdate ) ;
Proxy - > FastUpdateVertices ( UpdatedSets , bPositions ,
( UpdatedAttributes & EMeshRenderAttributeFlags : : VertexNormals ) ! = EMeshRenderAttributeFlags : : None ,
( UpdatedAttributes & EMeshRenderAttributeFlags : : VertexColors ) ! = EMeshRenderAttributeFlags : : None ,
( UpdatedAttributes & EMeshRenderAttributeFlags : : VertexUVs ) ! = EMeshRenderAttributeFlags : : None ) ;
}
2020-04-18 18:42:59 -04:00
2021-01-24 16:05:21 -04:00
if ( bUpdateSecondarySort )
{
Proxy - > FastUpdateIndexBuffers ( UpdatedSets ) ;
}
2020-04-18 18:42:59 -04:00
if ( bPositions )
{
2021-01-28 01:46:53 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastVertexUpdate_FinalPositionsUpdate ) ;
2020-04-18 18:42:59 -04:00
MarkRenderTransformDirty ( ) ;
2021-01-28 01:46:53 -04:00
UpdateBoundsCalc . Wait ( ) ;
2020-04-18 18:42:59 -04:00
UpdateBounds ( ) ;
}
2021-06-10 18:37:57 -04:00
GetDynamicMesh ( ) - > PostRealtimeUpdate ( ) ;
2020-04-18 18:42:59 -04:00
}
}
2021-01-28 01:46:53 -04:00
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : FastNotifyTriangleVerticesUpdated ( const TSet < int32 > & Triangles , EMeshRenderAttributeFlags UpdatedAttributes )
2020-04-18 18:42:59 -04:00
{
2020-12-03 17:40:22 -04:00
// should not be using fast paths if we have to run mesh postprocessor
if ( ensure ( ! RenderMeshPostProcessor ) = = false )
2020-04-18 18:42:59 -04:00
{
2021-06-10 18:37:57 -04:00
RenderMeshPostProcessor - > ProcessMesh ( * GetMesh ( ) , * RenderMesh ) ;
2020-12-03 17:40:22 -04:00
ResetProxy ( ) ;
return ;
2020-11-05 19:18:40 -04:00
}
2021-01-24 16:05:21 -04:00
bool bUpdateSecondarySort = ( SecondaryTriFilterFunc ) & &
( ( UpdatedAttributes & EMeshRenderAttributeFlags : : SecondaryIndexBuffers ) ! = EMeshRenderAttributeFlags : : None ) ;
2020-11-05 19:18:40 -04:00
2021-06-12 14:30:22 -04:00
FDynamicMeshSceneProxy * Proxy = GetCurrentSceneProxy ( ) ;
2024-03-20 11:50:05 -04:00
if ( ! Proxy | | ! AllowFastUpdate ( ) )
2020-11-05 19:18:40 -04:00
{
ResetProxy ( ) ;
2020-04-18 18:42:59 -04:00
}
else if ( ! Decomposition )
{
FastNotifyVertexAttributesUpdated ( UpdatedAttributes ) ;
2021-01-24 16:05:21 -04:00
if ( bUpdateSecondarySort )
{
Proxy - > FastUpdateAllIndexBuffers ( ) ;
}
2021-06-10 18:37:57 -04:00
GetDynamicMesh ( ) - > PostRealtimeUpdate ( ) ;
2020-04-18 18:42:59 -04:00
}
else
{
2021-01-28 01:46:53 -04:00
// compute list of sets to update
2020-04-18 18:42:59 -04:00
TArray < int32 > UpdatedSets ;
{
2021-01-28 01:46:53 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastVertexUpdate_FindSets ) ;
for ( int32 tid : Triangles )
{
int32 SetID = Decomposition - > GetGroupForTriangle ( tid ) ;
UpdatedSets . AddUnique ( SetID ) ;
}
2020-04-18 18:42:59 -04:00
}
bool bPositions = ( UpdatedAttributes & EMeshRenderAttributeFlags : : Positions ) ! = EMeshRenderAttributeFlags : : None ;
// calculate bounds while we are updating vertices
TFuture < void > UpdateBoundsCalc ;
if ( bPositions )
{
2021-06-12 14:30:22 -04:00
UpdateBoundsCalc = Async ( DynamicMeshComponentAsyncExecTarget , [ this ] ( )
2020-04-18 18:42:59 -04:00
{
2021-01-28 01:46:53 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastVertexUpdate_AsyncBoundsUpdate ) ;
2021-06-10 18:37:57 -04:00
UpdateLocalBounds ( ) ;
2020-04-18 18:42:59 -04:00
} ) ;
}
2021-01-28 01:46:53 -04:00
// update the render buffers
2021-01-24 16:05:21 -04:00
{
2021-01-28 01:46:53 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastVertexUpdate_ApplyUpdate ) ;
Proxy - > FastUpdateVertices ( UpdatedSets , bPositions ,
( UpdatedAttributes & EMeshRenderAttributeFlags : : VertexNormals ) ! = EMeshRenderAttributeFlags : : None ,
( UpdatedAttributes & EMeshRenderAttributeFlags : : VertexColors ) ! = EMeshRenderAttributeFlags : : None ,
( UpdatedAttributes & EMeshRenderAttributeFlags : : VertexUVs ) ! = EMeshRenderAttributeFlags : : None ) ;
2021-01-24 16:05:21 -04:00
}
2021-01-28 01:46:53 -04:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastVertexUpdate_UpdateIndexBuffers ) ;
if ( bUpdateSecondarySort )
{
Proxy - > FastUpdateIndexBuffers ( UpdatedSets ) ;
}
}
// finish up, have to wait for background bounds recalculation here
2020-04-18 18:42:59 -04:00
if ( bPositions )
{
2021-01-28 01:46:53 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastVertexUpdate_FinalPositionsUpdate ) ;
2020-04-18 18:42:59 -04:00
MarkRenderTransformDirty ( ) ;
UpdateBoundsCalc . Wait ( ) ;
UpdateBounds ( ) ;
}
2021-06-10 18:37:57 -04:00
GetDynamicMesh ( ) - > PostRealtimeUpdate ( ) ;
2020-04-18 18:42:59 -04:00
}
}
2021-01-28 01:46:53 -04:00
/**
* Compute the combined bounding - box of the Triangles array in parallel , by computing
* partial boxes for subsets of this array , and then combining those boxes .
* TODO : this should move to a pulbic utility function , and possibly the block - based ParallelFor
* should be refactored out into something more general , as this pattern is useful in many places . . .
*/
static FAxisAlignedBox3d ParallelComputeROIBounds ( const FDynamicMesh3 & Mesh , const TArray < int32 > & Triangles )
{
FAxisAlignedBox3d FinalBounds = FAxisAlignedBox3d : : Empty ( ) ;
FCriticalSection FinalBoundsLock ;
int32 N = Triangles . Num ( ) ;
constexpr int32 BlockSize = 4096 ;
int32 Blocks = ( N / BlockSize ) + 1 ;
ParallelFor ( Blocks , [ & ] ( int bi )
{
FAxisAlignedBox3d BlockBounds = FAxisAlignedBox3d : : Empty ( ) ;
for ( int32 k = 0 ; k < BlockSize ; + + k )
{
int32 i = bi * BlockSize + k ;
if ( i < N )
{
int32 tid = Triangles [ i ] ;
const FIndex3i & TriV = Mesh . GetTriangleRef ( tid ) ;
BlockBounds . Contain ( Mesh . GetVertexRef ( TriV . A ) ) ;
BlockBounds . Contain ( Mesh . GetVertexRef ( TriV . B ) ) ;
BlockBounds . Contain ( Mesh . GetVertexRef ( TriV . C ) ) ;
}
}
FinalBoundsLock . Lock ( ) ;
FinalBounds . Contain ( BlockBounds ) ;
FinalBoundsLock . Unlock ( ) ;
} ) ;
return FinalBounds ;
}
2021-06-12 14:30:22 -04:00
TFuture < bool > UDynamicMeshComponent : : FastNotifyTriangleVerticesUpdated_TryPrecompute (
2021-01-28 01:46:53 -04:00
const TArray < int32 > & Triangles ,
TArray < int32 > & UpdateSetsOut ,
FAxisAlignedBox3d & BoundsOut )
{
2024-03-20 11:50:05 -04:00
if ( ( ! ! RenderMeshPostProcessor ) | | ( GetCurrentSceneProxy ( ) = = nullptr ) | | ( ! Decomposition ) | | ! AllowFastUpdate ( ) )
2021-01-28 01:46:53 -04:00
{
// is there a simpler way to do this? cannot seem to just make a TFuture<bool>...
2021-06-12 14:30:22 -04:00
return Async ( DynamicMeshComponentAsyncExecTarget , [ ] ( ) { return false ; } ) ;
2021-01-28 01:46:53 -04:00
}
2021-06-12 14:30:22 -04:00
return Async ( DynamicMeshComponentAsyncExecTarget , [ this , & Triangles , & UpdateSetsOut , & BoundsOut ] ( )
2021-01-28 01:46:53 -04:00
{
2021-06-12 14:30:22 -04:00
TFuture < void > ComputeBounds = Async ( DynamicMeshComponentAsyncExecTarget , [ this , & BoundsOut , & Triangles ] ( )
2021-01-28 01:46:53 -04:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastVertexUpdatePrecomp_CalcBounds ) ;
2021-06-10 18:37:57 -04:00
BoundsOut = ParallelComputeROIBounds ( * GetMesh ( ) , Triangles ) ;
2021-01-28 01:46:53 -04:00
} ) ;
2021-06-12 14:30:22 -04:00
TFuture < void > ComputeSets = Async ( DynamicMeshComponentAsyncExecTarget , [ this , & UpdateSetsOut , & Triangles ] ( )
2021-01-28 01:46:53 -04:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastVertexUpdatePrecomp_FindSets ) ;
2021-01-28 20:32:26 -04:00
int32 NumBuffers = Decomposition - > Num ( ) ;
TArray < std : : atomic < bool > > BufferFlags ;
BufferFlags . SetNum ( NumBuffers ) ;
for ( int32 k = 0 ; k < NumBuffers ; + + k )
2021-01-28 01:46:53 -04:00
{
2021-01-28 20:32:26 -04:00
BufferFlags [ k ] = false ;
2021-01-28 01:46:53 -04:00
}
2021-01-28 20:32:26 -04:00
ParallelFor ( Triangles . Num ( ) , [ & ] ( int32 k )
{
int32 SetID = Decomposition - > GetGroupForTriangle ( Triangles [ k ] ) ;
BufferFlags [ SetID ] = true ;
} ) ;
UpdateSetsOut . Reset ( ) ;
for ( int32 k = 0 ; k < NumBuffers ; + + k )
{
if ( BufferFlags [ k ] )
{
UpdateSetsOut . Add ( k ) ;
}
}
2021-01-28 01:46:53 -04:00
} ) ;
ComputeSets . Wait ( ) ;
ComputeBounds . Wait ( ) ;
2021-06-10 18:37:57 -04:00
2021-01-28 01:46:53 -04:00
return true ;
} ) ;
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : FastNotifyTriangleVerticesUpdated_ApplyPrecompute (
2021-01-28 01:46:53 -04:00
const TArray < int32 > & Triangles ,
EMeshRenderAttributeFlags UpdatedAttributes ,
TFuture < bool > & Precompute ,
const TArray < int32 > & UpdateSets ,
const FAxisAlignedBox3d & UpdateSetBounds )
{
Precompute . Wait ( ) ;
bool bPrecomputeOK = Precompute . Get ( ) ;
2024-03-20 11:50:05 -04:00
if ( bPrecomputeOK = = false | | GetCurrentSceneProxy ( ) = = nullptr | | ! AllowFastUpdate ( ) )
2021-01-28 01:46:53 -04:00
{
FastNotifyTriangleVerticesUpdated ( Triangles , UpdatedAttributes ) ;
return ;
}
2021-06-12 14:30:22 -04:00
FDynamicMeshSceneProxy * Proxy = GetCurrentSceneProxy ( ) ;
2021-01-28 01:46:53 -04:00
bool bPositions = ( UpdatedAttributes & EMeshRenderAttributeFlags : : Positions ) ! = EMeshRenderAttributeFlags : : None ;
bool bUpdateSecondarySort = ( SecondaryTriFilterFunc ) & &
( ( UpdatedAttributes & EMeshRenderAttributeFlags : : SecondaryIndexBuffers ) ! = EMeshRenderAttributeFlags : : None ) ;
{
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastVertexUpdate_ApplyUpdate ) ;
Proxy - > FastUpdateVertices ( UpdateSets , bPositions ,
( UpdatedAttributes & EMeshRenderAttributeFlags : : VertexNormals ) ! = EMeshRenderAttributeFlags : : None ,
( UpdatedAttributes & EMeshRenderAttributeFlags : : VertexColors ) ! = EMeshRenderAttributeFlags : : None ,
( UpdatedAttributes & EMeshRenderAttributeFlags : : VertexUVs ) ! = EMeshRenderAttributeFlags : : None ) ;
}
{
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastVertexUpdate_UpdateIndexBuffers ) ;
if ( bUpdateSecondarySort )
{
Proxy - > FastUpdateIndexBuffers ( UpdateSets ) ;
}
}
if ( bPositions )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( SimpleDynamicMeshComponent_FastVertexUpdate_FinalPositionsUpdate ) ;
MarkRenderTransformDirty ( ) ;
LocalBounds . Contain ( UpdateSetBounds ) ;
UpdateBounds ( ) ;
}
2021-06-10 18:37:57 -04:00
GetDynamicMesh ( ) - > PostRealtimeUpdate ( ) ;
2021-01-28 01:46:53 -04:00
}
2019-10-01 20:41:42 -04:00
2021-06-12 14:30:22 -04:00
FPrimitiveSceneProxy * UDynamicMeshComponent : : CreateSceneProxy ( )
2019-10-01 20:41:42 -04:00
{
2020-12-03 17:40:22 -04:00
// if this is not always the case, we have made incorrect assumptions
ensure ( GetCurrentSceneProxy ( ) = = nullptr ) ;
2019-12-19 18:07:47 -05:00
2021-06-12 14:30:22 -04:00
FDynamicMeshSceneProxy * NewProxy = nullptr ;
2021-06-10 18:37:57 -04:00
if ( GetMesh ( ) - > TriangleCount ( ) > 0 )
2019-10-01 20:41:42 -04:00
{
2021-06-12 14:30:22 -04:00
NewProxy = new FDynamicMeshSceneProxy ( this ) ;
2019-10-01 20:41:42 -04:00
if ( TriangleColorFunc )
{
2024-04-16 14:28:43 -04:00
NewProxy - > MeshRenderBufferSetConverter . bUsePerTriangleColor = true ;
NewProxy - > MeshRenderBufferSetConverter . PerTriangleColorFunc = [ this ] ( const FDynamicMesh3 * MeshIn , int TriangleID ) { return GetTriangleColor ( MeshIn , TriangleID ) ; } ;
2019-10-01 20:41:42 -04:00
}
2022-06-15 16:49:13 -04:00
else if ( GetColorOverrideMode ( ) = = EDynamicMeshComponentColorOverrideMode : : Polygroups )
{
2024-04-16 14:28:43 -04:00
NewProxy - > MeshRenderBufferSetConverter . bUsePerTriangleColor = true ;
NewProxy - > MeshRenderBufferSetConverter . PerTriangleColorFunc = [ this ] ( const FDynamicMesh3 * MeshIn , int TriangleID ) { return GetGroupColor ( MeshIn , TriangleID ) ; } ;
2022-06-15 16:49:13 -04:00
}
2019-10-01 20:41:42 -04:00
2023-05-17 11:12:48 -04:00
if ( HasVertexColorRemappingFunction ( ) )
{
2024-04-16 14:28:43 -04:00
NewProxy - > MeshRenderBufferSetConverter . bApplyVertexColorRemapping = true ;
NewProxy - > MeshRenderBufferSetConverter . VertexColorRemappingFunc = [ this ] ( FVector4f & Color ) { RemapVertexColor ( Color ) ; } ;
2023-05-17 11:12:48 -04:00
}
2019-12-19 18:07:47 -05:00
if ( SecondaryTriFilterFunc )
{
2024-04-16 14:28:43 -04:00
NewProxy - > MeshRenderBufferSetConverter . bUseSecondaryTriBuffers = true ;
NewProxy - > MeshRenderBufferSetConverter . SecondaryTriFilterFunc = [ this ] ( const FDynamicMesh3 * MeshIn , int32 TriangleID )
2019-12-19 18:07:47 -05:00
{
return ( SecondaryTriFilterFunc ) ? SecondaryTriFilterFunc ( MeshIn , TriangleID ) : false ;
} ;
}
2020-04-18 18:42:59 -04:00
if ( Decomposition )
{
NewProxy - > InitializeFromDecomposition ( Decomposition ) ;
}
else
{
NewProxy - > Initialize ( ) ;
}
2022-02-14 12:20:58 -05:00
2024-03-27 14:27:24 -04:00
// set new distance field
if ( DistanceFieldMode ! = EDynamicMeshComponentDistanceFieldMode : : NoDistanceField )
{
DistanceFieldLock . Lock ( ) ;
if ( CurrentDistanceField . IsValid ( ) )
{
NewProxy - > SetNewDistanceField ( CurrentDistanceField , true ) ;
}
DistanceFieldLock . Unlock ( ) ;
}
2022-02-14 12:20:58 -05:00
NewProxy - > SetVerifyUsedMaterials ( bProxyVerifyUsedMaterials ) ;
2019-10-01 20:41:42 -04:00
}
2020-12-03 17:40:22 -04:00
bProxyValid = true ;
2019-12-19 18:07:47 -05:00
return NewProxy ;
2019-10-01 20:41:42 -04:00
}
2019-12-19 18:07:47 -05:00
2020-12-03 17:40:22 -04:00
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : NotifyMaterialSetUpdated ( )
2019-10-01 20:41:42 -04:00
{
2019-12-19 18:07:47 -05:00
if ( GetCurrentSceneProxy ( ) ! = nullptr )
{
GetCurrentSceneProxy ( ) - > UpdatedReferencedMaterials ( ) ;
}
2019-10-01 20:41:42 -04:00
}
2024-03-27 14:27:24 -04:00
void UDynamicMeshComponent : : OnNewDistanceFieldMode ( )
{
UpdateDistanceField ( ) ;
}
void UDynamicMeshComponent : : UpdateDistanceField ( )
{
if ( DistanceFieldMode = = EDynamicMeshComponentDistanceFieldMode : : NoDistanceField )
{
FScopeLock Lock ( & DistanceFieldLock ) ;
CurrentDistanceField = TSharedPtr < FDistanceFieldVolumeData > ( ) ;
if ( GetCurrentSceneProxy ( ) ! = nullptr )
{
GetCurrentSceneProxy ( ) - > SetNewDistanceField ( CurrentDistanceField , false ) ;
}
return ;
}
2024-03-28 11:32:35 -04:00
// For safety, run the distance field compute on a (geometry-only) copy of the mesh
FDynamicMesh3 GeoOnlyCopy ;
// Compute whether the mesh uses mainly two-sided materials before, as this is the only info the distance field compute needs from the mesh attributes
bool bMostlyTwoSided = false ;
ProcessMesh ( [ & ] ( const FDynamicMesh3 & ReadMesh )
2024-03-27 14:27:24 -04:00
{
if ( ReadMesh . Attributes ( ) & & ReadMesh . Attributes ( ) - > GetMaterialID ( ) )
{
TArray < bool > MatIsTwoSided ;
MatIsTwoSided . SetNumUninitialized ( BaseMaterials . Num ( ) ) ;
for ( int32 Idx = 0 ; Idx < BaseMaterials . Num ( ) ; + + Idx )
{
MatIsTwoSided [ Idx ] = BaseMaterials [ Idx ] ? BaseMaterials [ Idx ] - > IsTwoSided ( ) : false ;
}
const FDynamicMeshMaterialAttribute * Materials = ReadMesh . Attributes ( ) - > GetMaterialID ( ) ;
int32 TwoSidedTriCount = 0 ;
for ( int32 TID : ReadMesh . TriangleIndicesItr ( ) )
{
int32 MID = Materials - > GetValue ( TID ) ;
TwoSidedTriCount + = MatIsTwoSided . IsValidIndex ( MID ) ? ( int32 ) MatIsTwoSided [ MID ] : 0 ;
}
bMostlyTwoSided = TwoSidedTriCount * 2 > = ReadMesh . TriangleCount ( ) ;
}
2024-03-28 11:32:35 -04:00
GeoOnlyCopy . Copy ( ReadMesh , false , false , false , false ) ;
2024-03-27 14:27:24 -04:00
} ) ;
2024-03-28 11:32:35 -04:00
DistanceFieldComputeQueue . LaunchJob ( TEXT ( " DynamicMeshComponentDistanceField " ) ,
[ this , MovedGeoOnlyCopy = MoveTemp ( GeoOnlyCopy ) , bMostlyTwoSided ] ( FProgressCancel & Progress )
{
return ComputeNewDistanceField_TaskFunction ( Progress , MovedGeoOnlyCopy , bMostlyTwoSided ) ;
} ) ;
}
TUniquePtr < FDistanceFieldVolumeData > UDynamicMeshComponent : : ComputeNewDistanceField_TaskFunction ( FProgressCancel & Progress , const FDynamicMesh3 & Mesh , bool bMostlyTwoSided )
{
// todo: consider making the number of concurrent distance field computes configurable
constexpr int32 MaxConcurrentComputes = 3 ;
static FSemaphore ComputesCountSemaphore ( MaxConcurrentComputes , MaxConcurrentComputes ) ;
ComputesCountSemaphore . Acquire ( ) ;
if ( Progress . Cancelled ( ) )
{
ComputesCountSemaphore . Release ( ) ;
return nullptr ;
}
TUniquePtr < FDistanceFieldVolumeData > NewDistanceField ;
float DistanceFieldResolutionScale = 1.0f ;
NewDistanceField =
FDynamicMeshSceneProxy : : ComputeDistanceFieldForMesh ( Mesh , Progress , DistanceFieldResolutionScale , bMostlyTwoSided ) ;
ComputesCountSemaphore . Release ( ) ;
2024-03-27 14:27:24 -04:00
return NewDistanceField ;
}
void UDynamicMeshComponent : : OnNewDistanceFieldData_Async ( TUniquePtr < FDistanceFieldVolumeData > NewData )
{
// WARNING: this function will be called from TAsyncComponentDataComputeQueue background tasks
TSharedPtr < FDistanceFieldVolumeData > NewDistanceField ( NewData . Release ( ) ) ;
DistanceFieldLock . Lock ( ) ;
CurrentDistanceField = NewDistanceField ;
if ( GetCurrentSceneProxy ( ) ! = nullptr )
{
2024-03-28 11:32:35 -04:00
// mark render state dirty on the game thread to ensure it updates at a safe time (e.g., cannot update when bPostTickComponentUpdate == true)
AsyncTask (
ENamedThreads : : GameThread ,
[ this ] ( )
{
// the new distance field will be set when the scene proxy is re-created
MarkRenderStateDirty ( ) ;
}
) ;
2024-03-27 14:27:24 -04:00
}
DistanceFieldLock . Unlock ( ) ;
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : SetTriangleColorFunction (
2021-06-10 18:37:57 -04:00
TUniqueFunction < FColor ( const FDynamicMesh3 * , int ) > TriangleColorFuncIn ,
EDynamicMeshComponentRenderUpdateMode UpdateMode )
{
TriangleColorFunc = MoveTemp ( TriangleColorFuncIn ) ;
if ( UpdateMode = = EDynamicMeshComponentRenderUpdateMode : : FastUpdate )
{
FastNotifyColorsUpdated ( ) ;
}
else if ( UpdateMode = = EDynamicMeshComponentRenderUpdateMode : : FullUpdate )
{
NotifyMeshUpdated ( ) ;
}
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : ClearTriangleColorFunction ( EDynamicMeshComponentRenderUpdateMode UpdateMode )
2021-06-10 18:37:57 -04:00
{
if ( TriangleColorFunc )
{
TriangleColorFunc = nullptr ;
if ( UpdateMode = = EDynamicMeshComponentRenderUpdateMode : : FastUpdate )
{
FastNotifyColorsUpdated ( ) ;
}
else if ( UpdateMode = = EDynamicMeshComponentRenderUpdateMode : : FullUpdate )
{
NotifyMeshUpdated ( ) ;
}
}
}
2021-06-12 14:30:22 -04:00
bool UDynamicMeshComponent : : HasTriangleColorFunction ( )
2021-06-10 18:37:57 -04:00
{
return ! ! TriangleColorFunc ;
}
2019-12-19 18:07:47 -05:00
2023-05-17 11:12:48 -04:00
void UDynamicMeshComponent : : SetVertexColorRemappingFunction (
TUniqueFunction < void ( FVector4f & ) > ColorMapFuncIn ,
EDynamicMeshComponentRenderUpdateMode UpdateMode )
{
VertexColorMappingFunc = MoveTemp ( ColorMapFuncIn ) ;
if ( UpdateMode = = EDynamicMeshComponentRenderUpdateMode : : FastUpdate )
{
FastNotifyColorsUpdated ( ) ;
}
else if ( UpdateMode = = EDynamicMeshComponentRenderUpdateMode : : FullUpdate )
{
NotifyMeshUpdated ( ) ;
}
}
void UDynamicMeshComponent : : ClearVertexColorRemappingFunction ( EDynamicMeshComponentRenderUpdateMode UpdateMode )
{
if ( VertexColorMappingFunc )
{
VertexColorMappingFunc = nullptr ;
if ( UpdateMode = = EDynamicMeshComponentRenderUpdateMode : : FastUpdate )
{
FastNotifyColorsUpdated ( ) ;
}
else if ( UpdateMode = = EDynamicMeshComponentRenderUpdateMode : : FullUpdate )
{
NotifyMeshUpdated ( ) ;
}
}
}
bool UDynamicMeshComponent : : HasVertexColorRemappingFunction ( )
{
return ! ! VertexColorMappingFunc ;
}
void UDynamicMeshComponent : : RemapVertexColor ( FVector4f & VertexColorInOut )
{
if ( VertexColorMappingFunc )
{
VertexColorMappingFunc ( VertexColorInOut ) ;
}
}
2019-12-19 18:07:47 -05:00
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : EnableSecondaryTriangleBuffers ( TUniqueFunction < bool ( const FDynamicMesh3 * , int32 ) > SecondaryTriFilterFuncIn )
2019-12-19 18:07:47 -05:00
{
SecondaryTriFilterFunc = MoveTemp ( SecondaryTriFilterFuncIn ) ;
NotifyMeshUpdated ( ) ;
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : DisableSecondaryTriangleBuffers ( )
2019-12-19 18:07:47 -05:00
{
SecondaryTriFilterFunc = nullptr ;
NotifyMeshUpdated ( ) ;
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : SetExternalDecomposition ( TUniquePtr < FMeshRenderDecomposition > DecompositionIn )
2020-04-18 18:42:59 -04:00
{
2022-08-24 16:13:55 -04:00
ensure ( DecompositionIn - > Num ( ) > 0 ) ;
2020-04-18 18:42:59 -04:00
Decomposition = MoveTemp ( DecompositionIn ) ;
NotifyMeshUpdated ( ) ;
}
2019-12-19 18:07:47 -05:00
2021-06-12 14:30:22 -04:00
FColor UDynamicMeshComponent : : GetTriangleColor ( const FDynamicMesh3 * MeshIn , int TriangleID )
2019-10-01 20:41:42 -04:00
{
if ( TriangleColorFunc )
{
2019-11-09 21:49:15 -05:00
return TriangleColorFunc ( MeshIn , TriangleID ) ;
2019-10-01 20:41:42 -04:00
}
else
{
return ( TriangleID % 2 = = 0 ) ? FColor : : Red : FColor : : White ;
}
}
2022-06-15 16:49:13 -04:00
FColor UDynamicMeshComponent : : GetGroupColor ( const FDynamicMesh3 * Mesh , int TriangleID ) const
{
int32 GroupID = Mesh - > HasTriangleGroups ( ) ? Mesh - > GetTriangleGroup ( TriangleID ) : 0 ;
return UE : : Geometry : : LinearColors : : SelectFColor ( GroupID ) ;
}
2019-10-01 20:41:42 -04:00
2021-06-12 14:30:22 -04:00
FBoxSphereBounds UDynamicMeshComponent : : CalcBounds ( const FTransform & LocalToWorld ) const
2019-10-01 20:41:42 -04:00
{
2019-12-19 18:07:47 -05:00
// can get a tighter box by calculating in world space, but we care more about performance
FBox LocalBoundingBox = ( FBox ) LocalBounds ;
FBoxSphereBounds Ret ( LocalBoundingBox . TransformBy ( LocalToWorld ) ) ;
Ret . BoxExtent * = BoundsScale ;
Ret . SphereRadius * = BoundsScale ;
return Ret ;
2019-10-01 20:41:42 -04:00
}
2021-06-10 18:37:57 -04:00
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : SetInvalidateProxyOnChangeEnabled ( bool bEnabled )
2019-10-01 20:41:42 -04:00
{
2021-06-10 18:37:57 -04:00
bInvalidateProxyOnChange = bEnabled ;
2019-10-01 20:41:42 -04:00
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : ApplyChange ( const FMeshVertexChange * Change , bool bRevert )
2021-06-10 18:37:57 -04:00
{
// will fire UDynamicMesh::MeshChangedEvent, which will call OnMeshObjectChanged() below to invalidate proxy, fire change events, etc
MeshObject - > ApplyChange ( Change , bRevert ) ;
}
2019-10-01 20:41:42 -04:00
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : ApplyChange ( const FMeshChange * Change , bool bRevert )
2019-10-01 20:41:42 -04:00
{
2021-06-10 18:37:57 -04:00
// will fire UDynamicMesh::MeshChangedEvent, which will call OnMeshObjectChanged() below to invalidate proxy, fire change events, etc
MeshObject - > ApplyChange ( Change , bRevert ) ;
2019-12-19 18:07:47 -05:00
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : ApplyChange ( const FMeshReplacementChange * Change , bool bRevert )
2019-12-19 18:07:47 -05:00
{
2021-06-10 18:37:57 -04:00
// will fire UDynamicMesh::MeshChangedEvent, which will call OnMeshObjectChanged() below to invalidate proxy, fire change events, etc
MeshObject - > ApplyChange ( Change , bRevert ) ;
}
2019-12-19 18:07:47 -05:00
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : OnMeshObjectChanged ( UDynamicMesh * ChangedMeshObject , FDynamicMeshChangeInfo ChangeInfo )
2021-06-10 18:37:57 -04:00
{
bool bIsFChange = (
ChangeInfo . Type = = EDynamicMeshChangeType : : MeshChange
| | ChangeInfo . Type = = EDynamicMeshChangeType : : MeshVertexChange
| | ChangeInfo . Type = = EDynamicMeshChangeType : : MeshReplacementChange ) ;
if ( bIsFChange )
{
if ( bInvalidateProxyOnChange )
{
NotifyMeshUpdated ( ) ;
}
OnMeshChanged . Broadcast ( ) ;
if ( ChangeInfo . Type = = EDynamicMeshChangeType : : MeshVertexChange )
{
OnMeshVerticesChanged . Broadcast ( this , ChangeInfo . VertexChange , ChangeInfo . bIsRevertChange ) ;
}
}
else
2020-04-18 18:42:59 -04:00
{
2022-06-20 22:42:51 -04:00
if ( ChangeInfo . Type = = EDynamicMeshChangeType : : DeformationEdit )
{
// if ChangeType is a vertex deformation, we can do a fast-update of the vertex buffers
// without fully rebuilding the SceneProxy
EMeshRenderAttributeFlags UpdateFlags = UELocal : : ConvertChangeFlagsToUpdateFlags ( ChangeInfo . Flags ) ;
FastNotifyVertexAttributesUpdated ( UpdateFlags ) ;
}
else
{
NotifyMeshUpdated ( ) ;
}
2021-06-10 18:37:57 -04:00
OnMeshChanged . Broadcast ( ) ;
2020-04-18 18:42:59 -04:00
}
2021-06-20 18:12:30 -04:00
2024-03-04 18:02:09 -05:00
InternalOnMeshUpdated ( ) ;
2021-06-10 18:37:57 -04:00
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : SetDynamicMesh ( UDynamicMesh * NewMesh )
2021-06-10 18:37:57 -04:00
{
if ( ensure ( NewMesh ) = = false )
{
return ;
}
if ( ensure ( MeshObject ) )
{
MeshObject - > OnMeshChanged ( ) . Remove ( MeshObjectChangedHandle ) ;
}
2023-06-15 22:53:04 -04:00
// set Outer of NewMesh to be this Component, ie transfer ownership. This is done via "renaming", which is
// a bit odd, so the flags prevent some standard "renaming" behaviors from happening
2024-06-17 11:55:02 -04:00
NewMesh - > Rename ( nullptr , this , REN_DontCreateRedirectors ) ;
2021-06-10 18:37:57 -04:00
MeshObject = NewMesh ;
2021-06-12 14:30:22 -04:00
MeshObjectChangedHandle = MeshObject - > OnMeshChanged ( ) . AddUObject ( this , & UDynamicMeshComponent : : OnMeshObjectChanged ) ;
2021-06-10 18:37:57 -04:00
NotifyMeshUpdated ( ) ;
2019-12-19 18:07:47 -05:00
OnMeshChanged . Broadcast ( ) ;
2021-06-20 18:12:30 -04:00
2024-03-04 18:02:09 -05:00
InternalOnMeshUpdated ( ) ;
2019-12-19 18:07:47 -05:00
}
2021-06-10 18:37:57 -04:00
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : OnChildAttached ( USceneComponent * ChildComponent )
2021-06-10 18:37:57 -04:00
{
Super : : OnChildAttached ( ChildComponent ) ;
OnChildAttachmentModified . Broadcast ( ChildComponent , true ) ;
}
2021-06-12 14:30:22 -04:00
void UDynamicMeshComponent : : OnChildDetached ( USceneComponent * ChildComponent )
2021-06-10 18:37:57 -04:00
{
Super : : OnChildDetached ( ChildComponent ) ;
OnChildAttachmentModified . Broadcast ( ChildComponent , false ) ;
}
2021-06-20 18:12:30 -04:00
2024-03-04 18:02:09 -05:00
void UDynamicMeshComponent : : InternalOnMeshUpdated ( )
{
// Rebuild physics data
if ( bDeferCollisionUpdates | | bTransientDeferCollisionUpdates )
{
InvalidatePhysicsData ( ) ;
}
else
{
RebuildPhysicsData ( ) ;
}
2024-03-27 14:27:24 -04:00
UpdateDistanceField ( ) ;
2024-03-04 18:02:09 -05:00
}
2021-06-20 18:12:30 -04:00
2024-02-23 14:43:16 -05:00
bool UDynamicMeshComponent : : GetTriMeshSizeEstimates ( struct FTriMeshCollisionDataEstimates & OutTriMeshEstimates , bool bInUseAllTriData ) const
{
ProcessMesh ( [ & ] ( const FDynamicMesh3 & Mesh )
{
bool bCopyUVs = UPhysicsSettings : : Get ( ) - > bSupportUVFromHitResults & & Mesh . HasAttributes ( ) & & Mesh . Attributes ( ) - > NumUVLayers ( ) > 0 ;
if ( bCopyUVs )
{
// conservative estimate
OutTriMeshEstimates . VerticeCount = Mesh . TriangleCount ( ) * 3 ;
}
else
{
OutTriMeshEstimates . VerticeCount = Mesh . VertexCount ( ) ;
}
}
) ;
return true ;
}
2021-06-20 18:12:30 -04:00
bool UDynamicMeshComponent : : GetPhysicsTriMeshData ( struct FTriMeshCollisionData * CollisionData , bool InUseAllTriData )
{
// this is something we currently assume, if you hit this ensure, we made a mistake
ensure ( bEnableComplexCollision ) ;
ProcessMesh ( [ & ] ( const FDynamicMesh3 & Mesh )
{
2024-02-23 14:43:16 -05:00
// See if we should copy UVs
const bool bCopyUVs = UPhysicsSettings : : Get ( ) - > bSupportUVFromHitResults & & Mesh . HasAttributes ( ) & & Mesh . Attributes ( ) - > NumUVLayers ( ) > 0 ;
if ( bCopyUVs )
{
CollisionData - > UVs . SetNum ( Mesh . Attributes ( ) - > NumUVLayers ( ) ) ;
}
2024-02-21 18:46:48 -05:00
const FDynamicMeshMaterialAttribute * MaterialAttrib = Mesh . HasAttributes ( ) & & Mesh . Attributes ( ) - > HasMaterialID ( ) ? Mesh . Attributes ( ) - > GetMaterialID ( ) : nullptr ;
2024-02-23 14:43:16 -05:00
TArray < int32 > VertexMap ;
const bool bIsSparseV = ! Mesh . IsCompactV ( ) ;
2021-06-20 18:12:30 -04:00
// copy vertices
2024-02-23 14:43:16 -05:00
if ( ! bCopyUVs )
2021-06-20 18:12:30 -04:00
{
if ( bIsSparseV )
{
2024-02-23 14:43:16 -05:00
VertexMap . SetNum ( Mesh . MaxVertexID ( ) ) ;
2021-06-20 18:12:30 -04:00
}
2024-02-23 14:43:16 -05:00
CollisionData - > Vertices . Reserve ( Mesh . VertexCount ( ) ) ;
for ( int32 vid : Mesh . VertexIndicesItr ( ) )
2021-06-20 18:12:30 -04:00
{
2024-02-23 14:43:16 -05:00
int32 Index = CollisionData - > Vertices . Add ( ( FVector3f ) Mesh . GetVertex ( vid ) ) ;
if ( bIsSparseV )
{
VertexMap [ vid ] = Index ;
}
else
{
check ( vid = = Index ) ;
}
}
}
else
{
// map vertices per wedge
VertexMap . SetNumZeroed ( Mesh . TriangleCount ( ) * 3 ) ;
// temp array to store the UVs on a vertex (per triangle)
TArray < FVector2D > VertUVs ;
const FDynamicMeshAttributeSet * Attribs = Mesh . Attributes ( ) ;
const int32 NumUVLayers = Attribs - > NumUVLayers ( ) ;
for ( int32 VID : Mesh . VertexIndicesItr ( ) )
{
FVector3f Pos = ( FVector3f ) Mesh . GetVertex ( VID ) ;
int32 VertStart = CollisionData - > Vertices . Num ( ) ;
Mesh . EnumerateVertexTriangles ( VID , [ & ] ( int32 TID )
{
FIndex3i Tri = Mesh . GetTriangle ( TID ) ;
int32 VSubIdx = Tri . IndexOf ( VID ) ;
// Get the UVs on this wedge
VertUVs . Reset ( 8 ) ;
for ( int32 UVIdx = 0 ; UVIdx < NumUVLayers ; + + UVIdx )
{
const FDynamicMeshUVOverlay * Overlay = Attribs - > GetUVLayer ( UVIdx ) ;
FIndex3i UVTri = Overlay - > GetTriangle ( TID ) ;
int32 ElID = UVTri [ VSubIdx ] ;
FVector2D UV ( 0 , 0 ) ;
if ( ElID > = 0 )
{
UV = ( FVector2D ) Overlay - > GetElement ( ElID ) ;
}
VertUVs . Add ( UV ) ;
}
// Check if we've already added these UVs via an earlier wedge
int32 OutputVIdx = INDEX_NONE ;
for ( int32 VIdx = VertStart ; VIdx < CollisionData - > Vertices . Num ( ) ; + + VIdx )
{
bool bFound = true ;
for ( int32 UVIdx = 0 ; UVIdx < NumUVLayers ; + + UVIdx )
{
if ( CollisionData - > UVs [ UVIdx ] [ VIdx ] ! = VertUVs [ UVIdx ] )
{
bFound = false ;
break ;
}
}
if ( bFound )
{
OutputVIdx = VIdx ;
break ;
}
}
// If not, add the vertex w/ the UVs
if ( OutputVIdx = = INDEX_NONE )
{
OutputVIdx = CollisionData - > Vertices . Add ( Pos ) ;
for ( int32 UVIdx = 0 ; UVIdx < NumUVLayers ; + + UVIdx )
{
CollisionData - > UVs [ UVIdx ] . Add ( VertUVs [ UVIdx ] ) ;
}
}
// Map the wedge to the output vertex
VertexMap [ TID * 3 + VSubIdx ] = OutputVIdx ;
} ) ;
2021-06-20 18:12:30 -04:00
}
}
// copy triangles
CollisionData - > Indices . Reserve ( Mesh . TriangleCount ( ) ) ;
CollisionData - > MaterialIndices . Reserve ( Mesh . TriangleCount ( ) ) ;
for ( int32 tid : Mesh . TriangleIndicesItr ( ) )
{
FIndex3i Tri = Mesh . GetTriangle ( tid ) ;
FTriIndices Triangle ;
2024-02-23 14:43:16 -05:00
if ( bCopyUVs )
{
// UVs need a wedge-based map
Triangle . v0 = VertexMap [ tid * 3 + 0 ] ;
Triangle . v1 = VertexMap [ tid * 3 + 1 ] ;
Triangle . v2 = VertexMap [ tid * 3 + 2 ] ;
}
else if ( bIsSparseV )
{
Triangle . v0 = VertexMap [ Tri . A ] ;
Triangle . v1 = VertexMap [ Tri . B ] ;
Triangle . v2 = VertexMap [ Tri . C ] ;
}
else
{
Triangle . v0 = Tri . A ;
Triangle . v1 = Tri . B ;
Triangle . v2 = Tri . C ;
}
2022-09-09 10:37:31 -04:00
// Filter out triangles which will cause physics system to emit degenerate-geometry warnings.
// These checks reproduce tests in Chaos::CleanTrimesh
const FVector3f & A = CollisionData - > Vertices [ Triangle . v0 ] ;
const FVector3f & B = CollisionData - > Vertices [ Triangle . v1 ] ;
const FVector3f & C = CollisionData - > Vertices [ Triangle . v2 ] ;
if ( A = = B | | A = = C | | B = = C )
{
continue ;
}
// anything that fails the first check should also fail this, but Chaos does both so doing the same here...
const float SquaredArea = FVector3f : : CrossProduct ( A - B , A - C ) . SizeSquared ( ) ;
if ( SquaredArea < UE_SMALL_NUMBER )
{
continue ;
}
2021-06-20 18:12:30 -04:00
CollisionData - > Indices . Add ( Triangle ) ;
2024-02-21 18:46:48 -05:00
int32 MaterialID = MaterialAttrib ? MaterialAttrib - > GetValue ( tid ) : 0 ;
CollisionData - > MaterialIndices . Add ( MaterialID ) ;
2021-06-20 18:12:30 -04:00
}
CollisionData - > bFlipNormals = true ;
CollisionData - > bDeformableMesh = true ;
CollisionData - > bFastCook = true ;
} ) ;
return true ;
}
bool UDynamicMeshComponent : : ContainsPhysicsTriMeshData ( bool InUseAllTriData ) const
{
2024-03-04 18:02:09 -05:00
if ( bEnableComplexCollision & & ( MeshObject ! = nullptr ) )
{
int32 TriangleCount = MeshObject - > GetTriangleCount ( ) ;
// if the triangle count is too large, skip building complex collision
int32 MaxComplexCollisionTriCount = CVarDynamicMeshComponent_MaxComplexCollisionTriCount . GetValueOnAnyThread ( ) ;
if ( MaxComplexCollisionTriCount > = 0 & & TriangleCount > MaxComplexCollisionTriCount )
{
static bool bHavePrintedWarningMessage = false ;
if ( ! bHavePrintedWarningMessage )
{
UE_LOG ( LogGeometry , Display , TEXT ( " Ignoring attempt to build Complex Collision for a DynamicMeshComponent with triangle count larger than %d. Increase the geometry.DynamicMesh.MaxComplexCollisionTriCount value if you are certain you want to build Complex Collision for very large meshes. " ) , MaxComplexCollisionTriCount ) ;
bHavePrintedWarningMessage = true ;
}
return false ;
}
if ( TriangleCount > 0 )
{
return true ;
}
}
return false ;
2021-06-20 18:12:30 -04:00
}
bool UDynamicMeshComponent : : WantsNegXTriMesh ( )
{
return true ;
}
2022-03-11 23:38:07 -05:00
UBodySetup * UDynamicMeshComponent : : CreateBodySetupHelper ( )
{
UBodySetup * NewBodySetup = nullptr ;
{
FGCScopeGuard Scope ;
// Below flags are copied from UProceduralMeshComponent::CreateBodySetupHelper(). Without these flags, DynamicMeshComponents inside
// a DynamicMeshActor BP will result on a GLEO error after loading and modifying a saved Level (but *not* on the initial save)
// The UBodySetup in a template needs to be public since the property is Instanced and thus is the archetype of the instance meaning there is a direct reference
NewBodySetup = NewObject < UBodySetup > ( this , NAME_None , ( IsTemplate ( ) ? RF_Public | RF_ArchetypeObject : RF_NoFlags ) ) ;
}
NewBodySetup - > BodySetupGuid = FGuid : : NewGuid ( ) ;
NewBodySetup - > bGenerateMirroredCollision = false ;
NewBodySetup - > CollisionTraceFlag = this - > CollisionType ;
NewBodySetup - > DefaultInstance . SetCollisionProfileName ( UCollisionProfile : : BlockAll_ProfileName ) ;
NewBodySetup - > bSupportUVsAndFaceRemap = false ; /* bSupportPhysicalMaterialMasks; */
return NewBodySetup ;
}
2021-06-20 18:12:30 -04:00
UBodySetup * UDynamicMeshComponent : : GetBodySetup ( )
{
if ( MeshBodySetup = = nullptr )
{
2022-03-11 23:38:07 -05:00
UBodySetup * NewBodySetup = CreateBodySetupHelper ( ) ;
2021-06-20 18:12:30 -04:00
SetBodySetup ( NewBodySetup ) ;
}
return MeshBodySetup ;
}
void UDynamicMeshComponent : : SetBodySetup ( UBodySetup * NewSetup )
{
if ( ensure ( NewSetup ) )
{
MeshBodySetup = NewSetup ;
}
}
2022-03-11 23:38:07 -05:00
void UDynamicMeshComponent : : SetSimpleCollisionShapes ( const struct FKAggregateGeom & AggGeomIn , bool bUpdateCollision )
{
AggGeom = AggGeomIn ;
if ( bUpdateCollision )
{
UpdateCollision ( false ) ;
}
}
void UDynamicMeshComponent : : ClearSimpleCollisionShapes ( bool bUpdateCollision )
{
AggGeom . EmptyElements ( ) ;
if ( bUpdateCollision )
{
UpdateCollision ( false ) ;
}
}
2021-06-20 18:12:30 -04:00
void UDynamicMeshComponent : : InvalidatePhysicsData ( )
{
if ( GetBodySetup ( ) )
{
GetBodySetup ( ) - > InvalidatePhysicsData ( ) ;
bCollisionUpdatePending = true ;
}
}
void UDynamicMeshComponent : : RebuildPhysicsData ( )
{
2022-03-11 23:38:07 -05:00
UWorld * World = GetWorld ( ) ;
const bool bUseAsyncCook = World & & World - > IsGameWorld ( ) & & bUseAsyncCooking ;
UBodySetup * BodySetup = nullptr ;
if ( bUseAsyncCook )
{
// Abort all previous ones still standing
for ( UBodySetup * OldBody : AsyncBodySetupQueue )
{
OldBody - > AbortPhysicsMeshAsyncCreation ( ) ;
}
BodySetup = CreateBodySetupHelper ( ) ;
if ( BodySetup )
{
AsyncBodySetupQueue . Add ( BodySetup ) ;
}
}
else
{
AsyncBodySetupQueue . Empty ( ) ; // If for some reason we modified the async at runtime, just clear any pending async body setups
BodySetup = GetBodySetup ( ) ;
}
if ( ! BodySetup )
{
return ;
}
BodySetup - > CollisionTraceFlag = this - > CollisionType ;
// Note: Directly assigning AggGeom wouldn't do some important-looking cleanup (clearing pointers on convex elements)
// so we RemoveSimpleCollision then AddCollisionFrom instead
BodySetup - > RemoveSimpleCollision ( ) ;
BodySetup - > AddCollisionFrom ( this - > AggGeom ) ;
if ( bUseAsyncCook )
{
BodySetup - > CreatePhysicsMeshesAsync ( FOnAsyncPhysicsCookFinished : : CreateUObject ( this , & UDynamicMeshComponent : : FinishPhysicsAsyncCook , BodySetup ) ) ;
}
else
2021-06-20 18:12:30 -04:00
{
// New GUID as collision has changed
BodySetup - > BodySetupGuid = FGuid : : NewGuid ( ) ;
// Also we want cooked data for this
BodySetup - > bHasCookedCollisionData = true ;
BodySetup - > InvalidatePhysicsData ( ) ;
BodySetup - > CreatePhysicsMeshes ( ) ;
RecreatePhysicsState ( ) ;
bCollisionUpdatePending = false ;
}
2024-03-26 17:34:12 -04:00
if ( FDynamicMeshSceneProxy * Proxy = GetCurrentSceneProxy ( ) )
{
Proxy - > SetCollisionData ( ) ;
}
2021-06-20 18:12:30 -04:00
}
2022-03-11 23:38:07 -05:00
void UDynamicMeshComponent : : FinishPhysicsAsyncCook ( bool bSuccess , UBodySetup * FinishedBodySetup )
{
TArray < UBodySetup * > NewQueue ;
NewQueue . Reserve ( AsyncBodySetupQueue . Num ( ) ) ;
int32 FoundIdx ;
if ( AsyncBodySetupQueue . Find ( FinishedBodySetup , FoundIdx ) )
{
// Note: currently no-cook-needed is reported identically to cook failed.
// Checking AggGeom.GetElemCount() here is a hack to distinguish the no-cook-needed case
// TODO: remove this hack to distinguish the no-cook-needed case when/if that is no longer identical to the cook failed case
if ( bSuccess | | FinishedBodySetup - > AggGeom . GetElementCount ( ) > 0 )
{
// The new body was found in the array meaning it's newer, so use it
MeshBodySetup = FinishedBodySetup ;
RecreatePhysicsState ( ) ;
// remove any async body setups that were requested before this one
for ( int32 AsyncIdx = FoundIdx + 1 ; AsyncIdx < AsyncBodySetupQueue . Num ( ) ; + + AsyncIdx )
{
NewQueue . Add ( AsyncBodySetupQueue [ AsyncIdx ] ) ;
}
AsyncBodySetupQueue = NewQueue ;
}
else
{
AsyncBodySetupQueue . RemoveAt ( FoundIdx ) ;
}
}
}
2021-06-20 18:12:30 -04:00
void UDynamicMeshComponent : : UpdateCollision ( bool bOnlyIfPending )
{
if ( bOnlyIfPending = = false | | bCollisionUpdatePending )
{
RebuildPhysicsData ( ) ;
}
2021-09-16 20:16:44 -04:00
}
2022-03-11 23:38:07 -05:00
void UDynamicMeshComponent : : BeginDestroy ( )
{
Super : : BeginDestroy ( ) ;
AggGeom . FreeRenderInfo ( ) ;
}
2021-09-16 20:16:44 -04:00
void UDynamicMeshComponent : : EnableComplexAsSimpleCollision ( )
{
2021-11-04 10:22:38 -04:00
SetComplexAsSimpleCollisionEnabled ( true , true ) ;
}
void UDynamicMeshComponent : : SetComplexAsSimpleCollisionEnabled ( bool bEnabled , bool bImmediateUpdate )
{
bool bModified = false ;
if ( bEnabled )
{
if ( bEnableComplexCollision = = false )
{
bEnableComplexCollision = true ;
bModified = true ;
}
if ( CollisionType ! = ECollisionTraceFlag : : CTF_UseComplexAsSimple )
{
CollisionType = ECollisionTraceFlag : : CTF_UseComplexAsSimple ;
bModified = true ;
}
}
else
{
if ( bEnableComplexCollision = = true )
{
bEnableComplexCollision = false ;
bModified = true ;
}
if ( CollisionType = = ECollisionTraceFlag : : CTF_UseComplexAsSimple )
{
CollisionType = ECollisionTraceFlag : : CTF_UseDefault ;
bModified = true ;
}
}
if ( bModified )
{
InvalidatePhysicsData ( ) ;
}
if ( bImmediateUpdate )
{
UpdateCollision ( true ) ;
}
}
void UDynamicMeshComponent : : SetDeferredCollisionUpdatesEnabled ( bool bEnabled , bool bImmediateUpdate )
{
if ( bDeferCollisionUpdates ! = bEnabled )
{
bDeferCollisionUpdates = bEnabled ;
if ( bEnabled = = false & & bImmediateUpdate )
{
UpdateCollision ( true ) ;
}
}
}
2022-02-14 12:20:58 -05:00
2022-06-28 14:14:26 -04:00
void UDynamicMeshComponent : : SetTransientDeferCollisionUpdates ( bool bEnabled )
{
2022-07-15 17:53:52 -04:00
bTransientDeferCollisionUpdates = bEnabled ;
2022-06-28 14:14:26 -04:00
}
2022-02-14 12:20:58 -05:00
void UDynamicMeshComponent : : SetSceneProxyVerifyUsedMaterials ( bool bState )
{
bProxyVerifyUsedMaterials = bState ;
if ( FDynamicMeshSceneProxy * Proxy = GetCurrentSceneProxy ( ) )
{
Proxy - > SetVerifyUsedMaterials ( bState ) ;
}
}
2022-09-24 13:57:58 -04:00