UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
StaticMeshComponentHelper.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
10#include "StaticMeshResources.h"
12#include "NaniteVertexFactory.h"
13#include "VertexFactory.h"
14#include "PSOPrecacheFwd.h"
15#include "PSOPrecache.h"
16#include "RenderUtils.h"
18#include "Engine/World.h"
19#include "SceneInterface.h"
20
23{
24 using GetPSOVertexElementsFn = TFunctionRef<void(const FStaticMeshLODResources& LODRenderData, int32 LODIndex, bool bSupportsManualVertexFetch, FVertexDeclarationElementList& Elements)>;
25
26public:
34
35public:
36 template<class T>
38
39 template<class T>
40 static UMaterialInterface* GetMaterial(const T& Component, int32 MaterialIndex, bool bDoingNaniteMaterialAudit = false, bool bIgnoreNaniteOverrideMaterials = false);
41
42 template<class T>
44
45 template<class T>
46 static void CollectPSOPrecacheDataImpl(const T& Component, const FVertexFactoryType* VFType, const FPSOPrecacheParams& BasePrecachePSOParams, GetPSOVertexElementsFn GetVertexElements, FMaterialInterfacePSOPrecacheParamsList& OutParams);
47
48 template<class T>
50
51 template<class T>
52 static bool IsNavigationRelevant(const T& Component);
53
54 template<class T>
55 static FBox GetNavigationBounds(const T& Component);
56
57 template<class T>
58 static void GetNavigationData(const T& Component, FNavigationRelevantData& Data);
59
60 template<class T>
62
63 template<class T, bool bAssumeRenderDataIsReady = false>
65};
66
67template<typename T>
69{
71 Component.GetStaticMesh()->GetUsedMaterials(RayTracingMaterials, [&Component](int32 MaterialIndex)
72 {
74
75 // If we have a base materials array, use that
76 if (Component.OverrideMaterials.IsValidIndex(MaterialIndex) && Component.OverrideMaterials[MaterialIndex])
77 {
78 OutMaterial = Component.OverrideMaterials[MaterialIndex];
79 }
80 // Otherwise get from static mesh
81 else if (Component.GetStaticMesh())
82 {
83 OutMaterial = Component.GetStaticMesh()->GetMaterial(MaterialIndex);
84 }
85
87 {
88 //@note FH: temporary preemptive PostLoad until zenloader load ordering improvements
90
92 {
93 return OutMaterial;
94 }
95 }
96
97 return (UMaterialInterface*)nullptr;
98 });
99
100 if (!RayTracingMaterials.IsEmpty())
101 {
104 }
105}
106
107template<class T>
109{
111
112 // If we have a base materials array, use that
113 if (Component.OverrideMaterials.IsValidIndex(MaterialIndex) && Component.OverrideMaterials[MaterialIndex])
114 {
115 OutMaterial = Component.OverrideMaterials[MaterialIndex];
116 }
117 // Otherwise get from static mesh
118 else if (Component.GetStaticMesh())
119 {
120 OutMaterial = Component.GetStaticMesh()->GetMaterial(MaterialIndex);
121 }
122
123 // If we have a nanite override, use that
124 if (OutMaterial)
125 {
126 //@note FH: temporary preemptive PostLoad until zenloader load ordering improvements
128
129 if (!bIgnoreNaniteOverrideMaterials && Component.UseNaniteOverrideMaterials(bDoingNaniteMaterialAudit))
130 {
133 }
134 }
135
136 return OutMaterial;
137}
138
139template<class T>
141{
142 if (Component.GetStaticMesh())
143 {
144 Component.GetStaticMesh()->GetUsedMaterials(OutMaterials, [&Component](int32 Index) { return Component.GetMaterial(Index); });
145
146 // For ray tracing if the mesh is using nanite override materials we need to include fallback materials as well
147 if (IsRayTracingAllowed() && Component.GetStaticMesh()->bSupportRayTracing && Component.UseNaniteOverrideMaterials(false))
148 {
150 }
151
152 if (OutMaterials.Num() > 0)
153 {
155 Component.GetMaterialSlotsOverlayMaterial(AssetAndComponentMaterialSlotsOverlayMaterial);
158
160 {
161 UMaterialInterface* OverlayMaterialInterface = Component.GetOverlayMaterial();
162 if (OverlayMaterialInterface != nullptr)
163 {
164 OutMaterials.Add(OverlayMaterialInterface);
165 }
166 }
167 }
168 }
169}
170
171template<class T>
173{
174 check(Component.GetStaticMesh() != nullptr && Component.GetStaticMesh()->GetRenderData() != nullptr);
175
176 bool bSupportsManualVertexFetch = VFType->SupportsManualVertexFetch(GMaxRHIFeatureLevel);
177 bool bAnySectionCastsShadows = false;
178 int32 MeshMinLOD = Component.GetStaticMesh()->GetMinLODIdx();
179
181 FStaticMeshLODResourcesArray& LODResources = Component.GetStaticMesh()->GetRenderData()->LODResources;
182 for (int32 LODIndex = MeshMinLOD; LODIndex < LODResources.Num(); ++LODIndex)
183 {
184 FStaticMeshLODResources& LODRenderData = LODResources[LODIndex];
185 FVertexDeclarationElementList VertexElements;
186 if (!bSupportsManualVertexFetch)
187 {
188 GetVertexElements(LODRenderData, LODIndex, bSupportsManualVertexFetch, VertexElements);
189 }
190
191 for (FStaticMeshSection& RenderSection : LODRenderData.Sections)
192 {
194
195 int16 MaterialIndex = RenderSection.MaterialIndex;
197 [MaterialIndex](const FPSOPrecacheVertexFactoryDataPerMaterialIndex& Other) { return Other.MaterialIndex == MaterialIndex; });
198 if (VFsPerMaterial == nullptr)
199 {
200 VFsPerMaterial = &VFTypesPerMaterialIndex.AddDefaulted_GetRef();
202 }
203
204 if (bSupportsManualVertexFetch)
205 {
206 VFsPerMaterial->VertexFactoryDataList.AddUnique(FPSOPrecacheVertexFactoryData(VFType));
207 }
208 else
209 {
210 VFsPerMaterial->VertexFactoryDataList.AddUnique(FPSOPrecacheVertexFactoryData(VFType, VertexElements));
211 }
212 }
213 }
214
215 bool bIsLocalToWorldDeterminantNegative = Component.GetRenderMatrix().Determinant() < 0;
216
217 FPSOPrecacheParams PrecachePSOParams = BasePrecachePSOParams;
218 PrecachePSOParams.bCastShadow = bAnySectionCastsShadows;
219 PrecachePSOParams.bReverseCulling = PrecachePSOParams.bReverseCulling || Component.IsReverseCulling() != bIsLocalToWorldDeterminantNegative;
220 PrecachePSOParams.bForceLODModel = Component.GetForcedLodModel() > 0;
221
223 {
224 UMaterialInterface* MaterialInterface = Component.GetMaterial(VFsPerMaterial.MaterialIndex);
225 if (MaterialInterface == nullptr)
226 {
227 MaterialInterface = UMaterial::GetDefaultMaterial(MD_Surface);
228 }
229
231 ComponentParams.MaterialInterface = MaterialInterface;
232 ComponentParams.VertexFactoryDataList = VFsPerMaterial.VertexFactoryDataList;
233 ComponentParams.PSOPrecacheParams = PrecachePSOParams;
234 }
235
236 //Add all overlay materials
237 if (VFTypesPerMaterialIndex.Num() != 0)
238 {
239 //Add all per section overlay material and add the global mesh only if not all sections has an overlay override
241
243 Component.GetMaterialSlotsOverlayMaterial(AssetAndComponentMaterialSlotsOverlayMaterial);
247 {
248 UMaterialInterface* OverlayMaterialInterface = Component.GetOverlayMaterial();
249 if (OverlayMaterialInterface)
250 {
251 OverlayMaterials.Add(OverlayMaterialInterface);
252 }
253 }
255 {
257 {
258 // Overlay is rendered with the same set of VFs
261 ComponentParams.VertexFactoryDataList = VFTypesPerMaterialIndex[0].VertexFactoryDataList;
262 ComponentParams.PSOPrecacheParams = PrecachePSOParams;
263 ComponentParams.PSOPrecacheParams.bCastShadow = false;
264 }
265 }
266 }
267}
268
269template<class T>
271{
272 if (Component.GetStaticMesh() == nullptr || Component.GetStaticMesh()->GetRenderData() == nullptr)
273 {
274 return;
275 }
276
277 int32 LightMapCoordinateIndex = Component.GetStaticMesh()->GetLightMapCoordinateIndex();
278
279 auto SMC_GetElements = [LightMapCoordinateIndex, &LODData = Component.LODData](const FStaticMeshLODResources& LODRenderData, int32 LODIndex, bool bSupportsManualVertexFetch, FVertexDeclarationElementList& Elements)
280 {
281 int32 NumTexCoords = (int32)LODRenderData.VertexBuffers.StaticMeshVertexBuffer.GetNumTexCoords();
283 bool bOverrideColorVertexBuffer = LODIndex < LODData.Num() && LODData[LODIndex].OverrideVertexColors != nullptr;
285 LODRenderData.VertexBuffers.InitComponentVF(nullptr /*VertexFactory*/, LODLightMapCoordinateIndex, bOverrideColorVertexBuffer, Data);
287 };
288
289 Nanite::FMaterialAudit NaniteMaterials{};
291 {
293 }
294 else
295 {
297 }
298}
299
300template<class T>
302{
303 if (const UStaticMesh* Mesh = Component.GetStaticMesh())
304 {
305 // Pending compilation, update to the navigation system will be done once compilation finishes.
306 return !Mesh->IsCompiling() && Mesh->IsNavigationRelevant() && Component.Super::IsNavigationRelevant();
307 }
308 return false;
309}
310
311template<class T>
313{
314 if (const UStaticMesh* Mesh = Component.GetStaticMesh())
315 {
316#if WITH_EDITOR
317 // @see GetNavigationData
318 if (!Mesh->IsCompiling())
319#endif // WITH_EDITOR
320 {
321 return Mesh->GetNavigationBounds(Component.GetComponentTransform());
322 }
323 }
324
325 return Component.Super::GetNavigationBounds();
326}
327
328template<class T>
330{
331 Component.Super::GetNavigationData(Data);
332
333 const FVector Scale3D = Component.GetComponentTransform().GetScale3D();
334 if (!Scale3D.IsZero())
335 {
336 if (const UStaticMesh* Mesh = Component.GetStaticMesh())
337 {
338#if WITH_EDITOR
339 // In Editor it's possible that compilation of a StaticMesh gets triggered on a newly registered component for
340 // which a pending update is queued for the Navigation system.
341 // Then GetNavigationData is called when the pending update is processed but we don't consider the current component
342 // relevant to navigation until associated mesh is compiled.
343 // On mesh post compilation the component will reregister with the right mesh.
344 if (!Mesh->IsCompiling())
345#endif // WITH_EDITOR
346 {
347 if (UNavCollisionBase* NavCollision = Mesh->GetNavCollision())
348 {
349 if (Component.ShouldExportAsObstacle(*NavCollision))
350 {
351 NavCollision->GetNavigationModifier(Data.Modifiers, Component.GetComponentTransform());
352 }
353 }
354 }
355 }
356 }
357}
358
361{
362 template<typename T, typename = void>
363 struct THasGetFullName : std::false_type {};
364
365 template<typename T>
366 struct THasGetFullName<T, std::void_t<decltype(std::declval<T>().GetFullName())>> : std::true_type {};
367
368 template<typename T>
370 {
371 if constexpr (THasGetFullName<T>::value)
372 {
373 return Object.GetFullName();
374 }
375 else
376 {
377 return FString("None");
378 }
379 }
380}
381
382template<class T>
384{
385 const FVector Scale3D = Component.GetComponentTransform().GetScale3D();
386
387 if (!Scale3D.IsZero())
388 {
389 if (const UStaticMesh* Mesh = Component.GetStaticMesh())
390 {
391 if (ensureMsgf(!Mesh->IsCompiling(), TEXT("Component %s is not considered relevant to navigation until associated mesh is compiled."), *UObjectHelper::GetFullNameIfAvailable(Component)))
392 {
393 if (const UNavCollisionBase* NavCollision = Mesh->GetNavCollision())
394 {
395 if (Component.ShouldExportAsObstacle(*NavCollision))
396 {
397 // skip default export
398 return false;
399 }
400
401 const bool bHasData = NavCollision->ExportGeometry(Component.GetComponentTransform(), GeomExport);
402 if (bHasData)
403 {
404 // skip default export
405 return false;
406 }
407 }
408 }
409 }
410 }
411
412 return true;
413}
414
415template<class T, bool bAssumeRenderDataIsReady>
417{
418 UStaticMesh* StaticMesh = Component.GetStaticMesh();
419
421 {
422 if (OutError)
423 {
424 *OutError = InError;
425 }
426 };
427
428 if constexpr (!bAssumeRenderDataIsReady)
429 {
430 if (StaticMesh == nullptr)
431 {
432 UE_LOG(LogStaticMesh, Verbose, TEXT("Skipping CreateSceneProxy for StaticMeshComponent %s (StaticMesh is null)"), *UObjectHelper::GetFullNameIfAvailable(Component));
434 return nullptr;
435 }
436
437 // Prevent accessing the RenderData during async compilation. The RenderState will be recreated when compilation finishes.
438 if (StaticMesh->IsCompiling())
439 {
440 UE_LOG(LogStaticMesh, Verbose, TEXT("Skipping CreateSceneProxy for StaticMeshComponent %s (StaticMesh is not ready)"), *UObjectHelper::GetFullNameIfAvailable(Component));
442 return nullptr;
443 }
444
445 if (StaticMesh->GetRenderData() == nullptr)
446 {
447 UE_LOG(LogStaticMesh, Verbose, TEXT("Skipping CreateSceneProxy for StaticMeshComponent %s (RenderData is null)"), *UObjectHelper::GetFullNameIfAvailable(Component));
449 return nullptr;
450 }
451
452 if (!StaticMesh->GetRenderData()->IsInitialized())
453 {
454 UE_LOG(LogStaticMesh, Verbose, TEXT("Skipping CreateSceneProxy for StaticMeshComponent %s (RenderData is not initialized)"), *UObjectHelper::GetFullNameIfAvailable(Component));
456 return nullptr;
457 }
458 }
459 else
460 {
462 check(!StaticMesh->IsCompiling());
463 check(StaticMesh->GetRenderData());
464 check(StaticMesh->GetRenderData()->IsInitialized());
465 }
466
469 {
470 UE_LOG(LogStaticMesh, Verbose, TEXT("Skipping CreateSceneProxy for StaticMeshComponent %s (Static mesh component PSOs are still compiling)"), *UObjectHelper::GetFullNameIfAvailable(Component));
472 return nullptr;
473 }
474
475 const bool bIsMaskingAllowed = Nanite::IsMaskingAllowed(Component.GetWorld(), Component.GetForceNaniteForMasked());
476
477 Nanite::FMaterialAudit NaniteMaterials{};
478
479 // Is Nanite supported, and is there built Nanite data for this static mesh?
480 const bool bUseNanite = Component.ShouldCreateNaniteProxy(&NaniteMaterials);
481
482 if (bUseNanite)
483 {
484 // Nanite is fully supported
485 return Component.CreateStaticMeshSceneProxy(NaniteMaterials, true);
486 }
487
488 // If we didn't get a proxy, but Nanite was enabled on the asset when it was built, evaluate proxy creation
489 if (Component.HasValidNaniteData())
490 {
491 if (NaniteMaterials.IsValid(bIsMaskingAllowed))
492 {
494#if WITH_EDITORONLY_DATA
495 // Check for specific case of static mesh editor "proxy toggle"
497#endif
498 ;
499
500 if (!bAllowProxyRender) // Never render proxies
501 {
502 // We don't want to fall back to Nanite proxy rendering, so just make the mesh invisible instead.
503 return nullptr;
504 }
505 }
506
507 // Fall back to rendering Nanite proxy meshes with traditional static mesh scene proxies
508
509 FSceneInterface* Scene = Component.GetScene();
511
512 // TODO: handle Nanite representation being overriden using OnGetNaniteResources
513 // for now need to check UStaticMesh::HasValidNaniteData() directly here
514 const bool bFallbackGenerated = !StaticMesh->HasValidNaniteData() || StaticMesh->HasNaniteFallbackMesh(ShaderPlatform);
515
517 {
518 // TODO: automatically enable fallback on the static mesh asset?
519
520 UE_LOG(LogStaticMesh, Warning, TEXT("Unable to create a proxy for StaticMeshComponent [%s] because it doesn't have a fallback mesh."), *UObjectHelper::GetFullNameIfAvailable(Component));
522 return nullptr;
523 }
524 }
525
526 // Validate the LOD resources here
527 const FStaticMeshLODResourcesArray& LODResources = StaticMesh->GetRenderData()->LODResources;
528 const int32 SMCurrentMinLOD = StaticMesh->GetMinLODIdx();
529 const int32 EffectiveMinLOD = Component.GetOverrideMinLOD() ? FMath::Max(Component.GetMinLOD(), SMCurrentMinLOD) : SMCurrentMinLOD;
530 if (LODResources.Num() == 0 || LODResources[FMath::Clamp<int32>(EffectiveMinLOD, 0, LODResources.Num() - 1)].VertexBuffers.StaticMeshVertexBuffer.GetNumVertices() == 0)
531 {
532 UE_LOG(LogStaticMesh, Verbose, TEXT("Skipping CreateSceneProxy for StaticMeshComponent %s (LOD problems)"), *UObjectHelper::GetFullNameIfAvailable(Component));
534 return nullptr;
535 }
536
537 return Component.CreateStaticMeshSceneProxy(NaniteMaterials, false);
538}
OODEFFUNC typedef void(OODLE_CALLBACK t_fp_OodleCore_Plugin_Free)(void *ptr)
#define check(expr)
Definition AssertionMacros.h:314
#define ensureMsgf( InExpression, InFormat,...)
Definition AssertionMacros.h:465
FPlatformTypes::int16 int16
A 16-bit signed integer.
Definition Platform.h:1123
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define UE_LOG(CategoryName, Verbosity, Format,...)
Definition LogMacros.h:270
EPSOPrecacheProxyCreationStrategy GetPSOPrecacheProxyCreationStrategy()
Definition PSOPrecache.cpp:114
EPSOPrecachePriority
Definition PipelineStateCache.h:33
EShaderPlatform
Definition RHIShaderPlatform.h:11
ERHIFeatureLevel::Type GMaxRHIFeatureLevel
Definition RHI.cpp:1338
EShaderPlatform GMaxRHIShaderPlatform
Definition RHI.cpp:1335
bool IsRayTracingAllowed()
Definition RenderUtils.cpp:1787
EPSOPrecachePriority GetStaticMeshComponentBoostPSOPrecachePriority()
Definition StaticMeshSceneProxy.cpp:96
if(Failed) console_printf("Failed.\n")
static ENGINE_API void GetVertexElements(ERHIFeatureLevel::Type FeatureLevel, EVertexInputStreamType InputStreamType, bool bSupportsManualVertexFetch, FDataType &Data, FVertexDeclarationElementList &Elements)
Definition LocalVertexFactory.cpp:377
static void AppendAllOverlayMaterial(const TArray< TObjectPtr< UMaterialInterface > > &SourceMaterials, TArray< UMaterialInterface * > &OutMaterials, bool &bOutHaveNullEntry)
Definition MaterialOverlayHelper.h:15
Definition PrimitiveSceneProxy.h:296
Definition SceneInterface.h:106
ENGINE_API EShaderPlatform GetShaderPlatform() const
Definition SceneInterface.cpp:39
Definition StaticMeshComponentHelper.h:23
static bool IsNavigationRelevant(const T &Component)
Definition StaticMeshComponentHelper.h:301
static FBox GetNavigationBounds(const T &Component)
Definition StaticMeshComponentHelper.h:312
static FPrimitiveSceneProxy * CreateSceneProxy(T &Component, FStaticMeshComponentHelper::ESceneProxyCreationError *OutError=nullptr)
Definition StaticMeshComponentHelper.h:416
static void GetNavigationData(const T &Component, FNavigationRelevantData &Data)
Definition StaticMeshComponentHelper.h:329
static void CollectPSOPrecacheData(const T &Component, const FPSOPrecacheParams &BasePrecachePSOParams, FMaterialInterfacePSOPrecacheParamsList &OutParams)
Definition StaticMeshComponentHelper.h:270
static bool DoCustomNavigableGeometryExport(const T &Component, FNavigableGeometryExport &GeomExport)
Definition StaticMeshComponentHelper.h:383
static void CollectPSOPrecacheDataImpl(const T &Component, const FVertexFactoryType *VFType, const FPSOPrecacheParams &BasePrecachePSOParams, GetPSOVertexElementsFn GetVertexElements, FMaterialInterfacePSOPrecacheParamsList &OutParams)
Definition StaticMeshComponentHelper.h:172
static void GetUsedRayTracingOnlyMaterials(const T &Component, TArray< UMaterialInterface * > &OutMaterials)
Definition StaticMeshComponentHelper.h:68
ESceneProxyCreationError
Definition StaticMeshComponentHelper.h:28
static void GetUsedMaterials(const T &Component, TArray< UMaterialInterface * > &OutMaterials, bool bGetDebugMaterials)
Definition StaticMeshComponentHelper.h:140
static UMaterialInterface * GetMaterial(const T &Component, int32 MaterialIndex, bool bDoingNaniteMaterialAudit=false, bool bIgnoreNaniteOverrideMaterials=false)
Definition StaticMeshComponentHelper.h:108
Definition VertexFactory.h:314
bool SupportsManualVertexFetch(ERHIFeatureLevel::Type InFeatureLevel) const
Definition VertexFactory.h:426
static bool ShouldCreateNaniteProxy(const T &Component, FMaterialAudit *OutNaniteMaterials)
Definition NaniteResourcesHelper.h:112
SizeType RemoveAll(const PREDICATE_CLASS &Predicate)
Definition Array.h:3108
Definition AssetRegistryState.h:50
UE_FORCEINLINE_HINT int32 Num() const
Definition IndirectArray.h:94
Definition MaterialInterface.h:296
virtual UMaterialInterface * GetNaniteOverride(TMicRecursionGuard RecursionGuard=TMicRecursionGuard()) const PURE_VIRTUAL(UMaterialInterface
Definition MaterialInterface.h:639
virtual class UMaterial * GetMaterial() PURE_VIRTUAL(UMaterialInterface
Definition MaterialInterface.h:482
static ENGINE_API UMaterial * GetDefaultMaterial(EMaterialDomain Domain)
Definition Material.cpp:1071
Definition NavCollisionBase.h:23
COREUOBJECT_API void ConditionalPostLoad()
Definition Obj.cpp:1341
Definition StaticMesh.h:593
EProxyRenderMode GetProxyRenderMode()
Definition NaniteResources.cpp:3237
@ AllowForDebugging
Disable rendering if Nanite is enabled on a mesh but is unsupported, except for debug purpose.
Definition NaniteSceneProxy.h:156
@ Allow
Fall back to rendering Nanite proxy meshes if Nanite is unsupported. (default)
Definition NaniteSceneProxy.h:155
bool IsMaskingAllowed(UWorld *World, bool bForceNaniteForMasked)
Definition NaniteResources.cpp:3222
Definition StaticMeshComponentHelper.h:361
FString GetFullNameIfAvailable(T &Object)
Definition StaticMeshComponentHelper.h:369
U16 Index
Definition radfft.cpp:71
Definition LocalVertexFactory.h:60
Definition PSOPrecache.h:187
UMaterialInterface * MaterialInterface
Definition PSOPrecache.h:189
Definition NavigationSystemHelpers.h:25
Definition NavigationRelevantData.h:40
Definition PSOPrecache.h:30
uint64 bForceLODModel
Definition PSOPrecache.h:128
uint64 bCastShadow
Definition PSOPrecache.h:120
uint64 bReverseCulling
Definition PSOPrecache.h:125
int16 MaterialIndex
Definition PSOPrecache.h:180
Definition PSOPrecache.h:150
Definition StaticMeshResources.h:426
FStaticMeshSectionArray Sections
Definition StaticMeshResources.h:430
Definition StaticMeshResources.h:202
Definition NaniteSceneProxy.h:66
bool IsZero() const
Definition Vector.h:1761
Definition StaticMeshComponentHelper.h:363