RuntimeMeshLibrary.cpp
Go to the documentation of this file.
1 // Copyright 2016-2018 Chris Conway (Koderz). All Rights Reserved.
2 
3 #include "RuntimeMeshLibrary.h"
5 #include "RuntimeMeshComponent.h"
6 #include "EngineGlobals.h"
7 #include "Logging/TokenizedMessage.h"
8 #include "Logging/MessageLog.h"
9 #include "Misc/UObjectToken.h"
10 #include "StaticMeshResources.h"
11 #include "Engine/StaticMesh.h"
14 #include "PhysicsEngine/BodySetup.h"
15 
16 #define LOCTEXT_NAMESPACE "RuntimeMeshLibrary"
17 
18 DECLARE_CYCLE_STAT(TEXT("RML - Copy Static Mesh to Runtime Mesh"), STAT_RuntimeMeshLibrary_CopyStaticMeshToRuntimeMesh, STATGROUP_RuntimeMesh);
19 DECLARE_CYCLE_STAT(TEXT("RML - Calculate Tangents For Mesh"), STAT_RuntimeMeshLibrary_CalculateTangentsForMesh, STATGROUP_RuntimeMesh);
20 DECLARE_CYCLE_STAT(TEXT("RML - Get Static Mesh Section"), STAT_RuntimeMeshLibrary_GetStaticMeshSection, STATGROUP_RuntimeMesh);
21 
22 
23 void URuntimeMeshLibrary::CalculateTangentsForMesh(const TArray<FVector>& Vertices, const TArray<int32>& Triangles, TArray<FVector>& Normals,
24  const TArray<FVector2D>& UVs, TArray<FRuntimeMeshTangent>& Tangents, bool bCreateSmoothNormals)
25 {
26  Normals.SetNum(Vertices.Num());
27  Tangents.SetNum(Vertices.Num());
29  [&Triangles](int32 Index) -> int32 { return Triangles[Index]; },
30  [&Vertices](int32 Index) -> FVector { return Vertices[Index]; },
31  [&UVs](int32 Index) -> FVector2D { return UVs[Index]; },
32  [&Normals, &Tangents](int32 Index, FVector TangentX, FVector TangentY, FVector TangentZ)
33  {
34  Normals[Index] = TangentZ;
35  Tangents[Index].TangentX = TangentX;
36  Tangents[Index].bFlipTangentY = GetBasisDeterminantSign(TangentX, TangentY, TangentZ) < 0;
37  },
38  Vertices.Num(), UVs.Num(), Triangles.Num(), bCreateSmoothNormals);
39 }
40 
41 void URuntimeMeshLibrary::CalculateTangentsForMeshPacked(TArray<FRuntimeMeshBlueprintVertexSimple>& Vertices, const TArray<int32>& Triangles, bool bCreateSmoothNormals)
42 {
44  [&Triangles](int32 Index) -> int32 { return Triangles[Index]; },
45  [&Vertices](int32 Index) -> FVector { return Vertices[Index].Position; },
46  [&Vertices](int32 Index) -> FVector2D { return Vertices[Index].UV0; },
47  [&Vertices](int32 Index, FVector TangentX, FVector TangentY, FVector TangentZ)
48  {
49  Vertices[Index].Normal = TangentZ;
50  Vertices[Index].Tangent.TangentX = TangentX;
51  Vertices[Index].Tangent.bFlipTangentY = GetBasisDeterminantSign(TangentX, TangentY, TangentZ) < 0;
52  },
53  Vertices.Num(), Vertices.Num(), Triangles.Num(), bCreateSmoothNormals);
54 }
55 
56 void URuntimeMeshLibrary::CalculateTangentsForMesh(TArray<FRuntimeMeshVertexSimple>& Vertices, const TArray<int32>& Triangles, bool bCreateSmoothNormals)
57 {
59  [&Triangles](int32 Index) -> int32 { return Triangles[Index]; },
60  [&Vertices](int32 Index) -> FVector { return Vertices[Index].Position; },
61  [&Vertices](int32 Index) -> FVector2D { return Vertices[Index].UV0; },
62  [&Vertices](int32 Index, FVector TangentX, FVector TangentY, FVector TangentZ)
63  {
64  Vertices[Index].Normal = TangentZ;
65  Vertices[Index].SetTangents(TangentX, TangentY, TangentZ);
66  },
67  Vertices.Num(), Vertices.Num(), Triangles.Num(), bCreateSmoothNormals);
68 }
69 
70 void URuntimeMeshLibrary::CalculateTangentsForMesh(const TSharedPtr<FRuntimeMeshAccessor>& MeshAccessor, bool bCreateSmoothNormals)
71 {
73  [MeshAccessor](int32 Index) -> int32 { return MeshAccessor->GetIndex(Index); },
74  [MeshAccessor](int32 Index) -> FVector { return MeshAccessor->GetPosition(Index); },
75  [MeshAccessor](int32 Index) -> FVector2D { return MeshAccessor->GetUV(Index); },
76  [MeshAccessor](int32 Index, FVector TangentX, FVector TangentY, FVector TangentZ)
77  {
78  MeshAccessor->SetTangents(Index, TangentX, TangentY, TangentZ);
79  },
80  MeshAccessor->NumVertices(), MeshAccessor->NumVertices(), MeshAccessor->NumIndices(), bCreateSmoothNormals);
81 }
82 
83 
84 
85 
86 TArray<int32> URuntimeMeshLibrary::GenerateTessellationIndexBuffer(const TArray<FVector>& Vertices, const TArray<int32>& Triangles, TArray<FVector>& Normals, const TArray<FVector2D>& UVs, TArray<FRuntimeMeshTangent>& Tangents)
87 {
88  TArray<int32> TessellationTriangles;
89  FTessellationUtilities::CalculateTessellationIndices(Vertices.Num(), Triangles.Num(),
90  [&Vertices](int32 Index) -> FVector { return Vertices[Index]; },
91  [&UVs](int32 Index) -> FVector2D { return UVs.Num() > Index ? UVs[Index] : FVector2D::ZeroVector; },
92  [&Triangles](int32 Index) -> int32 { return Triangles[Index]; },
93  [&TessellationTriangles](int32 NewSize) { TessellationTriangles.SetNum(NewSize); },
94  [&TessellationTriangles]() -> int32 { return TessellationTriangles.Num(); },
95  [&TessellationTriangles](int32 Index, int32 NewValue) { TessellationTriangles[Index] = NewValue; },
96  [&TessellationTriangles](int32 Index) -> int32 { return TessellationTriangles[Index]; });
97  return TessellationTriangles;
98 }
99 
100 TArray<int32> URuntimeMeshLibrary::GenerateTessellationIndexBufferPacked(const TArray<FRuntimeMeshBlueprintVertexSimple>& Vertices, const TArray<int32>& Triangles)
101 {
102  TArray<int32> TessellationTriangles;
103  FTessellationUtilities::CalculateTessellationIndices(Vertices.Num(), Triangles.Num(),
104  [&Vertices](int32 Index) -> FVector { return Vertices[Index].Position; },
105  [&Vertices](int32 Index) -> FVector2D { return Vertices[Index].UV0; },
106  [&Triangles](int32 Index) -> int32 { return Triangles[Index]; },
107  [&TessellationTriangles](int32 NewSize) { TessellationTriangles.SetNum(NewSize); },
108  [&TessellationTriangles]() -> int32 { return TessellationTriangles.Num(); },
109  [&TessellationTriangles](int32 Index, int32 NewValue) { TessellationTriangles[Index] = NewValue; },
110  [&TessellationTriangles](int32 Index) -> int32 { return TessellationTriangles[Index]; });
111  return TessellationTriangles;
112 }
113 
114 TArray<int32> URuntimeMeshLibrary::GenerateTessellationIndexBuffer(const TArray<FRuntimeMeshVertexSimple>& Vertices, const TArray<int32>& Triangles)
115 {
116  TArray<int32> TessellationTriangles;
117  FTessellationUtilities::CalculateTessellationIndices(Vertices.Num(), Triangles.Num(),
118  [&Vertices](int32 Index) -> FVector { return Vertices[Index].Position; },
119  [&Vertices](int32 Index) -> FVector2D { return Vertices[Index].UV0; },
120  [&Triangles](int32 Index) -> int32 { return Triangles[Index]; },
121  [&TessellationTriangles](int32 NewSize) { TessellationTriangles.SetNum(NewSize); },
122  [&TessellationTriangles]() -> int32 { return TessellationTriangles.Num(); },
123  [&TessellationTriangles](int32 Index, int32 NewValue) { TessellationTriangles[Index] = NewValue; },
124  [&TessellationTriangles](int32 Index) -> int32 { return TessellationTriangles[Index]; });
125  return TessellationTriangles;
126 }
127 
128 TArray<int32> URuntimeMeshLibrary::GenerateTessellationIndexBuffer(const TSharedPtr<FRuntimeMeshAccessor>& MeshAccessor)
129 {
130  TArray<int32> TessellationTriangles;
131  FTessellationUtilities::CalculateTessellationIndices(MeshAccessor->NumVertices(), MeshAccessor->NumIndices(),
132  [&MeshAccessor](int32 Index) -> FVector { return MeshAccessor->GetPosition(Index); },
133  [&MeshAccessor](int32 Index) -> FVector2D { return MeshAccessor->GetUV(Index); },
134  [&MeshAccessor](int32 Index) -> int32 { return MeshAccessor->GetIndex(Index); },
135  [&TessellationTriangles](int32 NewSize) { TessellationTriangles.SetNum(NewSize); },
136  [&TessellationTriangles]() -> int32 { return TessellationTriangles.Num(); },
137  [&TessellationTriangles](int32 Index, int32 NewValue) { TessellationTriangles[Index] = NewValue; },
138  [&TessellationTriangles](int32 Index) -> int32 { return TessellationTriangles[Index]; });
139  return TessellationTriangles;
140 }
141 
142 void URuntimeMeshLibrary::GenerateTessellationIndexBuffer(const TSharedPtr<FRuntimeMeshAccessor>& MeshAccessor, const TSharedPtr<FRuntimeMeshIndicesAccessor>& OutTessellationIndices)
143 {
144  OutTessellationIndices->EmptyIndices();
145  FTessellationUtilities::CalculateTessellationIndices(MeshAccessor->NumVertices(), MeshAccessor->NumIndices(),
146  [&MeshAccessor](int32 Index) -> FVector { return MeshAccessor->GetPosition(Index); },
147  [&MeshAccessor](int32 Index) -> FVector2D { return MeshAccessor->GetUV(Index); },
148  [&MeshAccessor](int32 Index) -> int32 { return MeshAccessor->GetIndex(Index); },
149  [&OutTessellationIndices](int32 NewSize) { OutTessellationIndices->SetNumIndices(NewSize); },
150  [&OutTessellationIndices]() -> int32 { return OutTessellationIndices->NumIndices(); },
151  [&OutTessellationIndices](int32 Index, int32 NewValue) { OutTessellationIndices->SetIndex(Index, NewValue); },
152  [&OutTessellationIndices](int32 Index) -> int32 { return OutTessellationIndices->GetIndex(Index); });
153 }
154 
155 
156 
157 
158 void URuntimeMeshLibrary::GetStaticMeshSection(UStaticMesh* InMesh, int32 LODIndex, int32 SectionIndex, TArray<FVector>& Vertices, TArray<int32>& Triangles,
159  TArray<FVector>& Normals, TArray<FVector2D>& UVs, TArray<FColor>& Colors, TArray<FRuntimeMeshTangent>& Tangents)
160 {
161  Vertices.Empty();
162  Triangles.Empty();
163  Normals.Empty();
164  UVs.Empty();
165  Colors.Empty();
166  Tangents.Empty();
167 
168  GetStaticMeshSection(InMesh, LODIndex, SectionIndex, 1,
169  [&Vertices, &Normals, &Tangents](FVector Position, FVector TangentX, FVector TangentY, FVector TangentZ) -> int32
170  {
171  int32 NewIndex = Vertices.Add(Position);
172  Normals.Add(TangentZ);
173  Tangents.Add(FRuntimeMeshTangent(TangentX, GetBasisDeterminantSign(TangentX, TangentY, TangentZ) < 0));
174  return NewIndex;
175  },
176  [&UVs](int32 Index, int32 UVIndex, FVector2D UV)
177  {
178  check(UVIndex == 0);
179  UVs.SetNum(Index + 1);
180  UVs[Index] = UV;
181  },
182  [&Colors](int32 Index, FColor Color)
183  {
184  Colors.SetNum(Index + 1);
185  Colors[Index] = Color;
186  },
187  [&Triangles](int32 Index)
188  {
189  Triangles.Add(Index);
190  },
191  [](int32 Index)
192  {
193  });
194 }
195 
196 void URuntimeMeshLibrary::GetStaticMeshSectionPacked(UStaticMesh* InMesh, int32 LODIndex, int32 SectionIndex, TArray<FRuntimeMeshBlueprintVertexSimple>& Vertices, TArray<int32>& Triangles)
197 {
198  Vertices.Empty();
199  Triangles.Empty();
200 
201  GetStaticMeshSection(InMesh, LODIndex, SectionIndex, 1,
202  [&Vertices](FVector Position, FVector TangentX, FVector TangentY, FVector TangentZ) -> int32
203  {
204  return Vertices.Add(FRuntimeMeshBlueprintVertexSimple(Position, TangentZ, FRuntimeMeshTangent(TangentX, GetBasisDeterminantSign(TangentX, TangentY, TangentZ) < 0), FVector2D::ZeroVector));
205  },
206  [&Vertices](int32 Index, int32 UVIndex, FVector2D UV)
207  {
208  check(UVIndex == 0);
209  Vertices[Index].UV0 = UV;
210  },
211  [&Vertices](int32 Index, FColor Color)
212  {
213  Vertices[Index].Color = Color;
214  },
215  [&Triangles](int32 Index)
216  {
217  Triangles.Add(Index);
218  },
219  [](int32 Index)
220  {
221  });
222 }
223 
224 void URuntimeMeshLibrary::GetStaticMeshSection(UStaticMesh* InMesh, int32 LODIndex, int32 SectionIndex, TArray<FRuntimeMeshVertexSimple>& Vertices, TArray<int32>& Triangles)
225 {
226  Vertices.Empty();
227  Triangles.Empty();
228 
229  GetStaticMeshSection(InMesh, LODIndex, SectionIndex, 1,
230  [&Vertices](FVector Position, FVector TangentX, FVector TangentY, FVector TangentZ) -> int32
231  {
232  return Vertices.Add(FRuntimeMeshVertexSimple(Position, TangentX, TangentY, TangentZ));
233  },
234  [&Vertices](int32 Index, int32 UVIndex, FVector2D UV)
235  {
236  check(UVIndex == 0);
237  Vertices[Index].UV0 = UV;
238  },
239  [&Vertices](int32 Index, FColor Color)
240  {
241  Vertices[Index].Color = Color;
242  },
243  [&Triangles](int32 Index)
244  {
245  Triangles.Add(Index);
246  },
247  [](int32 Index)
248  {
249  });
250 }
251 
252 void URuntimeMeshLibrary::GetStaticMeshSection(UStaticMesh* InMesh, int32 LODIndex, int32 SectionIndex, TArray<FRuntimeMeshVertexSimple>& Vertices, TArray<int32>& Triangles, TArray<int32>& AdjacencyTriangles)
253 {
254  Vertices.Empty();
255  Triangles.Empty();
256  AdjacencyTriangles.Empty();
257 
258  GetStaticMeshSection(InMesh, LODIndex, SectionIndex, 1,
259  [&Vertices](FVector Position, FVector TangentX, FVector TangentY, FVector TangentZ) -> int32
260  {
261  return Vertices.Add(FRuntimeMeshVertexSimple(Position, TangentX, TangentY, TangentZ));
262  },
263  [&Vertices](int32 Index, int32 UVIndex, FVector2D UV)
264  {
265  check(UVIndex == 0);
266  Vertices[Index].UV0 = UV;
267  },
268  [&Vertices](int32 Index, FColor Color)
269  {
270  Vertices[Index].Color = Color;
271  },
272  [&Triangles](int32 Index)
273  {
274  Triangles.Add(Index);
275  },
276  [&AdjacencyTriangles](int32 Index)
277  {
278  AdjacencyTriangles.Add(Index);
279  });
280 }
281 
282 void URuntimeMeshLibrary::GetStaticMeshSection(UStaticMesh* InMesh, int32 LODIndex, int32 SectionIndex, const TSharedPtr<FRuntimeMeshAccessor>& MeshAccessor)
283 {
284  MeshAccessor->EmptyVertices();
285  MeshAccessor->EmptyIndices();
286 
287  GetStaticMeshSection(InMesh, LODIndex, SectionIndex, MeshAccessor->NumUVChannels(),
288  [&MeshAccessor](FVector Position, FVector TangentX, FVector TangentY, FVector TangentZ) -> int32
289  {
290  int32 NewIndex = MeshAccessor->AddVertex(Position);
291  MeshAccessor->SetTangents(NewIndex, TangentX, TangentY, TangentZ);
292  return NewIndex;
293  },
294  [&MeshAccessor](int32 Index, int32 UVIndex, FVector2D UV)
295  {
296  MeshAccessor->SetUV(Index, UVIndex, UV);
297  },
298  [&MeshAccessor](int32 Index, FColor Color)
299  {
300  MeshAccessor->SetColor(Index, Color);
301  },
302  [&MeshAccessor](int32 Index)
303  {
304  MeshAccessor->AddIndex(Index);
305  },
306  [](int32 Index)
307  {
308  });
309 }
310 
311 void URuntimeMeshLibrary::GetStaticMeshSection(UStaticMesh* InMesh, int32 LODIndex, int32 SectionIndex, const TSharedPtr<FRuntimeMeshAccessor>& MeshAccessor, const TSharedPtr<FRuntimeMeshIndicesAccessor>& TessellationIndicesAccessor)
312 {
313  MeshAccessor->EmptyVertices();
314  MeshAccessor->EmptyIndices();
315  TessellationIndicesAccessor->EmptyIndices();
316 
317  GetStaticMeshSection(InMesh, LODIndex, SectionIndex, MeshAccessor->NumUVChannels(),
318  [&MeshAccessor](FVector Position, FVector TangentX, FVector TangentY, FVector TangentZ) -> int32
319  {
320  int32 NewIndex = MeshAccessor->AddVertex(Position);
321  MeshAccessor->SetTangents(NewIndex, TangentX, TangentY, TangentZ);
322  return NewIndex;
323  },
324  [&MeshAccessor](int32 Index, int32 UVIndex, FVector2D UV)
325  {
326  MeshAccessor->SetUV(Index, UVIndex, UV);
327  },
328  [&MeshAccessor](int32 Index, FColor Color)
329  {
330  MeshAccessor->SetColor(Index, Color);
331  },
332  [&MeshAccessor](int32 Index)
333  {
334  MeshAccessor->AddIndex(Index);
335  },
336  [&TessellationIndicesAccessor](int32 Index)
337  {
338  TessellationIndicesAccessor->AddIndex(Index);
339  });
340 }
341 
342 
343 
344 
345 
346 void URuntimeMeshLibrary::CopyStaticMeshToRuntimeMesh(UStaticMeshComponent* StaticMeshComponent, int32 LODIndex, URuntimeMesh* RuntimeMesh, bool bCreateCollision)
347 {
348  SCOPE_CYCLE_COUNTER(STAT_RuntimeMeshLibrary_CopyStaticMeshToRuntimeMesh);
349  if (StaticMeshComponent != nullptr &&
350  StaticMeshComponent->GetStaticMesh() != nullptr &&
351  RuntimeMesh != nullptr)
352  {
353  UStaticMesh* StaticMesh = StaticMeshComponent->GetStaticMesh();
354 
355  RuntimeMesh->ClearAllMeshSections();
356 
358 
359  int32 NumSections = StaticMesh->GetNumSections(LODIndex);
360  for (int32 SectionIndex = 0; SectionIndex < NumSections; SectionIndex++)
361  {
362  // Buffers for copying geom data
363  TSharedPtr<FRuntimeMeshBuilder> MeshData = MakeRuntimeMeshBuilder<FRuntimeMeshTangents, FVector2DHalf, uint32>();
364  TArray<uint8> AdjacencyTrianglesData;
365  TSharedPtr<FRuntimeMeshIndicesAccessor> AdjacencyTrianglesAccessor = MakeShared<FRuntimeMeshIndicesAccessor>(true, &AdjacencyTrianglesData);
366  TArray<uint32> AdjacencyTriangles;
367  AdjacencyTriangles.SetNum(AdjacencyTrianglesData.Num() / 4);
368  FMemory::Memcpy(AdjacencyTriangles.GetData(), AdjacencyTrianglesData.GetData(), AdjacencyTrianglesData.Num());
369 
370 
371  // TODO: Make this smarter to setup a mesh section to match the static mesh vertex configuration
372  // This will let it pick up the additional UVs or high pri normals/tangents/uvs
373 
374  // Get geom data from static mesh
375  GetStaticMeshSection(StaticMesh, LODIndex, SectionIndex, MeshData, AdjacencyTrianglesAccessor);
376 
377  // Create RuntimeMesh
378  RuntimeMesh->CreateMeshSection(SectionIndex, MeshData, bCreateCollision);
379  RuntimeMesh->SetSectionTessellationTriangles(SectionIndex, AdjacencyTriangles);
380  }
381 
383  CopyCollisionFromStaticMesh(StaticMesh, RuntimeMesh);
384 
385 
387 
388  for (int32 MatIndex = 0; MatIndex < StaticMeshComponent->GetNumMaterials(); MatIndex++)
389  {
390  RuntimeMesh->SetSectionMaterial(MatIndex, StaticMeshComponent->GetMaterial(MatIndex));
391  }
392  }
393 }
394 
395 
396 void URuntimeMeshLibrary::CopyStaticMeshToRuntimeMeshComponent(UStaticMeshComponent* StaticMeshComponent, int32 LODIndex, URuntimeMeshComponent* RuntimeMeshComponent, bool bCreateCollision)
397 {
398  CopyStaticMeshToRuntimeMesh(StaticMeshComponent, LODIndex, RuntimeMeshComponent->GetOrCreateRuntimeMesh(), bCreateCollision);
399 }
400 
401 void URuntimeMeshLibrary::CopyCollisionFromStaticMesh(UStaticMesh* StaticMesh, URuntimeMesh* RuntimeMesh)
402 {
403  // Clear any existing collision hulls
404  RuntimeMesh->ClearAllConvexCollisionSections();
405 
406  if (StaticMesh->BodySetup != nullptr)
407  {
408  // Iterate over all convex hulls on static mesh..
409  const int32 NumConvex = StaticMesh->BodySetup->AggGeom.ConvexElems.Num();
410  for (int ConvexIndex = 0; ConvexIndex < NumConvex; ConvexIndex++)
411  {
412  // Copy convex verts
413  FKConvexElem& MeshConvex = StaticMesh->BodySetup->AggGeom.ConvexElems[ConvexIndex];
414 
415  RuntimeMesh->AddConvexCollisionSection(MeshConvex.VertexData);
416  }
417  }
418 }
419 
420 void URuntimeMeshLibrary::CalculateTangentsForMesh(TFunction<int32(int32 Index)> IndexAccessor, TFunction<FVector(int32 Index)> VertexAccessor, TFunction<FVector2D(int32 Index)> UVAccessor,
421  TFunction<void(int32 Index, FVector TangentX, FVector TangentY, FVector TangentZ)> TangentSetter, int32 NumVertices, int32 NumUVs, int32 NumIndices, bool bCreateSmoothNormals)
422 {
423  SCOPE_CYCLE_COUNTER(STAT_RuntimeMeshLibrary_CalculateTangentsForMesh);
424 
425  if (NumVertices == 0 || NumIndices == 0)
426  {
427  return;
428  }
429 
430  // Calculate the duplicate vertices map if we're wanting smooth normals. Don't find duplicates if we don't want smooth normals
431  // that will cause it to only smooth across faces sharing a common vertex, not across faces with vertices of common position
432  const TMultiMap<uint32, uint32> DuplicateVertexMap = bCreateSmoothNormals ? FRuntimeMeshInternalUtilities::FindDuplicateVerticesMap(VertexAccessor, NumVertices) : TMultiMap<uint32, uint32>();
433 
434 
435  // Number of triangles
436  const int32 NumTris = NumIndices / 3;
437 
438  // Map of vertex to triangles in Triangles array
439  TMultiMap<uint32, uint32> VertToTriMap;
440  // Map of vertex to triangles to consider for normal calculation
441  TMultiMap<uint32, uint32> VertToTriSmoothMap;
442 
443  // Normal/tangents for each face
444  TArray<FVector> FaceTangentX, FaceTangentY, FaceTangentZ;
445  FaceTangentX.AddUninitialized(NumTris);
446  FaceTangentY.AddUninitialized(NumTris);
447  FaceTangentZ.AddUninitialized(NumTris);
448 
449  // Iterate over triangles
450  for (int TriIdx = 0; TriIdx < NumTris; TriIdx++)
451  {
452  uint32 CornerIndex[3];
453  FVector P[3];
454 
455  for (int32 CornerIdx = 0; CornerIdx < 3; CornerIdx++)
456  {
457  // Find vert index (clamped within range)
458  uint32 VertIndex = FMath::Min(IndexAccessor((TriIdx * 3) + CornerIdx), NumVertices - 1);
459 
460  CornerIndex[CornerIdx] = VertIndex;
461  P[CornerIdx] = VertexAccessor(VertIndex);
462 
463  // Find/add this vert to index buffer
464  TArray<uint32> VertOverlaps;
465  DuplicateVertexMap.MultiFind(VertIndex, VertOverlaps);
466 
467  // Remember which triangles map to this vert
468  VertToTriMap.AddUnique(VertIndex, TriIdx);
469  VertToTriSmoothMap.AddUnique(VertIndex, TriIdx);
470 
471  // Also update map of triangles that 'overlap' this vert (ie don't match UV, but do match smoothing) and should be considered when calculating normal
472  for (int32 OverlapIdx = 0; OverlapIdx < VertOverlaps.Num(); OverlapIdx++)
473  {
474  // For each vert we overlap..
475  int32 OverlapVertIdx = VertOverlaps[OverlapIdx];
476 
477  // Add this triangle to that vert
478  VertToTriSmoothMap.AddUnique(OverlapVertIdx, TriIdx);
479 
480  // And add all of its triangles to us
481  TArray<uint32> OverlapTris;
482  VertToTriMap.MultiFind(OverlapVertIdx, OverlapTris);
483  for (int32 OverlapTriIdx = 0; OverlapTriIdx < OverlapTris.Num(); OverlapTriIdx++)
484  {
485  VertToTriSmoothMap.AddUnique(VertIndex, OverlapTris[OverlapTriIdx]);
486  }
487  }
488  }
489 
490  // Calculate triangle edge vectors and normal
491  const FVector Edge21 = P[1] - P[2];
492  const FVector Edge20 = P[0] - P[2];
493  const FVector TriNormal = (Edge21 ^ Edge20).GetSafeNormal();
494 
495  // If we have UVs, use those to calculate
496  if (NumUVs == NumVertices)
497  {
498  const FVector2D T1 = UVAccessor(CornerIndex[0]);
499  const FVector2D T2 = UVAccessor(CornerIndex[1]);
500  const FVector2D T3 = UVAccessor(CornerIndex[2]);
501 
502 // float X1 = P[1].X - P[0].X;
503 // float X2 = P[2].X - P[0].X;
504 // float Y1 = P[1].Y - P[0].Y;
505 // float Y2 = P[2].Y - P[0].Y;
506 // float Z1 = P[1].Z - P[0].Z;
507 // float Z2 = P[2].Z - P[0].Z;
508 //
509 // float S1 = U1.X - U0.X;
510 // float S2 = U2.X - U0.X;
511 // float T1 = U1.Y - U0.Y;
512 // float T2 = U2.Y - U0.Y;
513 //
514 // float R = 1.0f / (S1 * T2 - S2 * T1);
515 // FaceTangentX[TriIdx] = FVector((T2 * X1 - T1 * X2) * R, (T2 * Y1 - T1 * Y2) * R,
516 // (T2 * Z1 - T1 * Z2) * R);
517 // FaceTangentY[TriIdx] = FVector((S1 * X2 - S2 * X1) * R, (S1 * Y2 - S2 * Y1) * R,
518 // (S1 * Z2 - S2 * Z1) * R);
519 
520 
521 
522 
523  FMatrix ParameterToLocal(
524  FPlane(P[1].X - P[0].X, P[1].Y - P[0].Y, P[1].Z - P[0].Z, 0),
525  FPlane(P[2].X - P[0].X, P[2].Y - P[0].Y, P[2].Z - P[0].Z, 0),
526  FPlane(P[0].X, P[0].Y, P[0].Z, 0),
527  FPlane(0, 0, 0, 1)
528  );
529 
530  FMatrix ParameterToTexture(
531  FPlane(T2.X - T1.X, T2.Y - T1.Y, 0, 0),
532  FPlane(T3.X - T1.X, T3.Y - T1.Y, 0, 0),
533  FPlane(T1.X, T1.Y, 1, 0),
534  FPlane(0, 0, 0, 1)
535  );
536 
537  // Use InverseSlow to catch singular matrices. Inverse can miss this sometimes.
538  const FMatrix TextureToLocal = ParameterToTexture.Inverse() * ParameterToLocal;
539 
540  FaceTangentX[TriIdx] = TextureToLocal.TransformVector(FVector(1, 0, 0)).GetSafeNormal();
541  FaceTangentY[TriIdx] = TextureToLocal.TransformVector(FVector(0, 1, 0)).GetSafeNormal();
542  }
543  else
544  {
545  FaceTangentX[TriIdx] = Edge20.GetSafeNormal();
546  FaceTangentY[TriIdx] = (FaceTangentX[TriIdx] ^ TriNormal).GetSafeNormal();
547  }
548 
549  FaceTangentZ[TriIdx] = TriNormal;
550  }
551 
552 
553  // Arrays to accumulate tangents into
554  TArray<FVector> VertexTangentXSum, VertexTangentYSum, VertexTangentZSum;
555  VertexTangentXSum.AddZeroed(NumVertices);
556  VertexTangentYSum.AddZeroed(NumVertices);
557  VertexTangentZSum.AddZeroed(NumVertices);
558 
559  // For each vertex..
560  for (int VertxIdx = 0; VertxIdx < NumVertices; VertxIdx++)
561  {
562  // Find relevant triangles for normal
563  TArray<uint32> SmoothTris;
564  VertToTriSmoothMap.MultiFind(VertxIdx, SmoothTris);
565 
566  for (int i = 0; i < SmoothTris.Num(); i++)
567  {
568  uint32 TriIdx = SmoothTris[i];
569  VertexTangentZSum[VertxIdx] += FaceTangentZ[TriIdx];
570  }
571 
572  // Find relevant triangles for tangents
573  TArray<uint32> TangentTris;
574  VertToTriMap.MultiFind(VertxIdx, TangentTris);
575 
576  for (int i = 0; i < TangentTris.Num(); i++)
577  {
578  uint32 TriIdx = TangentTris[i];
579  VertexTangentXSum[VertxIdx] += FaceTangentX[TriIdx];
580  VertexTangentYSum[VertxIdx] += FaceTangentY[TriIdx];
581  }
582  }
583 
584  // Finally, normalize tangents and build output arrays
585  for (int VertxIdx = 0; VertxIdx < NumVertices; VertxIdx++)
586  {
587  FVector& TangentX = VertexTangentXSum[VertxIdx];
588  FVector& TangentY = VertexTangentYSum[VertxIdx];
589  FVector& TangentZ = VertexTangentZSum[VertxIdx];
590 
591  TangentX.Normalize();
592  //TangentY.Normalize();
593  TangentZ.Normalize();
594 
595  // Use Gram-Schmidt orthogonalization to make sure X is orthonormal with Z
596  TangentX -= TangentZ * (TangentZ | TangentX);
597  TangentX.Normalize();
598  TangentY.Normalize();
599 
600 
601  TangentSetter(VertxIdx, TangentX, TangentY, TangentZ);
602  }
603 }
604 
605 int32 URuntimeMeshLibrary::GetNewIndexForOldVertIndex(const FPositionVertexBuffer* PosBuffer, const FStaticMeshVertexBuffer* VertBuffer, const FColorVertexBuffer* ColorBuffer,
606  TMap<int32, int32>& MeshToSectionVertMap, int32 VertexIndex, int32 NumUVChannels, TFunction<int32(FVector Position, FVector TangentX, FVector TangentY, FVector TangentZ)> VertexCreator,
607  TFunction<void(int32 VertexIndex, int32 UVIndex, FVector2D UV)> UVSetter, TFunction<void(int32 VertexIndex, FColor Color)> ColorSetter)
608 {
609  int32* FoundIndex = MeshToSectionVertMap.Find(VertexIndex);
610  if (FoundIndex != nullptr)
611  {
612  return *FoundIndex;
613  }
614  else
615  {
616  int32 NewVertexIndex = VertexCreator(
617  PosBuffer->VertexPosition(VertexIndex),
618  VertBuffer->VertexTangentX(VertexIndex),
619  VertBuffer->VertexTangentY(VertexIndex),
620  VertBuffer->VertexTangentZ(VertexIndex));
621 
622  if (ColorBuffer && ColorBuffer->GetNumVertices() > (uint32)NewVertexIndex)
623  {
624  ColorSetter(NewVertexIndex, ColorBuffer->VertexColor(VertexIndex));
625  }
626 
627  int32 NumTexCoordsToCopy = FMath::Min(NumUVChannels, (int32)VertBuffer->GetNumTexCoords());
628  for (int32 Index = 0; Index < NumTexCoordsToCopy; Index++)
629  {
630  UVSetter(NewVertexIndex, Index, VertBuffer->GetVertexUV(VertexIndex, Index));
631  }
632 
633  MeshToSectionVertMap.Add(VertexIndex, NewVertexIndex);
634  return NewVertexIndex;
635  }
636 }
637 
638 void URuntimeMeshLibrary::GetStaticMeshSection(UStaticMesh* InMesh, int32 LODIndex, int32 SectionIndex, int32 NumSupportedUVs,
639  TFunction<int32(FVector Position, FVector TangentX, FVector TangentY, FVector TangentZ)> VertexCreator,
640  TFunction<void(int32 VertexIndex, int32 UVIndex, FVector2D UV)> UVSetter, TFunction<void(int32 VertexIndex, FColor Color)> ColorSetter, TFunction<void(int32)> IndexCreator, TFunction<void(int32)> AdjacencyIndexCreator)
641 {
642  SCOPE_CYCLE_COUNTER(STAT_RuntimeMeshLibrary_GetStaticMeshSection);
643 
644  if (InMesh != nullptr)
645  {
646  // Log a PIE warning if this will fail in a cooked build
647  if (!InMesh->bAllowCPUAccess)
648  {
649  FMessageLog("PIE").Warning()
650  ->AddToken(FTextToken::Create(LOCTEXT("GetSectionFromStaticMeshStart", "Calling GetSectionFromStaticMesh on")))
651  ->AddToken(FUObjectToken::Create(InMesh))
652  ->AddToken(FTextToken::Create(LOCTEXT("GetSectionFromStaticMeshEnd", "but 'Allow CPU Access' is not enabled. This is required for converting StaticMesh to ProceduralMeshComponent in cooked builds.")));
653  }
654 
655  if ((InMesh->bAllowCPUAccess || GIsEditor) && InMesh->RenderData != nullptr && InMesh->RenderData->LODResources.IsValidIndex(LODIndex))
656  {
657  const FStaticMeshLODResources& LOD = InMesh->RenderData->LODResources[LODIndex];
658  if (LOD.Sections.IsValidIndex(SectionIndex))
659  {
660  // Map from vert buffer for whole mesh to vert buffer for section of interest
661  TMap<int32, int32> MeshToSectionVertMap;
662 
663  const FStaticMeshSection& Section = LOD.Sections[SectionIndex];
664  const uint32 OnePastLastIndex = Section.FirstIndex + Section.NumTriangles * 3;
665  FIndexArrayView Indices = LOD.IndexBuffer.GetArrayView();
666 
667  // Iterate over section index buffer, copying verts as needed
668  for (uint32 i = Section.FirstIndex; i < OnePastLastIndex; i++)
669  {
670  uint32 MeshVertIndex = Indices[i];
671 
672  // See if we have this vert already in our section vert buffer, and copy vert in if not
673 
674 #if ENGINE_MAJOR_VERSION >= 4 && ENGINE_MINOR_VERSION >= 19
675  int32 SectionVertIndex = GetNewIndexForOldVertIndex(&LOD.VertexBuffers.PositionVertexBuffer, &LOD.VertexBuffers.StaticMeshVertexBuffer, &LOD.VertexBuffers.ColorVertexBuffer, MeshToSectionVertMap, MeshVertIndex, NumSupportedUVs, VertexCreator, UVSetter, ColorSetter);
676 #else
677  int32 SectionVertIndex = GetNewIndexForOldVertIndex(&LOD.PositionVertexBuffer, &LOD.VertexBuffer, &LOD.ColorVertexBuffer, MeshToSectionVertMap, MeshVertIndex, NumSupportedUVs, VertexCreator, UVSetter, ColorSetter);
678 #endif
679 
680  // Add to index buffer
681  IndexCreator(SectionVertIndex);
682  }
683 
684  // Lets copy the adjacency information too for tessellation
685  // At this point all vertices should be copied so it should work to just copy/convert the indices.
686  if (LOD.bHasAdjacencyInfo && LOD.AdditionalIndexBuffers->AdjacencyIndexBuffer.GetNumIndices() > 0)
687  {
688  FIndexArrayView AdjacencyIndices = LOD.AdditionalIndexBuffers->AdjacencyIndexBuffer.GetArrayView();
689 
690  // We multiply these by 4 as the adjacency data is 12 indices per triangle instead of the normal 3
691  uint32 StartIndex = Section.FirstIndex * 4;
692  uint32 NumIndices = Section.NumTriangles * 3 * 4;
693 
694  for (uint32 Index = 0; Index < NumIndices; Index++)
695  {
696  AdjacencyIndexCreator(MeshToSectionVertMap[AdjacencyIndices[Index]]);
697  }
698  }
699  }
700  }
701  }
702 }
703 
704 
705 #undef LOCTEXT_NAMESPACE
static void CalculateTangentsForMeshPacked(TArray< FRuntimeMeshBlueprintVertexSimple > &Vertices, const TArray< int32 > &Triangles, bool bCreateSmoothNormals=true)
static void CopyStaticMeshToRuntimeMeshComponent(UStaticMeshComponent *StaticMeshComponent, int32 LODIndex, URuntimeMeshComponent *RuntimeMeshComponent, bool bCreateCollision)
list Z
Definition: rmse.py:133
void CreateMeshSection(int32 SectionIndex, bool bWantsHighPrecisionTangents, bool bWantsHighPrecisionUVs, int32 NumUVs, bool bWants32BitIndices, bool bCreateCollision, EUpdateFrequency UpdateFrequency=EUpdateFrequency::Average)
Definition: RuntimeMesh.h:135
static void CalculateTessellationIndices(int32 NumVertices, int32 NumIndices, TFunction< FVector(int32)> PositionAccessor, TFunction< FVector2D(int32)> UVAccessor, TFunction< int32(int32)> IndexAccessor, TFunction< void(int32)> OutIndicesSizeSetter, TFunction< int32()> OutIndicesSizeGetter, TFunction< void(int32, int32)> OutIndicesWriter, TFunction< int32(int32)> OutIndicesReader)
static TMultiMap< uint32, uint32 > FindDuplicateVerticesMap(TFunction< FVector(int32)> VertexAccessor, int32 NumVertices, float Tollerance=0.0)
void SetSectionTessellationTriangles(int32 SectionId, const TArray< int32 > &Triangles)
Definition: RuntimeMesh.h:484
void SetSectionMaterial(int32 SectionId, UMaterialInterface *Material)
Definition: RuntimeMesh.h:517
static TArray< int32 > GenerateTessellationIndexBufferPacked(const TArray< FRuntimeMeshBlueprintVertexSimple > &Vertices, const TArray< int32 > &Triangles)
void ClearAllMeshSections()
Definition: RuntimeMesh.h:509
static int32 GetNewIndexForOldVertIndex(const FPositionVertexBuffer *PosBuffer, const FStaticMeshVertexBuffer *VertBuffer, const FColorVertexBuffer *ColorBuffer, TMap< int32, int32 > &MeshToSectionVertMap, int32 VertexIndex, int32 NumUVChannels, TFunction< int32(FVector Position, FVector TangentX, FVector TangentY, FVector TangentZ)> VertexCreator, TFunction< void(int32 VertexIndex, int32 UVIndex, FVector2D UV)> UVSetter, TFunction< void(int32 VertexIndex, FColor Color)> ColorSetter)
static void CalculateTangentsForMesh(const TArray< FVector > &Vertices, const TArray< int32 > &Triangles, TArray< FVector > &Normals, const TArray< FVector2D > &UVs, TArray< FRuntimeMeshTangent > &Tangents, bool bCreateSmoothNormals=true)
static void CopyCollisionFromStaticMesh(UStaticMesh *StaticMesh, URuntimeMesh *RuntimeMesh)
static const textual_icon check
Definition: model-views.h:260
void ClearAllConvexCollisionSections()
Definition: RuntimeMesh.h:687
int32 AddConvexCollisionSection(TArray< FVector > ConvexVerts)
Definition: RuntimeMesh.h:666
struct Index Index
Definition: sqlite3.c:11789
static void CopyStaticMeshToRuntimeMesh(UStaticMeshComponent *StaticMeshComponent, int32 LODIndex, URuntimeMesh *RuntimeMesh, bool bCreateCollision)
list Y
Definition: rmse.py:132
static void GetStaticMeshSectionPacked(UStaticMesh *InMesh, int32 LODIndex, int32 SectionIndex, TArray< FRuntimeMeshBlueprintVertexSimple > &Vertices, TArray< int32 > &Triangles)
int i
list X
Definition: rmse.py:131
static TArray< int32 > GenerateTessellationIndexBuffer(const TArray< FVector > &Vertices, const TArray< int32 > &Triangles, TArray< FVector > &Normals, const TArray< FVector2D > &UVs, TArray< FRuntimeMeshTangent > &Tangents)
static void GetStaticMeshSection(UStaticMesh *InMesh, int32 LODIndex, int32 SectionIndex, TArray< FVector > &Vertices, TArray< int32 > &Triangles, TArray< FVector > &Normals, TArray< FVector2D > &UVs, TArray< FColor > &Colors, TArray< FRuntimeMeshTangent > &Tangents)
DECLARE_CYCLE_STAT(TEXT("RML - Copy Static Mesh to Runtime Mesh"), STAT_RuntimeMeshLibrary_CopyStaticMeshToRuntimeMesh, STATGROUP_RuntimeMesh)


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