RuntimeMeshData.cpp
Go to the documentation of this file.
1 // Copyright 2016-2018 Chris Conway (Koderz). All Rights Reserved.
2 
3 #include "RuntimeMeshData.h"
5 #include "RuntimeMesh.h"
6 #include "RuntimeMeshLibrary.h"
7 #include "RuntimeMeshCollision.h"
8 #include "PhysicsEngine/BodySetup.h"
9 #include "PhysicsEngine/PhysicsSettings.h"
10 #include "RuntimeMeshProxy.h"
11 
12 
13 DECLARE_CYCLE_STAT(TEXT("RM - Validation - Create"), STAT_RuntimeMesh_CheckCreate, STATGROUP_RuntimeMesh);
14 DECLARE_CYCLE_STAT(TEXT("RM - Validation - Update"), STAT_RuntimeMesh_CheckUpdate, STATGROUP_RuntimeMesh);
15 DECLARE_CYCLE_STAT(TEXT("RM - Validation - BoundingBox"), STAT_RuntimeMesh_CheckBoundingBox, STATGROUP_RuntimeMesh);
16 
17 DECLARE_CYCLE_STAT(TEXT("RM - Create Mesh Section - MeshBuilder"), STAT_RuntimeMesh_CreateMeshSection_MeshData, STATGROUP_RuntimeMesh);
18 DECLARE_CYCLE_STAT(TEXT("RM - Create Mesh Section - MeshBuilder - Move"), STAT_RuntimeMesh_CreateMeshSection_MeshData_Move, STATGROUP_RuntimeMesh);
19 DECLARE_CYCLE_STAT(TEXT("RM - Update Mesh Section - MeshBuilder"), STAT_RuntimeMesh_UpdateMeshSection_MeshData, STATGROUP_RuntimeMesh);
20 DECLARE_CYCLE_STAT(TEXT("RM - Update Mesh Section - MeshBuilder - Move"), STAT_RuntimeMesh_UpdateMeshSection_MeshData_Move, STATGROUP_RuntimeMesh);
21 
22 DECLARE_CYCLE_STAT(TEXT("RM - Create Mesh Section - Component Buffers"), STAT_RuntimeMesh_CreateMeshSectionFromComponents, STATGROUP_RuntimeMesh);
23 DECLARE_CYCLE_STAT(TEXT("RM - Update Mesh Section - Component Buffers"), STAT_RuntimeMesh_UpdateMeshSectionFromComponents, STATGROUP_RuntimeMesh);
24 
25 DECLARE_CYCLE_STAT(TEXT("RM - Create Mesh Section - Blueprint Packed Buffer"), STAT_RuntimeMesh_CreateMeshSectionPacked_Blueprint, STATGROUP_RuntimeMesh);
26 DECLARE_CYCLE_STAT(TEXT("RM - Update Mesh Section - Blueprint Packed Buffer"), STAT_RuntimeMesh_UpdateMeshSectionPacked_Blueprint, STATGROUP_RuntimeMesh);
27 
28 DECLARE_CYCLE_STAT(TEXT("RM - Get Readonly Section Accessor"), STAT_RuntimeMesh_GetReadonlyMeshAccessor, STATGROUP_RuntimeMesh);
29 
30 DECLARE_CYCLE_STAT(TEXT("RM - Clear Mesh Section"), STAT_RuntimeMesh_ClearMeshSection, STATGROUP_RuntimeMesh);
31 DECLARE_CYCLE_STAT(TEXT("RM - Clear All Mesh Sections"), STAT_RuntimeMesh_ClearAllMeshSections, STATGROUP_RuntimeMesh);
32 DECLARE_CYCLE_STAT(TEXT("RM - Get Section Bounding Box"), STAT_RuntimeMesh_GetSectionBoundingBox, STATGROUP_RuntimeMesh);
33 
34 DECLARE_CYCLE_STAT(TEXT("RM - Set Mesh Section Visible"), STAT_RuntimeMesh_SetMeshSectionVisible, STATGROUP_RuntimeMesh);
35 DECLARE_CYCLE_STAT(TEXT("RM - Is Mesh Section Visible"), STAT_RuntimeMesh_IsMeshSectionVisible, STATGROUP_RuntimeMesh);
36 
37 DECLARE_CYCLE_STAT(TEXT("RM - Set Mesh Section Casts Shadow"), STAT_RuntimeMesh_SetMeshSectionCastsShadow, STATGROUP_RuntimeMesh);
38 DECLARE_CYCLE_STAT(TEXT("RM - Is Mesh Section Casting Shadows"), STAT_RuntimeMesh_IsMeshSectionCastingShadows, STATGROUP_RuntimeMesh);
39 
40 DECLARE_CYCLE_STAT(TEXT("RM - Set Mesh Section Collision Enabled"), STAT_RuntimeMesh_SetMeshSectionCollisionEnabled, STATGROUP_RuntimeMesh);
41 DECLARE_CYCLE_STAT(TEXT("RM - Is Mesh Section Collision Enabled"), STAT_RuntimeMesh_IsMeshSectionCollisionEnabled, STATGROUP_RuntimeMesh);
42 
43 DECLARE_CYCLE_STAT(TEXT("RM - Get Available Section Index"), STAT_RuntimeMesh_GetAvailableSectionIndex, STATGROUP_RuntimeMesh);
44 DECLARE_CYCLE_STAT(TEXT("RM - Get Section Ids"), STAT_RuntimeMesh_GetSectionIds, STATGROUP_RuntimeMesh);
45 
46 DECLARE_CYCLE_STAT(TEXT("RM - Set Mesh Collision Section"), STAT_RuntimeMesh_SetMeshCollisionSection, STATGROUP_RuntimeMesh);
47 DECLARE_CYCLE_STAT(TEXT("RM - Clear Mesh Collision Section"), STAT_RuntimeMesh_ClearMeshCollisionSection, STATGROUP_RuntimeMesh);
48 DECLARE_CYCLE_STAT(TEXT("RM - Clear All Mesh Collision Sections"), STAT_RuntimeMesh_ClearAllMeshCollisionSections, STATGROUP_RuntimeMesh);
49 
50 DECLARE_CYCLE_STAT(TEXT("RM - Add Convex Collision Section"), STAT_RuntimeMesh_AddConvexCollisionSection, STATGROUP_RuntimeMesh);
51 DECLARE_CYCLE_STAT(TEXT("RM - Set Convex Collision Section"), STAT_RuntimeMesh_SetConvexCollisionSection, STATGROUP_RuntimeMesh);
52 DECLARE_CYCLE_STAT(TEXT("RM - Clear Convex Collision Section"), STAT_RuntimeMesh_ClearConvexCollisionSection, STATGROUP_RuntimeMesh);
53 DECLARE_CYCLE_STAT(TEXT("RM - Clear All Convex Collision Sections"), STAT_RuntimeMesh_ClearAllConvexCollisionSections, STATGROUP_RuntimeMesh);
54 
55 DECLARE_CYCLE_STAT(TEXT("RM - Create Mesh Section - Internal"), STAT_RuntimeMesh_CreateSectionInternal, STATGROUP_RuntimeMesh);
56 DECLARE_CYCLE_STAT(TEXT("RM - Update Mesh Section - Internal"), STAT_RuntimeMesh_UpdateSectionInternal, STATGROUP_RuntimeMesh);
57 DECLARE_CYCLE_STAT(TEXT("RM - Handle Common Section Update Flags"), STAT_RuntimeMesh_HandleCommonSectionUpdateFlags, STATGROUP_RuntimeMesh);
58 DECLARE_CYCLE_STAT(TEXT("RM - Handle Common Section Update Flags - Calculate Tangents"), STAT_RuntimeMesh_HandleCommonSectionUpdateFlags_CalculateTangents, STATGROUP_RuntimeMesh);
59 DECLARE_CYCLE_STAT(TEXT("RM - Handle Common Section Update Flags - Calculate Tessellation Indices"), STAT_RuntimeMesh_HandleCommonSectionUpdateFlags_CalculateTessellationIndices, STATGROUP_RuntimeMesh);
60 DECLARE_CYCLE_STAT(TEXT("RM - Update Section Properties Internal"), STAT_RuntimeMesh_UpdateSectionPropertiesInternal, STATGROUP_RuntimeMesh);
61 DECLARE_CYCLE_STAT(TEXT("RM - Update Local Bounds"), STAT_RuntimeMesh_UpdateLocalBounds, STATGROUP_RuntimeMesh);
62 DECLARE_CYCLE_STAT(TEXT("RM - Initialize"), STAT_RuntimeMesh_Initialize, STATGROUP_RuntimeMesh);
63 
64 DECLARE_CYCLE_STAT(TEXT("RM - Contains Physics Triangle Mesh Data"), STAT_RuntimeMesh_ContainsPhysicsTriMeshData, STATGROUP_RuntimeMesh);
65 DECLARE_CYCLE_STAT(TEXT("RM - Get Physics Triangle Mesh Data"), STAT_RuntimeMesh_GetPhysicsTriMeshData, STATGROUP_RuntimeMesh);
66 DECLARE_CYCLE_STAT(TEXT("RM - Copy Collision Elements to Body Setup"), STAT_RuntimeMesh_CopyCollisionElementsToBodySetup, STATGROUP_RuntimeMesh);
67 DECLARE_CYCLE_STAT(TEXT("RM - Get Section From Collision Face Index"), STAT_RuntimeMesh_GetSectionFromCollisionFaceIndex, STATGROUP_RuntimeMesh);
68 
70  : SyncRoot(new FRuntimeMeshNullLockProvider())
71 {
72 }
73 
75 {
76 }
77 
78 void FRuntimeMeshData::Setup(TWeakObjectPtr<URuntimeMesh> InParentMeshObject)
79 {
80  ParentMeshObject = InParentMeshObject;
81 }
82 
83 void FRuntimeMeshData::CheckCreate(int32 NumUVs, bool bIndexIsValid) const
84 {
85  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_CheckCreate);
86 #if DO_CHECK
87 
88  if (NumUVs < 1 || NumUVs > 8)
89  {
90  UE_LOG(RuntimeMeshLog, Fatal, TEXT("UV Channel Count must be between 1 and 8 inclusive"));
91  }
92 
93  // Check indices
94  if (!bIndexIsValid)
95  {
96  UE_LOG(RuntimeMeshLog, Fatal, TEXT("Indices can only be of type uint16, int32, or uint32."));
97  }
98 #endif
99 }
100 
101 void FRuntimeMeshData::CheckCreateLegacyInternal(const FRuntimeMeshVertexStreamStructure& Stream0Structure, const FRuntimeMeshVertexStreamStructure& Stream1Structure, const FRuntimeMeshVertexStreamStructure& Stream2Structure, bool bIsIndexValid) const
102 {
103 #if DO_CHECK
104 
105  // Check stream 0 contains the position element
106  if (!Stream0Structure.Position.IsValid())
107  {
108 
109  UE_LOG(RuntimeMeshLog, Fatal, TEXT("Position element must always be in stream 0."));
110  }
111 
112  // Check the 3 streams are valid when combined
113  if (!FRuntimeMeshVertexStreamStructure::ValidTripleStream(Stream0Structure, Stream1Structure, Stream2Structure))
114  {
115  UE_LOG(RuntimeMeshLog, Fatal, TEXT("Streams cannot have overlapping elements, and all elements must be present."));
116  }
117 
118  // Check indices
119  if (!bIsIndexValid)
120  {
121  UE_LOG(RuntimeMeshLog, Fatal, TEXT("Indices can only be of type uint16, int32, or uint32."));
122  }
123 #endif
124 }
125 
126 void FRuntimeMeshData::CheckUpdate(bool bUseHighPrecisionTangents, bool bUseHighPrecisionUVs, int32 NumUVs, bool b32BitIndices, int32 SectionIndex, bool bShouldCheckIndexType,
127  bool bCheckTangentVertexStream, bool bCheckUVVertexStream) const
128 {
129  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_CheckUpdate);
130 #if DO_CHECK
131  if (!MeshSections.IsValidIndex(SectionIndex) || !MeshSections[SectionIndex].IsValid())
132  {
133  UE_LOG(RuntimeMeshLog, Fatal, TEXT("Mesh Section %d does not exist in RMC."), SectionIndex);
134  }
135 
136  FRuntimeMeshSectionPtr Section = MeshSections[SectionIndex];
137 
138  if (bCheckTangentVertexStream && !Section->CheckTangentBuffer(bUseHighPrecisionTangents))
139  {
140  UE_LOG(RuntimeMeshLog, Fatal, TEXT("Supplied vertex type does not match stream 1 for mesh section %d."), SectionIndex);
141  }
142 
143  if (bCheckUVVertexStream && !Section->CheckUVBuffer(bUseHighPrecisionUVs, NumUVs))
144  {
145  UE_LOG(RuntimeMeshLog, Fatal, TEXT("Supplied vertex type does not match stream 2 for mesh section %d."), SectionIndex);
146  }
147 
148  if (bShouldCheckIndexType && !Section->CheckIndexBufferSize(b32BitIndices))
149  {
150  UE_LOG(RuntimeMeshLog, Fatal, TEXT("Supplied index type do not match mesh section %d."), SectionIndex);
151  }
152 #endif
153 }
154 
155 void FRuntimeMeshData::CheckBoundingBox(const FBox& Box) const
156 {
157  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_CheckBoundingBox);
158 #if DO_CHECK
159  if (!Box.IsValid || Box.GetVolume() <= 0)
160  {
161  UE_LOG(RuntimeMeshLog, Fatal, TEXT("Supplied bounding invalid was invalid."));
162  }
163 #endif
164 }
165 
166 
167 
169 {
170  if (!SyncRoot->IsThreadSafe())
171  {
172  SyncRoot = MakeUnique<FRuntimeMeshMutexLockProvider>();
173  }
174 }
175 
176 void FRuntimeMeshData::CreateMeshSection(int32 SectionIndex, bool bWantsHighPrecisionTangents, bool bWantsHighPrecisionUVs, int32 NumUVs, bool bWants32BitIndices, bool bCreateCollision, EUpdateFrequency UpdateFrequency /*= EUpdateFrequency::Average*/)
177 {
178  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_CreateMeshSection_NoData);
179 
181 
182  CheckCreate(NumUVs, true);
183 
184  auto NewSection = CreateOrResetSection(SectionIndex, bWantsHighPrecisionTangents, bWantsHighPrecisionUVs, NumUVs, bWants32BitIndices, UpdateFrequency);
185 
186  // Track collision status and update collision information if necessary
187  NewSection->SetCollisionEnabled(bCreateCollision);
188 
189  // Finalize section.
191 }
192 
193 void FRuntimeMeshData::CreateMeshSection(int32 SectionId, const TSharedPtr<FRuntimeMeshBuilder>& MeshData, bool bCreateCollision /*= false*/, EUpdateFrequency UpdateFrequency /*= EUpdateFrequency::Average*/, ESectionUpdateFlags UpdateFlags /*= ESectionUpdateFlags::None*/)
194 {
195  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_CreateMeshSection_MeshData);
196 
198 
199  CheckCreate(MeshData->NumUVChannels(), true);
200 
201 
202  auto NewSection = CreateOrResetSection(SectionId, MeshData->IsUsingHighPrecisionTangents(), MeshData->IsUsingHighPrecisionUVs(), MeshData->NumUVChannels(), MeshData->IsUsing32BitIndices(), UpdateFrequency);
203 
204  NewSection->UpdatePositionBuffer(MeshData->GetPositionStream(), false);
205  NewSection->UpdateTangentsBuffer(MeshData->GetTangentStream(), false);
206  NewSection->UpdateUVsBuffer(MeshData->GetUVStream(), false);
207  NewSection->UpdateColorBuffer(MeshData->GetColorStream(), false);
208  NewSection->UpdateIndexBuffer(MeshData->GetIndexStream(), false);
209 
210  // Track collision status and update collision information if necessary
211  NewSection->SetCollisionEnabled(bCreateCollision);
212 
213  // Finalize section.
214  CreateSectionInternal(SectionId, UpdateFlags);
215 }
216 
217 void FRuntimeMeshData::CreateMeshSectionByMove(int32 SectionId, const TSharedPtr<FRuntimeMeshBuilder>& MeshData, bool bCreateCollision /*= false*/, EUpdateFrequency UpdateFrequency /*= EUpdateFrequency::Average*/, ESectionUpdateFlags UpdateFlags /*= ESectionUpdateFlags::None*/)
218 {
219  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_CreateMeshSection_MeshData_Move);
220 
222 
223  CheckCreate(MeshData->NumUVChannels(), true);
224 
225  auto NewSection = CreateOrResetSection(SectionId, MeshData->IsUsingHighPrecisionTangents(), MeshData->IsUsingHighPrecisionUVs(), MeshData->NumUVChannels(), MeshData->IsUsing32BitIndices(), UpdateFrequency);
226 
227  NewSection->UpdatePositionBuffer(MeshData->GetPositionStream(), true);
228  NewSection->UpdateTangentsBuffer(MeshData->GetTangentStream(), true);
229  NewSection->UpdateUVsBuffer(MeshData->GetUVStream(), true);
230  NewSection->UpdateColorBuffer(MeshData->GetColorStream(), true);
231  NewSection->UpdateIndexBuffer(MeshData->GetIndexStream(), true);
232 
233  // Track collision status and update collision information if necessary
234  NewSection->SetCollisionEnabled(bCreateCollision);
235 
236  // Finalize section.
237  CreateSectionInternal(SectionId, UpdateFlags);
238 }
239 
240 void FRuntimeMeshData::UpdateMeshSection(int32 SectionId, const TSharedPtr<FRuntimeMeshBuilder>& MeshData, ESectionUpdateFlags UpdateFlags /*= ESectionUpdateFlags::None*/)
241 {
242  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_UpdateMeshSection_MeshData);
243 
245 
246  CheckUpdate(MeshData->IsUsingHighPrecisionTangents(), MeshData->IsUsingHighPrecisionUVs(), MeshData->NumUVChannels(), MeshData->IsUsing32BitIndices(), SectionId, true, true, true);
247 
248  FRuntimeMeshSectionPtr Section = MeshSections[SectionId];
249 
251 
252  Section->UpdatePositionBuffer(MeshData->GetPositionStream(), false);
253  Section->UpdateTangentsBuffer(MeshData->GetTangentStream(), false);
254  Section->UpdateUVsBuffer(MeshData->GetUVStream(), false);
255  Section->UpdateColorBuffer(MeshData->GetColorStream(), false);
256  Section->UpdateIndexBuffer(MeshData->GetIndexStream(), false);
257 
258  UpdateSectionInternal(SectionId, BuffersToUpdate, UpdateFlags);
259 }
260 
261 void FRuntimeMeshData::UpdateMeshSectionByMove(int32 SectionId, const TSharedPtr<FRuntimeMeshBuilder>& MeshData, ESectionUpdateFlags UpdateFlags /*= ESectionUpdateFlags::None*/)
262 {
263  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_UpdateMeshSection_MeshData_Move);
264 
266 
267  CheckUpdate(MeshData->IsUsingHighPrecisionTangents(), MeshData->IsUsingHighPrecisionUVs(), MeshData->NumUVChannels(), MeshData->IsUsing32BitIndices(), SectionId, true, true, true);
268 
269  FRuntimeMeshSectionPtr Section = MeshSections[SectionId];
270 
272 
273  Section->UpdatePositionBuffer(MeshData->GetPositionStream(), true);
274  Section->UpdateTangentsBuffer(MeshData->GetTangentStream(), true);
275  Section->UpdateUVsBuffer(MeshData->GetUVStream(), true);
276  Section->UpdateColorBuffer(MeshData->GetColorStream(), true);
277  Section->UpdateIndexBuffer(MeshData->GetIndexStream(), true);
278 
279  UpdateSectionInternal(SectionId, BuffersToUpdate, UpdateFlags);
280 }
281 
282 
283 
284 
285 TUniquePtr<FRuntimeMeshScopedUpdater> FRuntimeMeshData::BeginSectionUpdate(int32 SectionId, ESectionUpdateFlags UpdateFlags /*= ESectionUpdateFlags::None*/)
286 {
287  check(DoesSectionExist(SectionId));
288 
289  // Enter the lock and then hand this lock to the updater
290  SyncRoot->Lock();
291 
292  FRuntimeMeshSectionPtr Section = MeshSections[SectionId];
293 
294  return Section->GetSectionMeshUpdater(this->AsShared(), SectionId, UpdateFlags, SyncRoot.Get(), false);
295 }
296 
297 TUniquePtr<FRuntimeMeshScopedUpdater> FRuntimeMeshData::GetSectionReadonly(int32 SectionId)
298 {
299  check(DoesSectionExist(SectionId));
300 
301  // Enter the lock and then hand this lock to the updater
302  SyncRoot->Lock();
303 
304  FRuntimeMeshSectionPtr Section = MeshSections[SectionId];
305 
306  return Section->GetSectionMeshUpdater(this->AsShared(), SectionId, ESectionUpdateFlags::None, SyncRoot.Get(), true);
307 }
308 
309 void FRuntimeMeshData::EndSectionUpdate(FRuntimeMeshScopedUpdater* Updater, ERuntimeMeshBuffersToUpdate BuffersToUpdate, const FBox* BoundingBox /*= nullptr*/)
310 {
312 
314 
315  if (BoundingBox)
316  {
317  Section->SetBoundingBox(*BoundingBox);
318  }
319  else
320  {
321  Section->UpdateBoundingBox();
322  }
323 
324  UpdateSectionInternal(Updater->SectionIndex, BuffersToUpdate, Updater->UpdateFlags);
325 }
326 
327 void FRuntimeMeshData::CreateMeshSectionFromComponents(int32 SectionIndex, const TArray<FVector>& Vertices, const TArray<int32>& Triangles, const TArray<FVector>& Normals,
328  const TArray<FVector2D>& UV0, const TArray<FVector2D>& UV1, TFunction<FColor(int32 Index)> ColorAccessor, int32 NumColors,
329  const TArray<FRuntimeMeshTangent>& Tangents, bool bCreateCollision, EUpdateFrequency UpdateFrequency, ESectionUpdateFlags UpdateFlags,
330  bool bUseHighPrecisionTangents, bool bUseHighPrecisionUVs, bool bWantsSecondUV)
331 {
332  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_CreateMeshSectionFromComponents);
333 
335 
336  // Create the section
337  auto NewSection = CreateOrResetSectionForBlueprint(SectionIndex, bWantsSecondUV, bUseHighPrecisionTangents, bUseHighPrecisionUVs, UpdateFrequency);
338 
339  TSharedPtr<FRuntimeMeshAccessor> MeshData = NewSection->GetSectionMeshAccessor();
340 
341  // We base the size of the mesh data off the vertices/positions
342  MeshData->SetNumVertices(Vertices.Num());
343 
344  for (int32 Index = 0; Index < Vertices.Num(); Index++)
345  {
346  MeshData->SetPosition(Index, Vertices[Index]);
347  MeshData->SetNormalTangent(Index,
348  Normals.Num() > Index ? Normals[Index] : FVector(0.0f, 0.0f, 1.0f),
349  Tangents.Num() > Index ? Tangents[Index] : FRuntimeMeshTangent(0, 0, 1.0f));
350  MeshData->SetColor(Index, NumColors > Index ? ColorAccessor(Index) : FColor::White);
351  MeshData->SetUV(Index, 0, UV0.Num() > Index ? UV0[Index] : FVector2D::ZeroVector);
352  if (bWantsSecondUV)
353  {
354  MeshData->SetUV(Index, 1, UV1.Num() > Index ? UV1[Index] : FVector2D::ZeroVector);
355  }
356  }
357 
358  NewSection->UpdateIndexBuffer(Triangles);
359 
360  NewSection->UpdateBoundingBox();
361 
362  // Track collision status and update collision information if necessary
363  NewSection->SetCollisionEnabled(bCreateCollision);
364 
365  // Finalize section.
366  CreateSectionInternal(SectionIndex, UpdateFlags);
367 }
368 
369 void FRuntimeMeshData::UpdateMeshSectionFromComponents(int32 SectionIndex, const TArray<FVector>& Vertices, const TArray<int32>& Triangles, const TArray<FVector>& Normals,
370  const TArray<FVector2D>& UV0, const TArray<FVector2D>& UV1, TFunction<FColor(int32 Index)> ColorAccessor, int32 NumColors, const TArray<FRuntimeMeshTangent>& Tangents, ESectionUpdateFlags UpdateFlags)
371 {
372  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_UpdateMeshSectionFromComponents);
373 
375 
376  // We only check stream 0 and 2 since stream 1 can change based on config, this is potentially dangerous to assume but probably not in practice.
377 // CheckUpdate(GetStreamStructure<FVector>(), GetStreamStructure<FRuntimeMeshNullVertex>(), GetStreamStructure<FColor>(), true, SectionIndex, true, true, false, true);
378 
379  FRuntimeMeshSectionPtr& Section = MeshSections[SectionIndex];
380 
382  if (Vertices.Num() > 0)
383  {
385  }
386  if (Normals.Num() > 0 || Tangents.Num() > 0)
387  {
389  }
390  if (UV0.Num() > 0 || UV1.Num() > 0)
391  {
392  BuffersToUpdate |= ERuntimeMeshBuffersToUpdate::UVBuffer;
393  }
394  if (NumColors > 0)
395  {
396  BuffersToUpdate |= ERuntimeMeshBuffersToUpdate::ColorBuffer;
397  }
398 
399  if (BuffersToUpdate != ERuntimeMeshBuffersToUpdate::None)
400  {
401  TSharedPtr<FRuntimeMeshAccessor> MeshData = Section->GetSectionMeshAccessor();
402 
403  int32 OldVertexCount = FMath::Min(MeshData->NumVertices(), Vertices.Num());
404 
405  // We base the size of the mesh data off the vertices/positions
406  MeshData->SetNumVertices(Vertices.Num());
407 
408  bool bHasSecondUV = MeshData->NumUVChannels() > 1;
409 
410  // Overwrite existing data
411  for (int32 Index = 0; Index < OldVertexCount; Index++)
412  {
413  if (Vertices.Num() > Index) MeshData->SetPosition(Index, Vertices[Index]);
414  if (Normals.Num() > Index) MeshData->SetNormal(Index, Normals[Index]);
415  if (Tangents.Num() > Index) MeshData->SetTangent(Index, FVector4(Tangents[Index].TangentX, Tangents[Index].bFlipTangentY ? -1.0f : 1.0f));
416  if (NumColors > Index) MeshData->SetColor(Index, ColorAccessor(Index));
417  if (UV0.Num() > Index) MeshData->SetUV(Index, 0, UV0[Index]);
418  if (bHasSecondUV && UV1.Num() > Index) MeshData->SetUV(Index, 1, UV1[Index]);
419  }
420 
421  // Fill remaining mesh data
422  for (int32 Index = OldVertexCount; Index < Vertices.Num(); Index++)
423  {
424  MeshData->SetPosition(Index, Vertices[Index]);
425  MeshData->SetNormalTangent(Index,
426  Normals.Num() > Index ? Normals[Index] : FVector(0.0f, 0.0f, 1.0f),
427  Tangents.Num() > Index ? Tangents[Index] : FRuntimeMeshTangent(0, 0, 1.0f));
428  MeshData->SetColor(Index, NumColors > Index ? ColorAccessor(Index) : FColor::White);
429  MeshData->SetUV(Index, 0, UV0.Num() > Index ? UV0[Index] : FVector2D::ZeroVector);
430  if (bHasSecondUV)
431  MeshData->SetUV(Index, 1, UV1.Num() > Index ? UV1[Index] : FVector2D::ZeroVector);
432  }
433  }
434 
435  if (Vertices.Num() > 0)
436  {
437  Section->UpdateBoundingBox();
438  }
439 
440  if (Triangles.Num() > 0)
441  {
442  Section->UpdateIndexBuffer(Triangles);
443  BuffersToUpdate |= ERuntimeMeshBuffersToUpdate::IndexBuffer;
444  }
445 
446  // Finalize section.
447  UpdateSectionInternal(SectionIndex, BuffersToUpdate, UpdateFlags);
448 }
449 
450 void FRuntimeMeshData::UpdateMeshSectionColors(int32 SectionIndex, TArray<FColor>& Colors, ESectionUpdateFlags UpdateFlags /*= ESectionUpdateFlags::None*/)
451 {
452  if (Colors.Num() == 0)
453  return;
454 
455  check(DoesSectionExist(SectionIndex));
456 
458  const FRuntimeMeshSectionPtr& Section = MeshSections[SectionIndex];
460  TSharedPtr<FRuntimeMeshAccessor> MeshData = Section->GetSectionMeshAccessor();
461 
462  for (int i = 0; i < Colors.Num(); i++)
463  MeshData->SetColor(i, Colors[i]);
464 
465  if (RenderProxy.IsValid())
466  RenderProxy->UpdateSection_GameThread(SectionIndex, Section->GetSectionUpdateData(BuffersToUpdate));
467 
468  const bool bRequireProxyRecreate = Section->GetUpdateFrequency() == EUpdateFrequency::Infrequent;
469  if (bRequireProxyRecreate)
471 
472  MarkChanged();
473 }
474 
475 void FRuntimeMeshData::CreateMeshSection(int32 SectionIndex, const TArray<FVector>& Vertices, const TArray<int32>& Triangles, const TArray<FVector>& Normals,
476  const TArray<FVector2D>& UV0, const TArray<FColor>& Colors, const TArray<FRuntimeMeshTangent>& Tangents, bool bCreateCollision, EUpdateFrequency UpdateFrequency,
477  ESectionUpdateFlags UpdateFlags, bool bUseHighPrecisionTangents, bool bUseHighPrecisionUVs)
478 {
479  CreateMeshSectionFromComponents(SectionIndex, Vertices, Triangles, Normals, UV0, TArray<FVector2D>(), [&Colors](int32 Index) -> FColor { return Colors[Index]; },
480  Colors.Num(), Tangents, bCreateCollision, UpdateFrequency, UpdateFlags, bUseHighPrecisionTangents, bUseHighPrecisionUVs, false);
481 }
482 
483 void FRuntimeMeshData::CreateMeshSection(int32 SectionIndex, const TArray<FVector>& Vertices, const TArray<int32>& Triangles, const TArray<FVector>& Normals,
484  const TArray<FVector2D>& UV0, const TArray<FVector2D>& UV1, const TArray<FColor>& Colors, const TArray<FRuntimeMeshTangent>& Tangents,
485  bool bCreateCollision, EUpdateFrequency UpdateFrequency, ESectionUpdateFlags UpdateFlags, bool bUseHighPrecisionTangents, bool bUseHighPrecisionUVs)
486 {
487  CreateMeshSectionFromComponents(SectionIndex, Vertices, Triangles, Normals, UV0, UV1, [&Colors](int32 Index) -> FColor { return Colors[Index]; },
488  Colors.Num(), Tangents, bCreateCollision, UpdateFrequency, UpdateFlags, bUseHighPrecisionTangents, bUseHighPrecisionUVs, true);
489 }
490 
491 void FRuntimeMeshData::UpdateMeshSection(int32 SectionIndex, const TArray<FVector>& Vertices, const TArray<FVector>& Normals, const TArray<FVector2D>& UV0,
492  const TArray<FColor>& Colors, const TArray<FRuntimeMeshTangent>& Tangents, ESectionUpdateFlags UpdateFlags)
493 {
494  UpdateMeshSectionFromComponents(SectionIndex, Vertices, TArray<int32>(), Normals, UV0, TArray<FVector2D>(),
495  [&Colors](int32 Index) -> FColor { return Colors[Index]; }, Colors.Num(), Tangents, UpdateFlags);
496 }
497 
498 void FRuntimeMeshData::UpdateMeshSection(int32 SectionIndex, const TArray<FVector>& Vertices, const TArray<FVector>& Normals, const TArray<FVector2D>& UV0,
499  const TArray<FVector2D>& UV1, const TArray<FColor>& Colors, const TArray<FRuntimeMeshTangent>& Tangents, ESectionUpdateFlags UpdateFlags)
500 {
501  UpdateMeshSectionFromComponents(SectionIndex, Vertices, TArray<int32>(), Normals, UV0, UV1,
502  [&Colors](int32 Index) -> FColor { return Colors[Index]; }, Colors.Num(), Tangents, UpdateFlags);
503 }
504 
505 void FRuntimeMeshData::UpdateMeshSection(int32 SectionIndex, const TArray<FVector>& Vertices, const TArray<int32>& Triangles, const TArray<FVector>& Normals,
506  const TArray<FVector2D>& UV0, const TArray<FColor>& Colors, const TArray<FRuntimeMeshTangent>& Tangents, ESectionUpdateFlags UpdateFlags)
507 {
508  UpdateMeshSectionFromComponents(SectionIndex, Vertices, Triangles, Normals, UV0, TArray<FVector2D>(),
509  [&Colors](int32 Index) -> FColor { return Colors[Index]; }, Colors.Num(), Tangents, UpdateFlags);
510 }
511 
512 void FRuntimeMeshData::UpdateMeshSection(int32 SectionIndex, const TArray<FVector>& Vertices, const TArray<int32>& Triangles, const TArray<FVector>& Normals,
513  const TArray<FVector2D>& UV0, const TArray<FVector2D>& UV1, const TArray<FColor>& Colors, const TArray<FRuntimeMeshTangent>& Tangents, ESectionUpdateFlags UpdateFlags)
514 {
515  UpdateMeshSectionFromComponents(SectionIndex, Vertices, Triangles, Normals, UV0, UV1,
516  [&Colors](int32 Index) -> FColor { return Colors[Index]; }, Colors.Num(), Tangents, UpdateFlags);
517 }
518 
519 void FRuntimeMeshData::CreateMeshSection_Blueprint(int32 SectionIndex, const TArray<FVector>& Vertices, const TArray<int32>& Triangles, const TArray<FVector>& Normals,
520  const TArray<FRuntimeMeshTangent>& Tangents, const TArray<FVector2D>& UV0, const TArray<FVector2D>& UV1, const TArray<FLinearColor>& VertexColors, bool bCreateCollision,
521  bool bCalculateNormalTangent, bool bShouldCreateHardTangents, bool bGenerateTessellationTriangles, EUpdateFrequency UpdateFrequency, bool bUseHighPrecisionTangents, bool bUseHighPrecisionUVs)
522 {
524  UpdateFlags |= bCalculateNormalTangent && !bShouldCreateHardTangents ? ESectionUpdateFlags::CalculateNormalTangent : ESectionUpdateFlags::None;
525  UpdateFlags |= bShouldCreateHardTangents ? ESectionUpdateFlags::CalculateNormalTangentHard : ESectionUpdateFlags::None;
526  UpdateFlags |= bGenerateTessellationTriangles ? ESectionUpdateFlags::CalculateTessellationIndices : ESectionUpdateFlags::None;
527 
528  CreateMeshSectionFromComponents(SectionIndex, Vertices, Triangles, Normals, UV0, UV1, [&VertexColors](int32 Index) -> FColor { return VertexColors[Index].ToFColor(false); },
529  VertexColors.Num(), Tangents, bCreateCollision, UpdateFrequency, UpdateFlags, bUseHighPrecisionTangents, bUseHighPrecisionUVs, UV1.Num() > 0);
530 }
531 
532 void FRuntimeMeshData::UpdateMeshSection_Blueprint(int32 SectionIndex, const TArray<FVector>& Vertices, const TArray<int32>& Triangles, const TArray<FVector>& Normals, const TArray<FRuntimeMeshTangent>& Tangents,
533  const TArray<FVector2D>& UV0, const TArray<FVector2D>& UV1, const TArray<FLinearColor>& VertexColors, bool bCalculateNormalTangent, bool bShouldCreateHardTangents, bool bGenerateTessellationTriangles)
534 {
536  UpdateFlags |= bCalculateNormalTangent && !bShouldCreateHardTangents ? ESectionUpdateFlags::CalculateNormalTangent : ESectionUpdateFlags::None;
537  UpdateFlags |= bShouldCreateHardTangents ? ESectionUpdateFlags::CalculateNormalTangentHard : ESectionUpdateFlags::None;
538  UpdateFlags |= bGenerateTessellationTriangles ? ESectionUpdateFlags::CalculateTessellationIndices : ESectionUpdateFlags::None;
539 
540  UpdateMeshSectionFromComponents(SectionIndex, Vertices, TArray<int32>(), Normals, UV0, UV1,
541  [&VertexColors](int32 Index) -> FColor { return VertexColors[Index].ToFColor(false); }, VertexColors.Num(), Tangents, UpdateFlags);
542 }
543 
544 
545 
546 void FRuntimeMeshData::CreateMeshSectionPacked_Blueprint(int32 SectionIndex, const TArray<FRuntimeMeshBlueprintVertexSimple>& Vertices, const TArray<int32>& Triangles,
547  bool bCreateCollision, bool bCalculateNormalTangent, bool bShouldCreateHardTangents, bool bGenerateTessellationTriangles, EUpdateFrequency UpdateFrequency, bool bUseHighPrecisionTangents, bool bUseHighPrecisionUVs)
548 {
549  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_CreateMeshSectionPacked_Blueprint);
550 
552 
553  // Create the section
554  auto NewSection = CreateOrResetSectionForBlueprint(SectionIndex, false, bUseHighPrecisionTangents, bUseHighPrecisionUVs, UpdateFrequency);
555 
556  TSharedPtr<FRuntimeMeshAccessor> MeshData = NewSection->GetSectionMeshAccessor();
557 
558  // We base the size of the mesh data off the vertices/positions
559  MeshData->SetNumVertices(Vertices.Num());
560 
561  for (int32 Index = 0; Index < Vertices.Num(); Index++)
562  {
563  MeshData->SetPosition(Index, Vertices[Index].Position);
564  MeshData->SetNormal(Index, Vertices[Index].Normal);
565  MeshData->SetTangent(Index, FVector4(Vertices[Index].Tangent.TangentX, Vertices[Index].Tangent.bFlipTangentY ? -1.0f : 1.0f));
566  MeshData->SetColor(Index, Vertices[Index].Color.ToFColor(false));
567  MeshData->SetUV(Index, 0, Vertices[Index].UV0);
568  }
569 
570  NewSection->UpdateIndexBuffer(Triangles);
571 
572  NewSection->UpdateBoundingBox();
573 
574  // Track collision status and update collision information if necessary
575  NewSection->SetCollisionEnabled(bCreateCollision);
576 
578  UpdateFlags |= bCalculateNormalTangent && !bShouldCreateHardTangents ? ESectionUpdateFlags::CalculateNormalTangent : ESectionUpdateFlags::None;
579  UpdateFlags |= bShouldCreateHardTangents ? ESectionUpdateFlags::CalculateNormalTangentHard : ESectionUpdateFlags::None;
580  UpdateFlags |= bGenerateTessellationTriangles ? ESectionUpdateFlags::CalculateTessellationIndices : ESectionUpdateFlags::None;
581 
582  // Finalize section.
583  CreateSectionInternal(SectionIndex, UpdateFlags);
584 }
585 
586 void FRuntimeMeshData::UpdateMeshSectionPacked_Blueprint(int32 SectionIndex, const TArray<FRuntimeMeshBlueprintVertexSimple>& Vertices, const TArray<int32>& Triangles,
587  bool bCalculateNormalTangent, bool bShouldCreateHardTangents, bool bGenerateTessellationTriangles)
588 {
589  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_UpdateMeshSectionPacked_Blueprint);
590 
592 
593  // We only check stream 0 and 2 since stream 1 can change based on config, this is potentially dangerous to assume but probably not in practice.
594 // CheckUpdate(GetStreamStructure<FVector>(), GetStreamStructure<FRuntimeMeshNullVertex>(), GetStreamStructure<FColor>(), true, SectionIndex, true, true, false, true);
595 
596  FRuntimeMeshSectionPtr& Section = MeshSections[SectionIndex];
597 
599  if (Vertices.Num() > 0)
600  {
602 
603  TSharedPtr<FRuntimeMeshAccessor> MeshData = Section->GetSectionMeshAccessor();
604 
605  // We base the size of the mesh data off the vertices/positions
606  MeshData->SetNumVertices(Vertices.Num());
607 
608  // Copy mesh data
609  for (int32 Index = 0; Index < Vertices.Num(); Index++)
610  {
611  MeshData->SetPosition(Index, Vertices[Index].Position);
612  MeshData->SetNormal(Index, Vertices[Index].Normal);
613  MeshData->SetTangent(Index, FVector4(Vertices[Index].Tangent.TangentX, Vertices[Index].Tangent.bFlipTangentY ? -1.0f : 1.0f));
614  MeshData->SetColor(Index, Vertices[Index].Color.ToFColor(false));
615  MeshData->SetUV(Index, 0, Vertices[Index].UV0);
616  }
617 
618  Section->UpdateBoundingBox();
619  }
620 
621 
622  if (Triangles.Num() > 0)
623  {
624  Section->UpdateIndexBuffer(Triangles);
625  BuffersToUpdate |= ERuntimeMeshBuffersToUpdate::IndexBuffer;
626  }
627 
629  UpdateFlags |= bCalculateNormalTangent && !bShouldCreateHardTangents ? ESectionUpdateFlags::CalculateNormalTangent : ESectionUpdateFlags::None;
630  UpdateFlags |= bShouldCreateHardTangents ? ESectionUpdateFlags::CalculateNormalTangentHard : ESectionUpdateFlags::None;
631  UpdateFlags |= bGenerateTessellationTriangles ? ESectionUpdateFlags::CalculateTessellationIndices : ESectionUpdateFlags::None;
632 
633  // Finalize section.
634  UpdateSectionInternal(SectionIndex, BuffersToUpdate, UpdateFlags);
635 }
636 
637 
638 
639 TSharedPtr<const FRuntimeMeshAccessor> FRuntimeMeshData::GetReadonlyMeshAccessor(int32 SectionId)
640 {
641  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_GetReadonlyMeshAccessor);
642 
644 
645  check(DoesSectionExist(SectionId));
646  FRuntimeMeshSectionPtr Section = MeshSections[SectionId];
647 
648  return ConstCastSharedPtr<const FRuntimeMeshAccessor, FRuntimeMeshAccessor>(Section->GetSectionMeshAccessor());
649 }
650 
652 {
653  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_ClearMeshSection);
654 
656 
657  if (DoesSectionExist(SectionId))
658  {
659  FRuntimeMeshSectionPtr Section = MeshSections[SectionId];
660 
661  bool bHadCollision = Section->IsCollisionEnabled();
662  bool bWasStaticSection = Section->GetUpdateFrequency() == EUpdateFrequency::Infrequent;
663 
664  MeshSections[SectionId].Reset();
665 
666  if (RenderProxy.IsValid())
667  {
668  RenderProxy->DeleteSection_GameThread(SectionId);
669  }
670 
671  // Strip tailing invalid sections
672  int32 LastValidIndex = GetLastSectionIndex();
673  MeshSections.SetNum(LastValidIndex + 1);
674 
677 
678  if (bHadCollision)
679  {
681  }
682  }
683 }
684 
686 {
687  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_ClearAllMeshSections);
688 
690 
691  MeshSections.Empty();
692 
693  if (RenderProxy.IsValid())
694  {
695  RenderProxy->DeleteSection_GameThread(INDEX_NONE);
696  }
697 
701 }
702 
704 {
705  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_GetSectionBoundingBox);
706 
708 
709  if (DoesSectionExist(SectionIndex))
710  {
711  return MeshSections[SectionIndex]->GetBoundingBox();
712  }
713 
714  return FBox();
715 }
716 
717 void FRuntimeMeshData::SetMeshSectionVisible(int32 SectionIndex, bool bNewVisibility)
718 {
719  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_SetMeshSectionVisible);
720 
722 
723  if (DoesSectionExist(SectionIndex))
724  {
725  MeshSections[SectionIndex]->SetVisible(bNewVisibility);
726 
727  // Finish the update
728  UpdateSectionPropertiesInternal(SectionIndex, false);
729  }
730 }
731 
732 bool FRuntimeMeshData::IsMeshSectionVisible(int32 SectionIndex) const
733 {
734  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_IsMeshSectionVisible);
735 
737 
738  if (DoesSectionExist(SectionIndex))
739  {
740  return MeshSections[SectionIndex]->IsVisible();
741  }
742 
743  return false;
744 }
745 
746 
747 void FRuntimeMeshData::SetMeshSectionCastsShadow(int32 SectionIndex, bool bNewCastsShadow)
748 {
749  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_SetMeshSectionCastsShadow);
750 
752 
753  if (DoesSectionExist(SectionIndex))
754  {
755  MeshSections[SectionIndex]->SetCastsShadow(bNewCastsShadow);
756 
757  // Finish the update
758  UpdateSectionPropertiesInternal(SectionIndex, true);
759  }
760 }
761 
762 bool FRuntimeMeshData::IsMeshSectionCastingShadows(int32 SectionIndex) const
763 {
764  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_IsMeshSectionCastingShadows);
765 
767 
768  if (DoesSectionExist(SectionIndex))
769  {
770  return MeshSections[SectionIndex]->CastsShadow();
771  }
772 
773  return false;
774 }
775 
776 
777 void FRuntimeMeshData::SetMeshSectionCollisionEnabled(int32 SectionIndex, bool bNewCollisionEnabled)
778 {
779  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_SetMeshSectionCollisionEnabled);
780 
782 
783  if (DoesSectionExist(SectionIndex))
784  {
785  bool bWasCollisionEnabled = MeshSections[SectionIndex]->IsCollisionEnabled();
786 
787  if (bWasCollisionEnabled != bNewCollisionEnabled)
788  {
789  MeshSections[SectionIndex]->SetCollisionEnabled(bNewCollisionEnabled);
790 
792  }
793  }
794 }
795 
797 {
798  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_IsMeshSectionCollisionEnabled);
799 
801 
802  if (DoesSectionExist(SectionIndex))
803  {
804  return MeshSections[SectionIndex]->IsCollisionEnabled();
805  }
806 
807  return false;
808 }
809 
810 
812 {
814 
815  return MeshSections.Num();
816 }
817 
818 bool FRuntimeMeshData::DoesSectionExist(int32 SectionIndex) const
819 {
821 
822  return MeshSections.IsValidIndex(SectionIndex) && MeshSections[SectionIndex].IsValid();
823 }
824 
826 {
827  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_GetAvailableSectionIndex);
828 
830 
831  // TODO: Make this faster. We could do this by tracking a minimum index to search from.
832  for (int32 Index = 0; Index < 10000; Index++)
833  {
834  if (!DoesSectionExist(Index))
835  {
836  return Index;
837  }
838  }
839  return INDEX_NONE;
840 }
841 
842 
844 {
845  for (int32 Index = MeshSections.Num() - 1; Index >= 0; Index--)
846  {
847  if (MeshSections[Index].IsValid())
848  {
849  return Index;
850  }
851  }
852  return INDEX_NONE;
853 }
854 
855 TArray<int32> FRuntimeMeshData::GetSectionIds() const
856 {
857  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_GetSectionIds);
858 
860 
861  TArray<int32> Sections;
862  for (int32 SectionId = 0; SectionId < MeshSections.Num(); SectionId++)
863  {
864  if (MeshSections[SectionId].IsValid())
865  {
866  Sections.Add(SectionId);
867  }
868  }
869  return Sections;
870 }
871 
872 
873 
874 void FRuntimeMeshData::SetMeshCollisionSection(int32 CollisionSectionIndex, const TArray<FVector>& Vertices, const TArray<int32>& Triangles)
875 {
876  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_SetMeshCollisionSection);
877 
879 
880  auto& Section = MeshCollisionSections.FindOrAdd(CollisionSectionIndex);
881 
882  Section.VertexBuffer = Vertices;
883  Section.IndexBuffer = Triangles;
884 
886 }
887 
888 void FRuntimeMeshData::ClearMeshCollisionSection(int32 CollisionSectionIndex)
889 {
890  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_ClearMeshCollisionSection);
891 
893 
894  MeshCollisionSections.Remove(CollisionSectionIndex);
895 
897 }
898 
900 {
901  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_ClearAllMeshCollisionSections);
902 
904 
905  MeshCollisionSections.Empty();
906 
908 }
909 
910 
911 int32 FRuntimeMeshData::AddConvexCollisionSection(TArray<FVector> ConvexVerts)
912 {
913  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_AddConvexCollisionSection);
914 
916 
917  int32 NewIndex = 0;
918  while (ConvexCollisionSections.Contains(NewIndex))
919  {
920  NewIndex++;
921  }
922 
923  auto& Section = ConvexCollisionSections.Add(NewIndex);
924 
925  Section.VertexBuffer = ConvexVerts;
926  Section.BoundingBox = FBox(ConvexVerts);
927 
929 
930  return NewIndex;
931 }
932 
933 void FRuntimeMeshData::SetConvexCollisionSection(int32 ConvexSectionIndex, TArray<FVector> ConvexVerts)
934 {
935  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_SetConvexCollisionSection);
936 
938 
939  auto& Section = ConvexCollisionSections.FindOrAdd(ConvexSectionIndex);
940 
941  Section.VertexBuffer = ConvexVerts;
942  Section.BoundingBox = FBox(ConvexVerts);
943 
945 }
946 
948 {
949  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_ClearConvexCollisionSection);
950 
952 
953  // Empty simple collision info
954  ConvexCollisionSections.Remove(ConvexSectionIndex);
955 
957 }
958 
960 {
961  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_ClearAllConvexCollisionSections);
962 
964 
965  ConvexCollisionSections.Empty();
966 
968 }
969 
970 void FRuntimeMeshData::SetCollisionConvexMeshes(const TArray<TArray<FVector>>& ConvexMeshes)
971 {
972  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_ClearAllConvexCollisionSections);
973 
975 
976  ConvexCollisionSections.Empty();
977 
978  int32 Index = 0;
979  for (const auto& Convex : ConvexMeshes)
980  {
981  auto& Section = ConvexCollisionSections.FindOrAdd(Index++);
982 
983  Section.VertexBuffer = Convex;
984  Section.BoundingBox = FBox(Convex);
985  }
986 
988 }
989 
990 
991 
993 {
995  int32 NewIndex = CollisionBoxes.Add(NewBox);
997  return NewIndex;
998 }
999 
1001 {
1003  CollisionBoxes.RemoveAt(Index);
1005 }
1006 
1008 {
1010  CollisionBoxes.Empty();
1012 }
1013 
1014 void FRuntimeMeshData::SetCollisionBoxes(const TArray<FRuntimeMeshCollisionBox>& NewBoxes)
1015 {
1017  CollisionBoxes = NewBoxes;
1019 }
1020 
1022 {
1024  int32 NewIndex = CollisionSpheres.Add(NewSphere);
1026  return NewIndex;
1027 }
1028 
1030 {
1032  CollisionSpheres.RemoveAt(Index);
1034 }
1035 
1037 {
1039  CollisionSpheres.Empty();
1041 }
1042 
1043 void FRuntimeMeshData::SetCollisionSpheres(const TArray<FRuntimeMeshCollisionSphere>& NewSpheres)
1044 {
1046  CollisionSpheres = NewSpheres;
1048 }
1049 
1051 {
1053  int32 NewIndex = CollisionCapsules.Add(NewCapsule);
1055  return NewIndex;
1056 }
1057 
1059 {
1061  CollisionCapsules.RemoveAt(Index);
1063 }
1064 
1066 {
1068  CollisionCapsules.Empty();
1070 }
1071 
1072 void FRuntimeMeshData::SetCollisionCapsules(const TArray<FRuntimeMeshCollisionCapsule>& NewCapsules)
1073 {
1075 
1076  CollisionCapsules = NewCapsules;
1078 }
1079 
1080 FBoxSphereBounds FRuntimeMeshData::GetLocalBounds() const
1081 {
1082  FRuntimeMeshScopeLock Lock(SyncRoot, false, true);
1083  return LocalBounds;
1084 }
1085 
1086 FRuntimeMeshSectionPtr FRuntimeMeshData::CreateOrResetSection(int32 SectionId, bool bInUseHighPrecisionTangents, bool bInUseHighPrecisionUVs,
1087  int32 InNumUVs, bool b32BitIndices, EUpdateFrequency UpdateFrequency)
1088 {
1089  // Create new section
1090  FRuntimeMeshSectionPtr NewSection = MakeShared<FRuntimeMeshSection, ESPMode::ThreadSafe>(bInUseHighPrecisionTangents, bInUseHighPrecisionUVs, InNumUVs, b32BitIndices, UpdateFrequency/*, LockFactory()*/);
1091 
1092  // Store section at index
1093  if (MeshSections.Num() <= SectionId)
1094  {
1095  MeshSections.SetNum(SectionId + 1);
1096  }
1097  MeshSections[SectionId] = NewSection;
1098 
1099  return NewSection;
1100 }
1101 
1102 FRuntimeMeshSectionPtr FRuntimeMeshData::CreateOrResetSectionForBlueprint(int32 SectionId, bool bWantsSecondUV, bool bHighPrecisionTangents, bool bHighPrecisionUVs, EUpdateFrequency UpdateFrequency)
1103 {
1104  return CreateOrResetSection(SectionId, bHighPrecisionTangents, bHighPrecisionUVs, bWantsSecondUV? 2 : 1, true, UpdateFrequency);
1105 }
1106 
1107 
1108 
1109 
1111 {
1112  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_CreateSectionInternal);
1113 
1114  check(DoesSectionExist(SectionId));
1115  FRuntimeMeshSectionPtr Section = MeshSections[SectionId];
1116 
1117  // Send section creation to render thread
1118  if (RenderProxy.IsValid())
1119  {
1120  RenderProxy->CreateSection_GameThread(SectionId, Section->GetSectionCreationParams());
1121  }
1122 
1123  // Update the combined local bounds
1125 
1126  // Do any additional processing on the section for this update.
1127  ERuntimeMeshBuffersToUpdate BuffersToUpdate; // This is ignored for creation as all buffers are updated.
1128  HandleCommonSectionUpdateFlags(SectionId, UpdateFlags, BuffersToUpdate);
1129 
1130 
1131  // Send the section creation notification to all linked RMC's
1132  DoOnGameThread(FRuntimeMeshGameThreadTaskDelegate::CreateLambda(
1133  [SectionId](URuntimeMesh* Mesh)
1134  {
1135  Mesh->SendSectionCreation(SectionId);
1136  }));
1137 
1138  // Update collision if necessary
1139  if (Section->IsCollisionEnabled())
1140  {
1141  MarkCollisionDirty(true);
1142  }
1143 
1144  MarkChanged();
1145 }
1146 
1148 {
1149  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_UpdateSectionInternal);
1150 
1151  check(DoesSectionExist(SectionId));
1152  FRuntimeMeshSectionPtr Section = MeshSections[SectionId];
1153 
1154  // Send section update to render thread
1155  if (RenderProxy.IsValid())
1156  {
1157  RenderProxy->UpdateSection_GameThread(SectionId, Section->GetSectionUpdateData(BuffersToUpdate));
1158  }
1159 
1160  // Update the combined local bounds
1162 
1163  // Do any additional processing on the section for this update.
1164  HandleCommonSectionUpdateFlags(SectionId, UpdateFlags, BuffersToUpdate);
1165 
1166  bool bRequireProxyRecreate = Section->GetUpdateFrequency() == EUpdateFrequency::Infrequent;
1167  if (bRequireProxyRecreate)
1168  {
1169  // Send the section creation notification to all linked RMC's
1170 
1172  }
1173 
1174  // Update collision if necessary
1175  if (Section->IsCollisionEnabled())
1176  {
1177  MarkCollisionDirty(true);
1178  }
1179 
1180  MarkChanged();
1181 }
1182 
1184 {
1185  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_HandleCommonSectionUpdateFlags);
1186 
1187  check(DoesSectionExist(SectionIndex));
1188 
1189  FRuntimeMeshSectionPtr Section = MeshSections[SectionIndex];
1190 
1192  {
1193  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_HandleCommonSectionUpdateFlags_CalculateTangents);
1194  URuntimeMeshLibrary::CalculateTangentsForMesh(Section->GetSectionMeshAccessor(), !(UpdateFlags & ESectionUpdateFlags::CalculateNormalTangentHard));
1196  }
1197 
1199  {
1200  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_HandleCommonSectionUpdateFlags_CalculateTessellationIndices);
1201  URuntimeMeshLibrary::GenerateTessellationIndexBuffer(Section->GetSectionMeshAccessor(), Section->GetTessellationIndexAccessor());
1203  }
1204 }
1205 
1206 void FRuntimeMeshData::UpdateSectionPropertiesInternal(int32 SectionIndex, bool bUpdateRequiresProxyRecreateIfStatic)
1207 {
1208  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_UpdateSectionPropertiesInternal);
1209 
1210  check(DoesSectionExist(SectionIndex));
1211  FRuntimeMeshSectionPtr Section = MeshSections[SectionIndex];
1212 
1213  if (RenderProxy.IsValid())
1214  {
1215  RenderProxy->UpdateSectionProperties_GameThread(SectionIndex, Section->GetSectionPropertyUpdateData());
1216  }
1217 
1218  bool bRequiresRecreate = bUpdateRequiresProxyRecreateIfStatic &&
1219  Section->GetUpdateFrequency() == EUpdateFrequency::Infrequent;
1220 
1221  if (bRequiresRecreate)
1222  {
1224  }
1225  else
1226  {
1227  SendSectionPropertiesUpdate(SectionIndex);
1228  }
1229 
1230  MarkChanged();
1231 }
1232 
1234 {
1235  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_UpdateLocalBounds);
1236 
1237  FBox LocalBox(EForceInit::ForceInitToZero);
1238 
1239  for (int32 SectionId = 0; SectionId < MeshSections.Num(); SectionId++)
1240  {
1241  FRuntimeMeshSectionPtr Section = MeshSections[SectionId];
1242  if (Section.IsValid() && Section->ShouldRender())
1243  {
1244  LocalBox += Section->GetBoundingBox();
1245  }
1246  }
1247 
1248  LocalBounds = LocalBox.IsValid ? FBoxSphereBounds(LocalBox) :
1249  FBoxSphereBounds(FVector(0, 0, 0), FVector(0, 0, 0), 0); // fall back to reset box sphere bounds
1250 
1251  DoOnGameThread(FRuntimeMeshGameThreadTaskDelegate::CreateLambda(
1252  [](URuntimeMesh* Mesh)
1253  {
1254  Mesh->UpdateLocalBounds();
1255  }));
1256 }
1257 
1259 {
1260  if (!RenderProxy.IsValid())
1261  {
1263  Initialize();
1264  }
1265 
1266  // Sanity check that all RMC's are on the same feature level. Not sure any reason they wouldn't be.
1267  check(RenderProxy->GetFeatureLevel() == InFeatureLevel);
1268 
1269  return RenderProxy;
1270 }
1271 
1272 
1273 
1274 
1276 {
1277  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_Initialize);
1278 
1279  check(RenderProxy.IsValid());
1280  for (int32 SectionId = 0; SectionId < MeshSections.Num(); SectionId++)
1281  {
1282  if (MeshSections[SectionId].IsValid())
1283  {
1284  RenderProxy->CreateSection_GameThread(SectionId, MeshSections[SectionId]->GetSectionCreationParams());
1285  }
1286  }
1287 }
1288 
1289 bool FRuntimeMeshData::ContainsPhysicsTriMeshData(bool InUseAllTriData) const
1290 {
1291  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_ContainsPhysicsTriMeshData);
1292 
1294 
1295  for (int32 SectionId = 0; SectionId < MeshSections.Num(); SectionId++)
1296  {
1297  FRuntimeMeshSectionPtr Section = MeshSections[SectionId];
1298  if (Section.IsValid() && Section->HasValidMeshData() && Section->IsCollisionEnabled())
1299  {
1300  return true;
1301  }
1302  }
1303 
1304  for (const auto& Section : MeshCollisionSections)
1305  {
1306  if (Section.Value.VertexBuffer.Num() > 0 && Section.Value.IndexBuffer.Num() > 0)
1307  {
1308  return true;
1309  }
1310  }
1311 
1312  return false;
1313 }
1314 
1315 bool FRuntimeMeshData::GetPhysicsTriMeshData(struct FTriMeshCollisionData* CollisionData, bool InUseAllTriData)
1316 {
1317  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_GetPhysicsTriMeshData);
1318 
1320 
1321  // Base vertex index for current section
1322 
1323  bool bHadCollision = false;
1324 
1325  // See if we should copy UVs
1326  bool bCopyUVs = UPhysicsSettings::Get()->bSupportUVFromHitResults;
1327 
1328  for (int32 SectionId = 0; SectionId < MeshSections.Num(); SectionId++)
1329  {
1330  if (MeshSections[SectionId].IsValid() && MeshSections[SectionId]->IsCollisionEnabled())
1331  {
1332  TArray<FVector2D> UVs;
1333  int32 NumTriangles = MeshSections[SectionId]->GetCollisionData(CollisionData->Vertices, CollisionData->Indices, UVs);
1334 
1335  if (bCopyUVs)
1336  {
1337  CollisionData->UVs.Add(MoveTemp(UVs));
1338  }
1339 
1340  for (int32 Index = 0; Index < NumTriangles; Index++)
1341  {
1342  CollisionData->MaterialIndices.Add(SectionId);
1343  }
1344 
1345  // Update the vertex base index
1346  bHadCollision = true;
1347  }
1348  }
1349 
1350  int32 VertexBase = CollisionData->Vertices.Num();
1351 
1352  for (const auto& SectionEntry : MeshCollisionSections)
1353  {
1354  const auto& Section = SectionEntry.Value;
1355  if (Section.VertexBuffer.Num() > 0 && Section.IndexBuffer.Num() > 0)
1356  {
1357  CollisionData->Vertices.Append(Section.VertexBuffer);
1358 
1359  const int32 NumTriangles = Section.IndexBuffer.Num() / 3;
1360  for (int32 TriIdx = 0; TriIdx < NumTriangles; TriIdx++)
1361  {
1362  // Add the triangle
1363  FTriIndices& Triangle = *new (CollisionData->Indices) FTriIndices;
1364  Triangle.v0 = Section.IndexBuffer[(TriIdx * 3) + 0] + VertexBase;
1365  Triangle.v1 = Section.IndexBuffer[(TriIdx * 3) + 1] + VertexBase;
1366  Triangle.v2 = Section.IndexBuffer[(TriIdx * 3) + 2] + VertexBase;
1367 
1368  // Add material info
1369  CollisionData->MaterialIndices.Add(SectionEntry.Key);
1370  }
1371 
1372 
1373  VertexBase = CollisionData->Vertices.Num();
1374  bHadCollision = true;
1375  }
1376  }
1377 
1378  CollisionData->bFlipNormals = true;
1379 
1380  return bHadCollision;
1381 }
1382 
1384 {
1385  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_CopyCollisionElementsToBodySetup);
1386 
1388 
1389  check(IsInGameThread());
1390 
1391  auto& ConvexElems = Setup->AggGeom.ConvexElems;
1392  ConvexElems.Empty();
1393  for (const auto& Section : ConvexCollisionSections)
1394  {
1395  FKConvexElem& NewConvexElem = *new(ConvexElems) FKConvexElem();
1396  NewConvexElem.VertexData = Section.Value.VertexBuffer;
1397  // TODO: Store this on the section so we don't have to compute it on each cook
1398  NewConvexElem.ElemBox = Section.Value.BoundingBox;
1399  }
1400 
1401  auto& BoxElems = Setup->AggGeom.BoxElems;
1402  BoxElems.Empty();
1403  for (const FRuntimeMeshCollisionBox& Box : CollisionBoxes)
1404  {
1405  FKBoxElem& NewBox = *new(BoxElems) FKBoxElem();
1406  NewBox.Center = Box.Center;
1407  NewBox.Rotation = Box.Rotation;
1408  NewBox.X = Box.Extents.X;
1409  NewBox.Y = Box.Extents.Y;
1410  NewBox.Z = Box.Extents.Z;
1411  }
1412 
1413  auto& SphereElems = Setup->AggGeom.SphereElems;
1414  SphereElems.Empty();
1415  for (const FRuntimeMeshCollisionSphere& Sphere : CollisionSpheres)
1416  {
1417  FKSphereElem& NewSphere = *new(SphereElems)FKSphereElem();
1418  NewSphere.Center = Sphere.Center;
1419  NewSphere.Radius = Sphere.Radius;
1420  }
1421 
1422  auto& SphylElems = Setup->AggGeom.SphylElems;
1423  SphylElems.Empty();
1424  for (const FRuntimeMeshCollisionCapsule& Capsule : CollisionCapsules)
1425  {
1426  FKSphylElem& NewSphyl = *new(SphylElems)FKSphylElem();
1427  NewSphyl.Center = Capsule.Center;
1428  NewSphyl.Rotation = Capsule.Rotation;
1429  NewSphyl.Radius = Capsule.Radius;
1430  NewSphyl.Length = Capsule.Length;
1431  }
1432 }
1433 
1434 void FRuntimeMeshData::MarkCollisionDirty(bool bSkipChangedFlag)
1435 {
1436  if (bSkipChangedFlag)
1437  {
1438  DoOnGameThread(FRuntimeMeshGameThreadTaskDelegate::CreateLambda(
1439  [](URuntimeMesh* Mesh)
1440  {
1441  Mesh->MarkCollisionDirty();
1442  }));
1443  }
1444  else
1445  {
1446  DoOnGameThread(FRuntimeMeshGameThreadTaskDelegate::CreateLambda(
1447  [](URuntimeMesh* Mesh)
1448  {
1449  Mesh->MarkCollisionDirty();
1450  Mesh->MarkChanged();
1451  }));
1452  }
1453 }
1454 
1455 
1457 {
1458  DoOnGameThread(FRuntimeMeshGameThreadTaskDelegate::CreateLambda(
1459  [](URuntimeMesh* Mesh)
1460  {
1461  Mesh->ForceProxyRecreate();
1462  }));
1463 }
1464 
1466 {
1467  DoOnGameThread(FRuntimeMeshGameThreadTaskDelegate::CreateLambda(
1468  [SectionIndex](URuntimeMesh* Mesh)
1469  {
1470  Mesh->SendSectionPropertiesUpdate(SectionIndex);
1471  }));
1472 }
1473 
1475 {
1476  int32 FaceIdx = FaceIndex;
1477 
1479 }
1480 /*
1481 * Gets the section ID from the given face index reference,
1482 * The face index reference then gets set to it's face index in the section.
1483 */
1485 {
1486  SCOPE_CYCLE_COUNTER(STAT_RuntimeMesh_GetSectionFromCollisionFaceIndex);
1487 
1489 
1490  int32 SectionIndex = 0;
1491 
1492  // Look for element that corresponds to the supplied face
1493  int32 TotalFaceCount = 0;
1494 
1495  for (int32 SectionIdx = 0; SectionIdx < MeshSections.Num(); SectionIdx++)
1496  {
1497  const FRuntimeMeshSectionPtr& Section = MeshSections[SectionIdx];
1498 
1499  if (Section.IsValid() && Section->IsCollisionEnabled())
1500  {
1501 
1502  int32 NumFaces = Section->GetNumIndices() / 3;
1503 
1504  if (FaceIndex < TotalFaceCount + NumFaces)
1505  {
1506  // Grab the material
1507  SectionIndex = SectionIdx;
1508  FaceIndex -= TotalFaceCount;
1509  break;
1510  }
1511  TotalFaceCount += NumFaces;
1512  }
1513  }
1514  return SectionIndex;
1515 }
1516 
1518 {
1519  TWeakObjectPtr<URuntimeMesh> RuntimeMesh;
1520  FRuntimeMeshGameThreadTaskDelegate Delegate;
1521 public:
1522 
1523  FRuntimeMeshGameThreadTask(TWeakObjectPtr<URuntimeMesh> InRuntimeMesh, FRuntimeMeshGameThreadTaskDelegate InDelegate)
1524  : RuntimeMesh(InRuntimeMesh), Delegate(InDelegate)
1525  {
1526  }
1527 
1528  FORCEINLINE TStatId GetStatId() const
1529  {
1530  RETURN_QUICK_DECLARE_CYCLE_STAT(FRuntimeMeshGameThreadTask, STATGROUP_TaskGraphTasks);
1531  }
1532 
1534  {
1535  return ENamedThreads::GameThread;
1536  }
1537 
1539  {
1540  return ESubsequentsMode::FireAndForget;
1541  }
1542 
1543  void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
1544  {
1545  if (URuntimeMesh* Comp = RuntimeMesh.Get())
1546  {
1547  Delegate.Execute(Comp);
1548  }
1549  }
1550 };
1551 
1552 
1553 void FRuntimeMeshData::DoOnGameThread(FRuntimeMeshGameThreadTaskDelegate Func)
1554 {
1555  if (IsInGameThread())
1556  {
1557  if (URuntimeMesh* Comp = ParentMeshObject.Get())
1558  {
1559  Func.Execute(Comp);
1560  }
1561  else
1562  {
1563  check(false);
1564  }
1565  }
1566  else
1567  {
1568  TGraphTask<FRuntimeMeshGameThreadTask>::CreateTask().ConstructAndDispatchWhenReady(ParentMeshObject, Func);
1569  }
1570 }
1571 
1573 {
1574 #if WITH_EDITOR
1575  DoOnGameThread(FRuntimeMeshGameThreadTaskDelegate::CreateLambda([](URuntimeMesh* Mesh)
1576  {
1577  Mesh->MarkChanged();
1578  }));
1579 #endif
1580 }
void EndSectionUpdate(FRuntimeMeshScopedUpdater *Updater, ERuntimeMeshBuffersToUpdate BuffersToUpdate, const FBox *BoundingBox=nullptr)
FRuntimeMeshSectionPtr CreateOrResetSection(int32 SectionId, EUpdateFrequency UpdateFrequency)
void CreateMeshSection_Blueprint(int32 SectionIndex, const TArray< FVector > &Vertices, const TArray< int32 > &Triangles, const TArray< FVector > &Normals, const TArray< FRuntimeMeshTangent > &Tangents, const TArray< FVector2D > &UV0, const TArray< FVector2D > &UV1, const TArray< FLinearColor > &Colors, bool bCreateCollision=false, bool bCalculateNormalTangent=false, bool bShouldCreateHardTangents=false, bool bGenerateTessellationTriangles=false, EUpdateFrequency UpdateFrequency=EUpdateFrequency::Average, bool bUseHighPrecisionTangents=false, bool bUseHighPrecisionUVs=true)
void RemoveCollisionSphere(int32 Index)
static ESubsequentsMode::Type GetSubsequentsMode()
void CreateMeshSection(int32 SectionIndex, bool bWantsHighPrecisionTangents, bool bWantsHighPrecisionUVs, int32 NumUVs, bool bWants32BitIndices, bool bCreateCollision, EUpdateFrequency UpdateFrequency=EUpdateFrequency::Average)
TArray< FRuntimeMeshCollisionBox > CollisionBoxes
void CopyCollisionElementsToBodySetup(UBodySetup *Setup)
bool GetPhysicsTriMeshData(struct FTriMeshCollisionData *CollisionData, bool InUseAllTriData)
void UpdateMeshSectionPacked_Blueprint(int32 SectionIndex, const TArray< FRuntimeMeshBlueprintVertexSimple > &Vertices, const TArray< int32 > &Triangles, bool bCalculateNormalTangent=false, bool bShouldCreateHardTangents=false, bool bGenerateTessellationTriangles=false)
void UpdateMeshSection_Blueprint(int32 SectionIndex, const TArray< FVector > &Vertices, const TArray< int32 > &Triangles, const TArray< FVector > &Normals, const TArray< FRuntimeMeshTangent > &Tangents, const TArray< FVector2D > &UV0, const TArray< FVector2D > &UV1, const TArray< FLinearColor > &Colors, bool bCalculateNormalTangent=false, bool bShouldCreateHardTangents=false, bool bGenerateTessellationTriangles=false)
TSharedPtr< const FRuntimeMeshAccessor > GetReadonlyMeshAccessor(int32 SectionId)
void ClearConvexCollisionSections()
void UpdateMeshSectionFromComponents(int32 SectionIndex, const TArray< FVector > &Vertices, const TArray< int32 > &Triangles, const TArray< FVector > &Normals, const TArray< FVector2D > &UV0, const TArray< FVector2D > &UV1, TFunction< FColor(int32 Index)> ColorAccessor, int32 NumColors, const TArray< FRuntimeMeshTangent > &Tangents, ESectionUpdateFlags UpdateFlags)
void CheckCreate(int32 NumUVs, bool bIndexIsValid) const
FBox GetSectionBoundingBox(int32 SectionIndex)
void DoOnGameThread(FRuntimeMeshGameThreadTaskDelegate Func)
ESectionUpdateFlags UpdateFlags
void MarkCollisionDirty()
int32 GetSectionAndFaceFromCollisionFaceIndex(int32 &FaceIndex) const
void SendSectionCreation(int32 SectionIndex)
EUpdateFrequency
void ClearMeshCollisionSection(int32 CollisionSectionIndex)
void HandleCommonSectionUpdateFlags(int32 SectionIndex, ESectionUpdateFlags UpdateFlags, ERuntimeMeshBuffersToUpdate &BuffersToUpdate)
FRuntimeMeshVertexStreamStructureElement Position
void MarkCollisionDirty(bool bSkipChangedFlag=false)
void UpdateSectionPropertiesInternal(int32 SectionIndex, bool bUpdateRequiresProxyRecreateIfStatic)
bool IsMeshSectionCollisionEnabled(int32 SectionIndex)
void SetMeshSectionVisible(int32 SectionIndex, bool bNewVisibility)
TUniquePtr< FRuntimeMeshScopedUpdater > BeginSectionUpdate(int32 SectionId, ESectionUpdateFlags UpdateFlags=ESectionUpdateFlags::None)
TArray< FRuntimeMeshSectionPtr > MeshSections
void UpdateMeshSectionByMove(int32 SectionId, const TSharedPtr< FRuntimeMeshBuilder > &MeshData, ESectionUpdateFlags UpdateFlags=ESectionUpdateFlags::None)
TWeakObjectPtr< URuntimeMesh > RuntimeMesh
FRuntimeMeshProxyPtr RenderProxy
void SetCollisionSpheres(const TArray< FRuntimeMeshCollisionSphere > &NewSpheres)
bool DoesSectionExist(int32 SectionIndex) const
TUniquePtr< FRuntimeMeshScopedUpdater > GetSectionReadonly(int32 SectionId)
GLdouble f
void UpdateLocalBounds()
int32 GetAvailableSectionIndex() const
TWeakObjectPtr< URuntimeMesh > ParentMeshObject
int32 AddCollisionCapsule(const FRuntimeMeshCollisionCapsule &NewCapsule)
int32 AddConvexCollisionSection(TArray< FVector > ConvexVerts)
void SetMeshSectionCollisionEnabled(int32 SectionIndex, bool bNewCollisionEnabled)
FRuntimeMeshGameThreadTaskDelegate Delegate
int32 AddCollisionBox(const FRuntimeMeshCollisionBox &NewBox)
void RemoveCollisionBox(int32 Index)
static bool ValidTripleStream(const FRuntimeMeshVertexStreamStructure &Stream1, const FRuntimeMeshVertexStreamStructure &Stream2, const FRuntimeMeshVertexStreamStructure &Stream3)
bool IsMeshSectionVisible(int32 SectionIndex) const
void SetMeshCollisionSection(int32 CollisionSectionIndex, const TArray< FVector > &Vertices, const TArray< int32 > &Triangles)
int32 GetNumSections() const
int32 GetSectionFromCollisionFaceIndex(int32 FaceIndex) const
TArray< FRuntimeMeshCollisionCapsule > CollisionCapsules
static void CalculateTangentsForMesh(const TArray< FVector > &Vertices, const TArray< int32 > &Triangles, TArray< FVector > &Normals, const TArray< FVector2D > &UVs, TArray< FRuntimeMeshTangent > &Tangents, bool bCreateSmoothNormals=true)
void UpdateSectionInternal(int32 SectionIndex, ERuntimeMeshBuffersToUpdate BuffersToUpdate, ESectionUpdateFlags UpdateFlags)
UTexture2D * Get(TUniquePtr< T > &Dtex)
static const textual_icon check
Definition: model-views.h:260
bool ContainsPhysicsTriMeshData(bool InUseAllTriData) const
void CheckCreateLegacyInternal(const FRuntimeMeshVertexStreamStructure &Stream0Structure, const FRuntimeMeshVertexStreamStructure &Stream1Structure, const FRuntimeMeshVertexStreamStructure &Stream2Structure, bool bIsIndexValid) const
ESectionUpdateFlags
bool IsMeshSectionCastingShadows(int32 SectionIndex) const
FRuntimeMeshGameThreadTask(TWeakObjectPtr< URuntimeMesh > InRuntimeMesh, FRuntimeMeshGameThreadTaskDelegate InDelegate)
void CheckUpdate(bool bUseHighPrecisionTangents, bool bUseHighPrecisionUVs, int32 NumUVs, bool b32BitIndices, int32 SectionIndex, bool bShouldCheckIndexType, bool bCheckTangentVertexStream, bool bCheckUVVertexStream) const
void UpdateMeshSection(int32 SectionId, TArray< VertexType0 > &InVertices0, ESectionUpdateFlags UpdateFlags=ESectionUpdateFlags::None)
TArray< int32 > GetSectionIds() const
struct Index Index
Definition: sqlite3.c:11789
TArray< FRuntimeMeshCollisionSphere > CollisionSpheres
TMap< int32, FRuntimeMeshCollisionConvexMesh > ConvexCollisionSections
void CreateMeshSectionByMove(int32 SectionId, const TSharedPtr< FRuntimeMeshBuilder > &MeshData, bool bCreateCollision=false, EUpdateFrequency UpdateFrequency=EUpdateFrequency::Average, ESectionUpdateFlags UpdateFlags=ESectionUpdateFlags::None)
TSharedPtr< FRuntimeMeshProxy, ESPMode::ThreadSafe > FRuntimeMeshProxyPtr
void CreateSectionInternal(int32 SectionIndex, ESectionUpdateFlags UpdateFlags)
void ClearMeshSection(int32 SectionIndex)
void CreateMeshSectionPacked_Blueprint(int32 SectionIndex, const TArray< FRuntimeMeshBlueprintVertexSimple > &Vertices, const TArray< int32 > &Triangles, bool bCreateCollision=false, bool bCalculateNormalTangent=false, bool bShouldCreateHardTangents=false, bool bGenerateTessellationTriangles=false, EUpdateFrequency UpdateFrequency=EUpdateFrequency::Average, bool bUseHighPrecisionTangents=false, bool bUseHighPrecisionUVs=true)
void SetConvexCollisionSection(int32 ConvexSectionIndex, TArray< FVector > ConvexVerts)
void RemoveConvexCollisionSection(int32 ConvexSectionIndex)
FRuntimeMeshProxyPtr EnsureProxyCreated(ERHIFeatureLevel::Type InFeatureLevel)
DECLARE_CYCLE_STAT(TEXT("RM - Validation - Create"), STAT_RuntimeMesh_CheckCreate, STATGROUP_RuntimeMesh)
void CheckBoundingBox(const FBox &Box) const
void SetCollisionConvexMeshes(const TArray< TArray< FVector >> &ConvexMeshes)
TMap< int32, FRuntimeMeshCollisionSection > MeshCollisionSections
int32 GetLastSectionIndex() const
ERuntimeMeshBuffersToUpdate
void Setup(TWeakObjectPtr< URuntimeMesh > InParentMeshObject)
int32 AddCollisionSphere(const FRuntimeMeshCollisionSphere &NewSphere)
void SetCollisionCapsules(const TArray< FRuntimeMeshCollisionCapsule > &NewCapsules)
void ClearAllMeshCollisionSections()
FORCEINLINE TStatId GetStatId() const
void CreateMeshSectionFromComponents(int32 SectionIndex, const TArray< FVector > &Vertices, const TArray< int32 > &Triangles, const TArray< FVector > &Normals, const TArray< FVector2D > &UV0, const TArray< FVector2D > &UV1, TFunction< FColor(int32 Index)> ColorAccessor, int32 NumColors, const TArray< FRuntimeMeshTangent > &Tangents, bool bCreateCollision, EUpdateFrequency UpdateFrequency, ESectionUpdateFlags UpdateFlags, bool bUseHighPrecisionTangents, bool bUseHighPrecisionUVs, bool bWantsSecondUV)
int i
void ForceProxyRecreate()
virtual void MarkChanged()
Definition: RuntimeMesh.h:850
void SendSectionPropertiesUpdate(int32 SectionIndex)
void UpdateMeshSectionColors(int32 SectionIndex, TArray< FColor > &Colors, ESectionUpdateFlags UpdateFlags=ESectionUpdateFlags::None)
static ENamedThreads::Type GetDesiredThread()
TSharedPtr< FRuntimeMeshSection, ESPMode::ThreadSafe > FRuntimeMeshSectionPtr
FBoxSphereBounds GetLocalBounds() const
void SendSectionPropertiesUpdate(int32 SectionIndex)
void SetMeshSectionCastsShadow(int32 SectionIndex, bool bNewCastsShadow)
FRuntimeMeshSectionPtr CreateOrResetSectionForBlueprint(int32 SectionId, bool bWantsSecondUV, bool bHighPrecisionTangents, bool bHighPrecisionUVs, EUpdateFrequency UpdateFrequency)
void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef &MyCompletionGraphEvent)
void RemoveCollisionCapsule(int32 Index)
void SetCollisionBoxes(const TArray< FRuntimeMeshCollisionBox > &NewBoxes)
TUniquePtr< FRuntimeMeshLockProvider > SyncRoot
static TArray< int32 > GenerateTessellationIndexBuffer(const TArray< FVector > &Vertices, const TArray< int32 > &Triangles, TArray< FVector > &Normals, const TArray< FVector2D > &UVs, TArray< FRuntimeMeshTangent > &Tangents)
FBoxSphereBounds LocalBounds


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:47:41