|
3 | 3 |
|
4 | 4 | #include "RuntimeMeshStaticMeshConverter.h" |
5 | 5 | #include "RuntimeMeshComponentPlugin.h" |
6 | | -#include "EngineGlobals.h" |
7 | 6 | #include "Engine/StaticMesh.h" |
8 | 7 | #include "PhysicsEngine/BodySetup.h" |
9 | 8 | #include "RuntimeMeshRenderable.h" |
|
14 | 13 | #define RMC_LOG_VERBOSE(MeshId, Format, ...) \ |
15 | 14 | UE_LOG(RuntimeMeshLog, Verbose, TEXT("[SMC->RMC Mesh:%d Thread:%d]: " Format), MeshId, FPlatformTLS::GetCurrentThreadId(), ##__VA_ARGS__); |
16 | 15 |
|
| 16 | +#define RMC_LOG_WARNING(MeshId, Format, ...) \ |
| 17 | + UE_LOG(RuntimeMeshLog, Warning, TEXT("[SMC->RMC Mesh:%d Thread:%d]: " Format), MeshId, FPlatformTLS::GetCurrentThreadId(), ##__VA_ARGS__); |
| 18 | + |
| 19 | + |
| 20 | +bool URuntimeMeshStaticMeshConverter::CheckStaticMeshAccessible(UStaticMesh* StaticMesh) |
| 21 | +{ |
| 22 | + if (!IsValid(StaticMesh)) |
| 23 | + { |
| 24 | + RMC_LOG_WARNING(-1, "Tried to copy data from static mesh but static mesh is invalid! Stack trace:"); |
| 25 | + FDebug::DumpStackTraceToLog(ELogVerbosity::Verbose); |
| 26 | + return false; |
| 27 | + } |
| 28 | + |
| 29 | + // Check mesh data is accessible |
| 30 | + if (!((GIsEditor || StaticMesh->bAllowCPUAccess) && StaticMesh->GetRenderData() != nullptr)) |
| 31 | + { |
| 32 | + RMC_LOG_WARNING(-1, "Tried to copy data from static mesh but static mesh \"%s\" is inaccessible!", *StaticMesh->GetFullName()); |
| 33 | + return false; |
| 34 | + } |
| 35 | + return true; |
| 36 | +} |
17 | 37 |
|
18 | 38 | int32 URuntimeMeshStaticMeshConverter::CopyVertexOrGetIndex(const FStaticMeshLODResources& LOD, const FStaticMeshSection& Section, TMap<int32, int32>& MeshToSectionVertexMap, int32 VertexIndex, FRuntimeMeshRenderableMeshData& NewMeshData) |
19 | 39 | { |
@@ -92,6 +112,13 @@ int32 URuntimeMeshStaticMeshConverter::CopyVertexOrGetIndex(const FStaticMeshLOD |
92 | 112 | } |
93 | 113 |
|
94 | 114 | bool URuntimeMeshStaticMeshConverter::CopyStaticMeshSectionToRenderableMeshData(UStaticMesh* StaticMesh, int32 LODIndex, int32 SectionId, FRuntimeMeshRenderableMeshData& OutMeshData) |
| 115 | +{ |
| 116 | + FRuntimeMeshSectionProperties Props; |
| 117 | + return CopyStaticMeshSectionToRenderableMeshData(StaticMesh, LODIndex, SectionId, OutMeshData, Props); |
| 118 | +} |
| 119 | + |
| 120 | +bool URuntimeMeshStaticMeshConverter::CopyStaticMeshSectionToRenderableMeshData(UStaticMesh* StaticMesh, int32 LODIndex, |
| 121 | + int32 SectionId, FRuntimeMeshRenderableMeshData& OutMeshData, FRuntimeMeshSectionProperties& OutProperties) |
95 | 122 | { |
96 | 123 | // Check valid static mesh |
97 | 124 | if (!IsValid(StaticMesh)) |
@@ -144,42 +171,44 @@ bool URuntimeMeshStaticMeshConverter::CopyStaticMeshSectionToRenderableMeshData( |
144 | 171 | OutMeshData.Triangles.Add(SectionVertIndex); |
145 | 172 | } |
146 | 173 |
|
| 174 | + FRuntimeMeshSectionProperties& SectionProperties = OutProperties; |
| 175 | + SectionProperties.MaterialSlot = Section.MaterialIndex; |
| 176 | + SectionProperties.bCastsShadow = Section.bCastShadow; |
| 177 | + SectionProperties.bForceOpaque = Section.bForceOpaque; |
| 178 | + SectionProperties.bIsVisible = true; |
| 179 | + |
147 | 180 | // Lets copy the adjacency information too for tessellation |
148 | 181 | // At this point all vertices should be copied so it should work to just copy/convert the indices. |
| 182 | + //Tesselation is only supported for UE4 |
| 183 | +#if ENGINE_MAJOR_VERSION == 4 |
| 184 | +#if ENGINE_MINOR_VERSION <= 22 |
| 185 | + const auto& LODAdjacencyIndexBuffer = LOD.AdjacencyIndexBuffer; |
| 186 | +#else |
| 187 | + const auto& LODAdjacencyIndexBuffer = LOD.AdditionalIndexBuffers->AdjacencyIndexBuffer; |
| 188 | +#endif |
| 189 | + |
| 190 | + if (LOD.bHasAdjacencyInfo && LODAdjacencyIndexBuffer.GetNumIndices() > 0) |
| 191 | + { |
| 192 | + FIndexArrayView AdjacencyIndices = LODAdjacencyIndexBuffer.GetArrayView(); |
149 | 193 |
|
150 | | -//#if ENGINE_MAJOR_VERSION <= 4 && ENGINE_MINOR_VERSION <= 22 |
151 | | -// const auto& LODAdjacencyIndexBuffer = LOD.AdjacencyIndexBuffer; |
152 | | -//#else |
153 | | -// const auto& LODAdjacencyIndexBuffer = LOD.AdditionalIndexBuffers->AdjacencyIndexBuffer; |
154 | | -//#endif |
155 | | -// |
156 | | -// if (LOD.bHasAdjacencyInfo && LODAdjacencyIndexBuffer.GetNumIndices() > 0) |
157 | | -// { |
158 | | -// FIndexArrayView AdjacencyIndices = LODAdjacencyIndexBuffer.GetArrayView(); |
159 | | -// |
160 | | -// // We multiply these by 4 as the adjacency data is 12 indices per triangle instead of the normal 3 |
161 | | -// uint32 StartIndex = Section.FirstIndex * 4; |
162 | | -// uint32 NumIndices = Section.NumTriangles * 3 * 4; |
163 | | -// |
164 | | -// for (uint32 Index = 0; Index < NumIndices; Index++) |
165 | | -// { |
166 | | -// OutMeshData.AdjacencyTriangles.Add(MeshToSectionVertMap[AdjacencyIndices[StartIndex + Index]]); |
167 | | -// } |
168 | | -// } |
| 194 | + // We multiply these by 4 as the adjacency data is 12 indices per triangle instead of the normal 3 |
| 195 | + uint32 StartIndex = Section.FirstIndex * 4; |
| 196 | + uint32 NumIndices = Section.NumTriangles * 3 * 4; |
169 | 197 |
|
| 198 | + for (uint32 Index = 0; Index < NumIndices; Index++) |
| 199 | + { |
| 200 | + OutMeshData.AdjacencyTriangles.Add(MeshToSectionVertMap[AdjacencyIndices[StartIndex + Index]]); |
| 201 | + } |
| 202 | + } |
| 203 | +#endif |
170 | 204 | return true; |
171 | 205 | } |
172 | 206 |
|
173 | 207 | bool URuntimeMeshStaticMeshConverter::CopyStaticMeshCollisionToCollisionSettings(UStaticMesh* StaticMesh, FRuntimeMeshCollisionSettings& OutCollisionSettings) |
174 | 208 | { |
| 209 | + OutCollisionSettings = FRuntimeMeshCollisionSettings(); |
175 | 210 | // Check valid static mesh |
176 | | - if (!IsValid(StaticMesh)) |
177 | | - { |
178 | | - return false; |
179 | | - } |
180 | | - |
181 | | - // Check mesh data is accessible |
182 | | - if (!((GIsEditor || StaticMesh->bAllowCPUAccess) && StaticMesh->GetRenderData() != nullptr)) |
| 211 | + if (!CheckStaticMeshAccessible(StaticMesh)) |
183 | 212 | { |
184 | 213 | return false; |
185 | 214 | } |
@@ -248,13 +277,7 @@ bool URuntimeMeshStaticMeshConverter::CopyStaticMeshCollisionToCollisionSettings |
248 | 277 | bool URuntimeMeshStaticMeshConverter::CopyStaticMeshLODToCollisionData(UStaticMesh* StaticMesh, int32 LODIndex, FRuntimeMeshCollisionData& OutCollisionData) |
249 | 278 | { |
250 | 279 | // Check valid static mesh |
251 | | - if (!IsValid(StaticMesh)) |
252 | | - { |
253 | | - return false; |
254 | | - } |
255 | | - |
256 | | - // Check mesh data is accessible |
257 | | - if (!((GIsEditor || StaticMesh->bAllowCPUAccess) && StaticMesh->GetRenderData() != nullptr)) |
| 280 | + if (!CheckStaticMeshAccessible(StaticMesh)) |
258 | 281 | { |
259 | 282 | return false; |
260 | 283 | } |
@@ -296,7 +319,7 @@ bool URuntimeMeshStaticMeshConverter::CopyStaticMeshLODToCollisionData(UStaticMe |
296 | 319 | uint32 MeshVertIndex = Indices[TriIndex * 3 + Index]; |
297 | 320 |
|
298 | 321 | // See if we have this vert already in our section vert buffer, and copy vert in if not |
299 | | - int32 SectionVertIndex = CopyVertexOrGetIndex(LOD, Section, MeshToSectionVertMap, MeshVertIndex, NumUVChannels, OutCollisionData); |
| 322 | + CopyVertexOrGetIndex(LOD, Section, MeshToSectionVertMap, MeshVertIndex, NumUVChannels, OutCollisionData); |
300 | 323 |
|
301 | 324 | TempIndices[Index] = MeshVertIndex; |
302 | 325 | } |
@@ -324,83 +347,111 @@ bool URuntimeMeshStaticMeshConverter::CopyStaticMeshToRuntimeMesh(UStaticMesh* S |
324 | 347 | // Not able to convert to RMC without a static provider |
325 | 348 | if (StaticProvider == nullptr) |
326 | 349 | { |
327 | | - RMC_LOG_VERBOSE(RuntimeMeshComponent->GetRuntimeMeshId(), "Unable to convert StaticMesh to RuntimeMesh. No StaticProvider present."); |
328 | | - return false; |
329 | | - } |
330 | | - |
331 | | - |
332 | | - // Check valid static mesh |
333 | | - if (!IsValid(StaticMesh)) |
334 | | - { |
335 | | - RMC_LOG_VERBOSE(RuntimeMeshComponent->GetRuntimeMeshId(), "Unable to convert StaticMesh to RuntimeMesh. Invalid source StaticMesh."); |
336 | | - StaticProvider->ConfigureLODs({ FRuntimeMeshLODProperties() }); |
337 | | - StaticProvider->SetCollisionMesh(FRuntimeMeshCollisionData()); |
338 | | - StaticProvider->SetCollisionSettings(FRuntimeMeshCollisionSettings()); |
| 350 | + RMC_LOG_WARNING(RuntimeMeshComponent->GetRuntimeMeshId(), "Unable to convert StaticMesh to RuntimeMesh. No StaticProvider present."); |
339 | 351 | return false; |
340 | 352 | } |
| 353 | + TArray<TArray<FRuntimeMeshSectionData>> MeshData; |
| 354 | + FRuntimeMeshCollisionSettings CollisionSettings; |
| 355 | + FRuntimeMeshCollisionData CollisionData; |
| 356 | + TArray<FRuntimeMeshLODProperties> LODProperties; |
| 357 | + TArray<FStaticMaterial> Materials; |
341 | 358 |
|
342 | | - // Check mesh data is accessible |
343 | | - if (!((GIsEditor || StaticMesh->bAllowCPUAccess) && StaticMesh->GetRenderData() != nullptr)) |
| 359 | + if (!CopyStaticMeshData(StaticMesh, MeshData, LODProperties, |
| 360 | + Materials, CollisionData, CollisionSettings, MaxLODToCopy)) |
344 | 361 | { |
345 | | - RMC_LOG_VERBOSE(RuntimeMeshComponent->GetRuntimeMeshId(), "Unable to convert StaticMesh to RuntimeMesh. Invalid source StaticMesh."); |
346 | 362 | StaticProvider->ConfigureLODs({ FRuntimeMeshLODProperties() }); |
347 | 363 | StaticProvider->SetCollisionMesh(FRuntimeMeshCollisionData()); |
348 | 364 | StaticProvider->SetCollisionSettings(FRuntimeMeshCollisionSettings()); |
349 | 365 | return false; |
350 | 366 | } |
351 | 367 |
|
352 | 368 | // Copy materials |
353 | | - const TArray<FStaticMaterial>& MaterialSlots = StaticMesh->GetStaticMaterials(); |
| 369 | + TArray<FStaticMaterial>& MaterialSlots = Materials; |
354 | 370 | for (int32 SlotIndex = 0; SlotIndex < MaterialSlots.Num(); SlotIndex++) |
355 | 371 | { |
356 | 372 | StaticProvider->SetupMaterialSlot(SlotIndex, MaterialSlots[SlotIndex].MaterialSlotName, MaterialSlots[SlotIndex].MaterialInterface); |
357 | 373 | } |
358 | 374 |
|
359 | | - const auto& LODResources = StaticMesh->GetRenderData()->LODResources; |
| 375 | + // Setup LODs |
| 376 | + TArray<FRuntimeMeshLODProperties>& LODs = LODProperties; |
| 377 | + StaticProvider->ConfigureLODs(LODs); |
| 378 | + |
360 | 379 |
|
| 380 | + // Create all sections for all LODs |
| 381 | + for (int32 LODIndex = 0; LODIndex < MeshData.Num(); LODIndex++) |
| 382 | + { |
| 383 | + |
| 384 | + for (int32 SectionId = 0; SectionId < MeshData[LODIndex].Num(); SectionId++) |
| 385 | + { |
| 386 | + StaticProvider->CreateSection(LODIndex, SectionId, MeshData[LODIndex][SectionId].Properties, MeshData[LODIndex][SectionId].MeshData); |
| 387 | + } |
| 388 | + } |
| 389 | + StaticProvider->SetCollisionSettings(CollisionSettings); |
| 390 | + |
| 391 | + if (CollisionData.HasValidMeshData()) |
| 392 | + { |
| 393 | + StaticProvider->SetCollisionMesh(CollisionData); |
| 394 | + } |
| 395 | + |
| 396 | + return true; |
| 397 | +} |
| 398 | + |
| 399 | +bool URuntimeMeshStaticMeshConverter::CopyStaticMeshData(UStaticMesh* StaticMesh, |
| 400 | + TArray<TArray<FRuntimeMeshSectionData>>& OutSectionData, TArray<FRuntimeMeshLODProperties>& OutLODProperties, |
| 401 | + TArray<FStaticMaterial>& OutMaterials, FRuntimeMeshCollisionData& OutCollisionData, |
| 402 | + FRuntimeMeshCollisionSettings& OutCollisionSettings, int32 MaxLODToCopy) |
| 403 | +{ |
| 404 | + if (!CheckStaticMeshAccessible(StaticMesh)) |
| 405 | + { |
| 406 | + return false; |
| 407 | + } |
| 408 | + |
| 409 | + // Copy materials |
| 410 | + OutMaterials = StaticMesh->GetStaticMaterials(); |
| 411 | + |
| 412 | + FStaticMeshRenderData* RenderData = StaticMesh->GetRenderData(); |
| 413 | + const auto& LODResources = RenderData->LODResources; |
| 414 | + |
| 415 | + int32 NumLODs = FMath::Min(LODResources.Num(), MaxLODToCopy+1); |
361 | 416 | // Setup LODs |
362 | | - TArray<FRuntimeMeshLODProperties> LODs; |
363 | | - for (int32 LODIndex = 0; LODIndex < LODResources.Num() && LODIndex <= MaxLODToCopy; LODIndex++) |
| 417 | + TArray<FRuntimeMeshLODProperties>& LODs = OutLODProperties; |
| 418 | + |
| 419 | + for (int32 LODIndex = 0; LODIndex < NumLODs; LODIndex++) |
364 | 420 | { |
365 | 421 | FRuntimeMeshLODProperties LODProperties; |
366 | | - LODProperties.ScreenSize = StaticMesh->GetRenderData()->ScreenSize[LODIndex].Default; |
367 | | - |
| 422 | + LODProperties.ScreenSize = RenderData->ScreenSize[LODIndex].Default; |
368 | 423 | LODs.Add(LODProperties); |
369 | 424 | } |
370 | | - StaticProvider->ConfigureLODs(LODs); |
371 | 425 |
|
372 | 426 |
|
373 | 427 | // Create all sections for all LODs |
374 | | - for (int32 LODIndex = 0; LODIndex < LODResources.Num() && LODIndex <= MaxLODToCopy; LODIndex++) |
| 428 | + |
| 429 | + OutSectionData.SetNum(NumLODs); |
| 430 | + for (int32 LODIndex = 0; LODIndex < NumLODs; LODIndex++) |
375 | 431 | { |
376 | 432 | const auto& LOD = LODResources[LODIndex]; |
377 | | - |
| 433 | + OutSectionData[LODIndex].SetNum(LOD.Sections.Num()); |
378 | 434 | for (int32 SectionId = 0; SectionId < LOD.Sections.Num(); SectionId++) |
379 | 435 | { |
380 | | - const auto& Section = LOD.Sections[SectionId]; |
381 | | - |
382 | | - FRuntimeMeshSectionProperties SectionProperties; |
383 | 436 |
|
384 | 437 | FRuntimeMeshRenderableMeshData MeshData; |
385 | | - CopyStaticMeshSectionToRenderableMeshData(StaticMesh, LODIndex, SectionId, MeshData); |
386 | | - |
387 | | - StaticProvider->CreateSection(LODIndex, SectionId, SectionProperties, MeshData); |
| 438 | + CopyStaticMeshSectionToRenderableMeshData(StaticMesh, LODIndex, SectionId, |
| 439 | + OutSectionData[LODIndex][SectionId].MeshData, OutSectionData[LODIndex][SectionId].Properties); |
388 | 440 | } |
389 | 441 | } |
390 | 442 |
|
391 | | - FRuntimeMeshCollisionSettings CollisionSettings; |
| 443 | + FRuntimeMeshCollisionSettings CollisionSettings = OutCollisionSettings; |
392 | 444 | if (CopyStaticMeshCollisionToCollisionSettings(StaticMesh, CollisionSettings)) |
393 | 445 | { |
394 | | - StaticProvider->SetCollisionSettings(CollisionSettings); |
395 | 446 | } |
396 | 447 |
|
| 448 | + int CollisionLODIndex = StaticMesh->LODForCollision; |
| 449 | + |
397 | 450 | FRuntimeMeshCollisionData CollisionData; |
398 | | - if (CollisionLODIndex != INDEX_NONE && CopyStaticMeshLODToCollisionData(StaticMesh, CollisionLODIndex, CollisionData)) |
| 451 | + if (CollisionLODIndex >=0 && CollisionLODIndex < LODResources.Num() && CopyStaticMeshLODToCollisionData(StaticMesh, CollisionLODIndex, OutCollisionData)) |
399 | 452 | { |
400 | | - StaticProvider->SetCollisionMesh(CollisionData); |
401 | 453 | } |
402 | 454 |
|
403 | | - |
404 | 455 | return true; |
405 | 456 | } |
406 | 457 |
|
|
0 commit comments