RuntimeMeshSection.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812
  1. // Copyright 2016 Chris Conway (Koderz). All Rights Reserved.
  2. #pragma once
  3. #include "Engine.h"
  4. #include "Components/MeshComponent.h"
  5. #include "RuntimeMeshProfiling.h"
  6. #include "RuntimeMeshVersion.h"
  7. #include "RuntimeMeshSectionProxy.h"
  8. #include "RuntimeMeshBuilder.h"
  9. #include "RuntimeMeshLibrary.h"
  10. /** Interface class for a single mesh section */
  11. class FRuntimeMeshSectionInterface
  12. {
  13. protected:
  14. const bool bNeedsPositionOnlyBuffer;
  15. public:
  16. /** Position only vertex buffer for this section */
  17. TArray<FVector> PositionVertexBuffer;
  18. /** Index buffer for this section */
  19. TArray<int32> IndexBuffer;
  20. /** Index buffer used for tessellation containing the needed adjacency info */
  21. TArray<int32> TessellationIndexBuffer;
  22. /** Local bounding box of section */
  23. FBox LocalBoundingBox;
  24. /** Should we build collision data for triangles in this section */
  25. bool CollisionEnabled;
  26. /** Should we display this section */
  27. bool bIsVisible;
  28. /** Should this section cast a shadow */
  29. bool bCastsShadow;
  30. /** If this section is currently using an adjacency index buffer */
  31. bool bShouldUseAdjacencyIndexBuffer;
  32. /** Update frequency of this section */
  33. EUpdateFrequency UpdateFrequency;
  34. FRuntimeMeshSectionInterface(bool bInNeedsPositionOnlyBuffer) :
  35. bNeedsPositionOnlyBuffer(bInNeedsPositionOnlyBuffer),
  36. LocalBoundingBox(EForceInit::ForceInitToZero),
  37. CollisionEnabled(false),
  38. bIsVisible(true),
  39. bCastsShadow(true),
  40. bIsLegacySectionType(false)
  41. {}
  42. virtual ~FRuntimeMeshSectionInterface() { }
  43. protected:
  44. /** Is this an internal section type. */
  45. bool bIsLegacySectionType;
  46. bool IsDualBufferSection() const { return bNeedsPositionOnlyBuffer; }
  47. /* Updates the vertex position buffer, returns whether we have a new bounding box */
  48. bool UpdateVertexPositionBuffer(TArray<FVector>& Positions, const FBox* BoundingBox, bool bShouldMoveArray)
  49. {
  50. // Holds the new bounding box after this update.
  51. FBox NewBoundingBox(EForceInit::ForceInitToZero);
  52. if (bShouldMoveArray)
  53. {
  54. // Move buffer data
  55. PositionVertexBuffer = MoveTemp(Positions);
  56. // Calculate the bounding box if one doesn't exist.
  57. if (BoundingBox == nullptr)
  58. {
  59. for (int32 VertexIdx = 0; VertexIdx < PositionVertexBuffer.Num(); VertexIdx++)
  60. {
  61. NewBoundingBox += PositionVertexBuffer[VertexIdx];
  62. }
  63. }
  64. else
  65. {
  66. // Copy the supplied bounding box instead of calculating it.
  67. NewBoundingBox = *BoundingBox;
  68. }
  69. }
  70. else
  71. {
  72. if (BoundingBox == nullptr)
  73. {
  74. // Copy the buffer and calculate the bounding box at the same time
  75. int32 NumVertices = Positions.Num();
  76. PositionVertexBuffer.SetNumUninitialized(NumVertices);
  77. for (int32 VertexIdx = 0; VertexIdx < NumVertices; VertexIdx++)
  78. {
  79. NewBoundingBox += Positions[VertexIdx];
  80. PositionVertexBuffer[VertexIdx] = Positions[VertexIdx];
  81. }
  82. }
  83. else
  84. {
  85. // Copy the buffer
  86. PositionVertexBuffer = Positions;
  87. // Copy the supplied bounding box instead of calculating it.
  88. NewBoundingBox = *BoundingBox;
  89. }
  90. }
  91. // Update the bounding box if necessary and alert our caller if we did
  92. if (!(LocalBoundingBox == NewBoundingBox))
  93. {
  94. LocalBoundingBox = NewBoundingBox;
  95. return true;
  96. }
  97. return false;
  98. }
  99. virtual void UpdateVertexBuffer(IRuntimeMeshVerticesBuilder& Vertices, const FBox* BoundingBox, bool bShouldMoveArray) = 0;
  100. void UpdateIndexBuffer(TArray<int32>& Triangles, bool bShouldMoveArray)
  101. {
  102. if (bShouldMoveArray)
  103. {
  104. IndexBuffer = MoveTemp(Triangles);
  105. }
  106. else
  107. {
  108. IndexBuffer = Triangles;
  109. }
  110. }
  111. void UpdateIndexBuffer(FRuntimeMeshIndicesBuilder& Triangles, bool bShouldMoveArray)
  112. {
  113. if (bShouldMoveArray)
  114. {
  115. IndexBuffer = MoveTemp(*Triangles.GetIndices());
  116. Triangles.Reset();
  117. }
  118. else
  119. {
  120. IndexBuffer = *Triangles.GetIndices();
  121. }
  122. }
  123. void UpdateTessellationIndexBuffer(TArray<int32>& Triangles, bool bShouldMoveArray)
  124. {
  125. if (bShouldMoveArray)
  126. {
  127. TessellationIndexBuffer = MoveTemp(Triangles);
  128. }
  129. else
  130. {
  131. TessellationIndexBuffer = Triangles;
  132. }
  133. }
  134. virtual FRuntimeMeshSectionCreateDataInterface* GetSectionCreationData(FSceneInterface* InScene, UMaterialInterface* InMaterial) const = 0;
  135. virtual FRuntimeMeshRenderThreadCommandInterface* GetSectionUpdateData(bool bIncludePositionVertices, bool bIncludeVertices, bool bIncludeIndices) const = 0;
  136. virtual FRuntimeMeshRenderThreadCommandInterface* GetSectionPositionUpdateData() const = 0;
  137. virtual void RecalculateBoundingBox() = 0;
  138. #if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 13
  139. virtual int32 GetCollisionInformation(TArray<FVector>& Positions, TArray<TArray<FVector2D>>& UVs, bool bIncludeUVs) = 0;
  140. #else
  141. virtual int32 GetCollisionInformation(TArray<FVector>& Positions) = 0;
  142. #endif
  143. virtual void GetInternalVertexComponents(int32& NumUVChannels, bool& WantsHalfPrecisionUVs) { }
  144. // This is only meant for internal use for supporting the old style create/update sections
  145. virtual bool UpdateVertexBufferInternal(const TArray<FVector>& Positions, const TArray<FVector>& Normals, const TArray<FRuntimeMeshTangent>& Tangents, const TArray<FVector2D>& UV0, const TArray<FVector2D>& UV1, const TArray<FColor>& Colors) { return false; }
  146. virtual void GetSectionMesh(IRuntimeMeshVerticesBuilder*& Vertices, FRuntimeMeshIndicesBuilder*& Indices) = 0;
  147. virtual const FRuntimeMeshVertexTypeInfo* GetVertexType() const = 0;
  148. virtual void GenerateNormalTangent() = 0;
  149. virtual void GenerateTessellationIndices() = 0;
  150. virtual void Serialize(FArchive& Ar)
  151. {
  152. if (Ar.CustomVer(FRuntimeMeshVersion::GUID) >= FRuntimeMeshVersion::SerializationV2)
  153. {
  154. if (bNeedsPositionOnlyBuffer)
  155. {
  156. Ar << PositionVertexBuffer;
  157. }
  158. Ar << IndexBuffer;
  159. Ar << TessellationIndexBuffer;
  160. Ar << LocalBoundingBox;
  161. Ar << CollisionEnabled;
  162. Ar << bIsVisible;
  163. Ar << bCastsShadow;
  164. Ar << bShouldUseAdjacencyIndexBuffer;
  165. // Serialize the update frequency as an int32
  166. int32 UpdateFreq = (int32)UpdateFrequency;
  167. Ar << UpdateFreq;
  168. UpdateFrequency = (EUpdateFrequency)UpdateFreq;
  169. Ar << bIsLegacySectionType;
  170. }
  171. else
  172. {
  173. if (Ar.CustomVer(FRuntimeMeshVersion::GUID) >= FRuntimeMeshVersion::DualVertexBuffer)
  174. {
  175. Ar << PositionVertexBuffer;
  176. }
  177. Ar << IndexBuffer;
  178. Ar << LocalBoundingBox;
  179. Ar << CollisionEnabled;
  180. Ar << bIsVisible;
  181. int32 UpdateFreq = (int32)UpdateFrequency;
  182. Ar << UpdateFreq;
  183. UpdateFrequency = (EUpdateFrequency)UpdateFreq;
  184. }
  185. }
  186. friend class FRuntimeMeshSceneProxy;
  187. friend class URuntimeMeshComponent;
  188. };
  189. namespace RuntimeMeshSectionInternal
  190. {
  191. template<typename Type>
  192. static typename TEnableIf<FRuntimeMeshVertexTraits<Type>::HasPosition, int32>::Type
  193. GetAllVertexPositions(const TArray<Type>& VertexBuffer, const TArray<FVector>& PositionVertexBuffer, TArray<FVector>& Positions)
  194. {
  195. int32 VertexCount = VertexBuffer.Num();
  196. for (int32 VertIdx = 0; VertIdx < VertexCount; VertIdx++)
  197. {
  198. Positions.Add(VertexBuffer[VertIdx].Position);
  199. }
  200. return VertexCount;
  201. }
  202. template<typename Type>
  203. static typename TEnableIf<!FRuntimeMeshVertexTraits<Type>::HasPosition, int32>::Type
  204. GetAllVertexPositions(const TArray<Type>& VertexBuffer, const TArray<FVector>& PositionVertexBuffer, TArray<FVector>& Positions)
  205. {
  206. Positions.Append(PositionVertexBuffer);
  207. return PositionVertexBuffer.Num();
  208. }
  209. template<typename Type>
  210. static typename TEnableIf<FRuntimeMeshVertexTraits<Type>::HasPosition, bool>::Type
  211. UpdateVertexBufferInternal(TArray<Type>& VertexBuffer, FBox& LocalBoundingBox, TArray<Type>& Vertices, const FBox* BoundingBox, bool bShouldMoveArray)
  212. {
  213. // Holds the new bounding box after this update.
  214. FBox NewBoundingBox(EForceInit::ForceInitToZero);
  215. if (bShouldMoveArray)
  216. {
  217. // Move buffer data
  218. VertexBuffer = MoveTemp(Vertices);
  219. // Calculate the bounding box if one doesn't exist.
  220. if (BoundingBox == nullptr)
  221. {
  222. for (int32 VertexIdx = 0; VertexIdx < VertexBuffer.Num(); VertexIdx++)
  223. {
  224. NewBoundingBox += VertexBuffer[VertexIdx].Position;
  225. }
  226. }
  227. else
  228. {
  229. // Copy the supplied bounding box instead of calculating it.
  230. NewBoundingBox = *BoundingBox;
  231. }
  232. }
  233. else
  234. {
  235. if (BoundingBox == nullptr)
  236. {
  237. // Copy the buffer and calculate the bounding box at the same time
  238. int32 NumVertices = Vertices.Num();
  239. VertexBuffer.SetNumUninitialized(NumVertices);
  240. for (int32 VertexIdx = 0; VertexIdx < NumVertices; VertexIdx++)
  241. {
  242. NewBoundingBox += Vertices[VertexIdx].Position;
  243. VertexBuffer[VertexIdx] = Vertices[VertexIdx];
  244. }
  245. }
  246. else
  247. {
  248. // Copy the buffer
  249. VertexBuffer = Vertices;
  250. // Copy the supplied bounding box instead of calculating it.
  251. NewBoundingBox = *BoundingBox;
  252. }
  253. }
  254. // Update the bounding box if necessary and alert our caller if we did
  255. if (!(LocalBoundingBox == NewBoundingBox))
  256. {
  257. LocalBoundingBox = NewBoundingBox;
  258. return true;
  259. }
  260. return false;
  261. }
  262. template<typename Type>
  263. static typename TEnableIf<!FRuntimeMeshVertexTraits<Type>::HasPosition, bool>::Type
  264. UpdateVertexBufferInternal(TArray<Type>& VertexBuffer, FBox& LocalBoundingBox, TArray<Type>& Vertices, const FBox* BoundingBox, bool bShouldMoveArray)
  265. {
  266. if (bShouldMoveArray)
  267. {
  268. VertexBuffer = MoveTemp(Vertices);
  269. }
  270. else
  271. {
  272. VertexBuffer = Vertices;
  273. }
  274. return false;
  275. }
  276. template<typename Type>
  277. static typename TEnableIf<FRuntimeMeshVertexTraits<Type>::HasPosition>::Type RecalculateBoundingBox(TArray<Type>& VertexBuffer, FBox& BoundingBox)
  278. {
  279. for (int32 Index = 0; Index < VertexBuffer.Num(); Index++)
  280. {
  281. BoundingBox += VertexBuffer[Index].Position;
  282. }
  283. }
  284. template<typename Type>
  285. static typename TEnableIf<!FRuntimeMeshVertexTraits<Type>::HasPosition>::Type RecalculateBoundingBox(TArray<Type>& VertexBuffer, FBox& BoundingBox)
  286. {
  287. }
  288. }
  289. /** Templated class for a single mesh section */
  290. template<typename VertexType>
  291. class FRuntimeMeshSection : public FRuntimeMeshSectionInterface
  292. {
  293. public:
  294. /** Vertex buffer for this section */
  295. TArray<VertexType> VertexBuffer;
  296. FRuntimeMeshSection(bool bInNeedsPositionOnlyBuffer) : FRuntimeMeshSectionInterface(bInNeedsPositionOnlyBuffer) { }
  297. virtual ~FRuntimeMeshSection() override { }
  298. protected:
  299. bool UpdateVertexBuffer(TArray<VertexType>& Vertices, const FBox* BoundingBox, bool bShouldMoveArray)
  300. {
  301. return RuntimeMeshSectionInternal::UpdateVertexBufferInternal<VertexType>(VertexBuffer, LocalBoundingBox, Vertices, BoundingBox, bShouldMoveArray);
  302. }
  303. virtual void UpdateVertexBuffer(IRuntimeMeshVerticesBuilder& Vertices, const FBox* BoundingBox, bool bShouldMoveArray) override
  304. {
  305. if (Vertices.GetBuilderType() == ERuntimeMeshVerticesBuilderType::Component)
  306. {
  307. FRuntimeMeshComponentVerticesBuilder* VerticesBuilder = static_cast<FRuntimeMeshComponentVerticesBuilder*>(&Vertices);
  308. TArray<FVector>* Positions = VerticesBuilder->GetPositions();
  309. TArray<FVector>* Normals = VerticesBuilder->GetNormals();
  310. TArray<FRuntimeMeshTangent>* Tangents = VerticesBuilder->GetTangents();
  311. TArray<FColor>* Colors = VerticesBuilder->GetColors();
  312. TArray<FVector2D>* UV0s = VerticesBuilder->GetUV0s();
  313. TArray<FVector2D>* UV1s = VerticesBuilder->GetUV1s();
  314. UpdateVertexBufferInternal(
  315. Positions ? *Positions : TArray<FVector>(),
  316. Normals ? *Normals : TArray<FVector>(),
  317. Tangents ? *Tangents : TArray<FRuntimeMeshTangent>(),
  318. UV0s ? *UV0s : TArray<FVector2D>(),
  319. UV1s ? *UV1s : TArray<FVector2D>(),
  320. Colors ? *Colors : TArray<FColor>());
  321. if (BoundingBox)
  322. {
  323. LocalBoundingBox = *BoundingBox;
  324. }
  325. else
  326. {
  327. LocalBoundingBox = FBox(*Positions);
  328. }
  329. if (bShouldMoveArray)
  330. {
  331. // This is just to keep similar behavior to the packed vertices builder.
  332. Vertices.Reset();
  333. }
  334. }
  335. else
  336. {
  337. // Make sure section type is the same
  338. Vertices.GetVertexType()->EnsureEquals<VertexType>();
  339. FRuntimeMeshPackedVerticesBuilder<VertexType>* VerticesBuilder = static_cast<FRuntimeMeshPackedVerticesBuilder<VertexType>*>(&Vertices);
  340. RuntimeMeshSectionInternal::UpdateVertexBufferInternal<VertexType>(VertexBuffer, LocalBoundingBox, *VerticesBuilder->GetVertices(), BoundingBox, bShouldMoveArray);
  341. if (BoundingBox == nullptr && VerticesBuilder->WantsSeparatePositionBuffer())
  342. {
  343. LocalBoundingBox = FBox(*VerticesBuilder->GetPositions());
  344. }
  345. }
  346. }
  347. virtual FRuntimeMeshSectionCreateDataInterface* GetSectionCreationData(FSceneInterface* InScene, UMaterialInterface* InMaterial) const override
  348. {
  349. auto UpdateData = new FRuntimeMeshSectionCreateData<VertexType>();
  350. FMaterialRelevance MaterialRelevance = (InMaterial != nullptr)
  351. ? InMaterial->GetRelevance(InScene->GetFeatureLevel())
  352. : UMaterial::GetDefaultMaterial(MD_Surface)->GetRelevance(InScene->GetFeatureLevel());
  353. // Create new section proxy based on whether we need separate position buffer
  354. if (IsDualBufferSection())
  355. {
  356. UpdateData->NewProxy = new FRuntimeMeshSectionProxy<VertexType, true>(InScene, UpdateFrequency, bIsVisible, bCastsShadow, InMaterial, MaterialRelevance);
  357. UpdateData->PositionVertexBuffer = PositionVertexBuffer;
  358. }
  359. else
  360. {
  361. UpdateData->NewProxy = new FRuntimeMeshSectionProxy<VertexType, false>(InScene, UpdateFrequency, bIsVisible, bCastsShadow, InMaterial, MaterialRelevance);
  362. }
  363. const_cast<FRuntimeMeshSection*>(this)->bShouldUseAdjacencyIndexBuffer = UpdateData->NewProxy->ShouldUseAdjacencyIndexBuffer();
  364. UpdateData->VertexBuffer = VertexBuffer;
  365. // Switch between normal/tessellation indices
  366. if (bShouldUseAdjacencyIndexBuffer && TessellationIndexBuffer.Num() > 0)
  367. {
  368. UpdateData->IndexBuffer = TessellationIndexBuffer;
  369. UpdateData->bIsAdjacencyIndexBuffer = true;
  370. }
  371. else
  372. {
  373. UpdateData->IndexBuffer = IndexBuffer;
  374. UpdateData->bIsAdjacencyIndexBuffer = false;
  375. }
  376. return UpdateData;
  377. }
  378. virtual FRuntimeMeshRenderThreadCommandInterface* GetSectionUpdateData(bool bIncludePositionVertices, bool bIncludeVertices, bool bIncludeIndices) const override
  379. {
  380. auto UpdateData = new FRuntimeMeshSectionUpdateData<VertexType>();
  381. UpdateData->bIncludeVertexBuffer = bIncludeVertices;
  382. UpdateData->bIncludePositionBuffer = bIncludePositionVertices;
  383. UpdateData->bIncludeIndices = bIncludeIndices;
  384. if (bIncludePositionVertices)
  385. {
  386. UpdateData->PositionVertexBuffer = PositionVertexBuffer;
  387. }
  388. if (bIncludeVertices)
  389. {
  390. UpdateData->VertexBuffer = VertexBuffer;
  391. }
  392. if (bIncludeIndices)
  393. {
  394. if (bShouldUseAdjacencyIndexBuffer && TessellationIndexBuffer.Num() > 0)
  395. {
  396. UpdateData->IndexBuffer = TessellationIndexBuffer;
  397. UpdateData->bIsAdjacencyIndexBuffer = true;
  398. }
  399. else
  400. {
  401. UpdateData->IndexBuffer = IndexBuffer;
  402. UpdateData->bIsAdjacencyIndexBuffer = false;
  403. }
  404. }
  405. return UpdateData;
  406. }
  407. virtual FRuntimeMeshRenderThreadCommandInterface* GetSectionPositionUpdateData() const override
  408. {
  409. auto UpdateData = new FRuntimeMeshSectionPositionOnlyUpdateData<VertexType>();
  410. UpdateData->PositionVertexBuffer = PositionVertexBuffer;
  411. return UpdateData;
  412. }
  413. #if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 13
  414. virtual int32 GetCollisionInformation(TArray<FVector>& Positions, TArray<TArray<FVector2D>>& UVs, bool bIncludeUVs) override
  415. #else
  416. virtual int32 GetCollisionInformation(TArray<FVector>& Positions) override
  417. #endif
  418. {
  419. FRuntimeMeshPackedVerticesBuilder<VertexType> VerticesBuilder(&VertexBuffer, bNeedsPositionOnlyBuffer ? &PositionVertexBuffer : nullptr);
  420. int32 PositionStart = Positions.Num();
  421. Positions.SetNum(PositionStart + VerticesBuilder.Length());
  422. #if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 13
  423. if (bIncludeUVs)
  424. {
  425. UVs[0].SetNumZeroed(PositionStart + VerticesBuilder.Length());
  426. }
  427. #endif
  428. for (int VertexIdx = 0; VertexIdx < VerticesBuilder.Length(); VertexIdx++)
  429. {
  430. Positions[PositionStart + VertexIdx] = VerticesBuilder.GetPosition(VertexIdx);
  431. #if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 13
  432. if (bIncludeUVs && VerticesBuilder.HasUVComponent(0))
  433. {
  434. UVs[0][PositionStart + VertexIdx] = VerticesBuilder.GetUV(0);
  435. }
  436. #endif
  437. }
  438. return VerticesBuilder.Length();
  439. }
  440. virtual void GetSectionMesh(IRuntimeMeshVerticesBuilder*& Vertices, FRuntimeMeshIndicesBuilder*& Indices) override
  441. {
  442. Vertices = new FRuntimeMeshPackedVerticesBuilder<VertexType>(&VertexBuffer);
  443. Indices = new FRuntimeMeshIndicesBuilder(&IndexBuffer);
  444. }
  445. virtual const FRuntimeMeshVertexTypeInfo* GetVertexType() const { return &VertexType::TypeInfo; }
  446. virtual void GenerateNormalTangent()
  447. {
  448. if (IsDualBufferSection())
  449. {
  450. URuntimeMeshLibrary::CalculateTangentsForMesh<VertexType>(PositionVertexBuffer, VertexBuffer, IndexBuffer);
  451. }
  452. else
  453. {
  454. URuntimeMeshLibrary::CalculateTangentsForMesh<VertexType>(VertexBuffer, IndexBuffer);
  455. }
  456. }
  457. virtual void GenerateTessellationIndices()
  458. {
  459. TArray<int32> TessellationIndices;
  460. if (IsDualBufferSection())
  461. {
  462. URuntimeMeshLibrary::GenerateTessellationIndexBuffer<VertexType>(PositionVertexBuffer, VertexBuffer, IndexBuffer, TessellationIndices);
  463. }
  464. else
  465. {
  466. URuntimeMeshLibrary::GenerateTessellationIndexBuffer<VertexType>(VertexBuffer, IndexBuffer, TessellationIndices);
  467. }
  468. UpdateTessellationIndexBuffer(TessellationIndices, true);
  469. }
  470. virtual void RecalculateBoundingBox() override
  471. {
  472. LocalBoundingBox.Init();
  473. if (IsDualBufferSection())
  474. {
  475. for (int32 Index = 0; Index < PositionVertexBuffer.Num(); Index++)
  476. {
  477. LocalBoundingBox += PositionVertexBuffer[Index];
  478. }
  479. }
  480. else
  481. {
  482. RuntimeMeshSectionInternal::RecalculateBoundingBox<VertexType>(VertexBuffer, LocalBoundingBox);
  483. }
  484. }
  485. virtual void GetInternalVertexComponents(int32& NumUVChannels, bool& WantsHalfPrecisionUVs) override
  486. {
  487. NumUVChannels = FRuntimeMeshVertexTraits<VertexType>::NumUVChannels;
  488. WantsHalfPrecisionUVs = !FRuntimeMeshVertexTraits<VertexType>::HasHighPrecisionUVs;
  489. }
  490. virtual bool UpdateVertexBufferInternal(const TArray<FVector>& Positions, const TArray<FVector>& Normals, const TArray<FRuntimeMeshTangent>& Tangents, const TArray<FVector2D>& UV0, const TArray<FVector2D>& UV1, const TArray<FColor>& Colors) override
  491. {
  492. // Check existence of data components
  493. const bool HasPositions = Positions.Num() > 0;
  494. int32 NewVertexCount = HasPositions ? Positions.Num() : VertexBuffer.Num();
  495. int32 OldVertexCount = FMath::Min(VertexBuffer.Num(), NewVertexCount);
  496. // Size the vertex buffer correctly
  497. if (NewVertexCount != VertexBuffer.Num())
  498. {
  499. VertexBuffer.SetNumZeroed(NewVertexCount);
  500. }
  501. // Clear the bounding box if we have new positions
  502. if (HasPositions)
  503. {
  504. LocalBoundingBox.Init();
  505. }
  506. FRuntimeMeshPackedVerticesBuilder<VertexType> VerticesBuilder(&VertexBuffer);
  507. // Loop through existing range to update data
  508. for (int32 VertexIdx = 0; VertexIdx < OldVertexCount; VertexIdx++)
  509. {
  510. VerticesBuilder.Seek(VertexIdx);
  511. // Update position and bounding box
  512. if (HasPositions)
  513. {
  514. VerticesBuilder.SetPosition(Positions[VertexIdx]);
  515. LocalBoundingBox += Positions[VertexIdx];
  516. }
  517. // see if we have a new normal and/or tangent
  518. bool HasNormal = Normals.Num() > VertexIdx;
  519. bool HasTangent = Tangents.Num() > VertexIdx;
  520. // Update normal and tangent together
  521. if (HasNormal && HasTangent)
  522. {
  523. FVector4 NewNormal(Normals[VertexIdx], Tangents[VertexIdx].bFlipTangentY ? -1.0f : 1.0f);
  524. VerticesBuilder.SetNormal(NewNormal);
  525. VerticesBuilder.SetTangent(Tangents[VertexIdx].TangentX);
  526. }
  527. // Else update only normal keeping the W component
  528. else if (HasNormal)
  529. {
  530. float W = VerticesBuilder.GetNormal().W;
  531. VerticesBuilder.SetNormal(FVector4(Normals[VertexIdx], W));
  532. }
  533. // Else update tangent updating the normals W component
  534. else if (HasTangent)
  535. {
  536. FVector4 Normal = VerticesBuilder.GetNormal();
  537. Normal.W = Tangents[VertexIdx].bFlipTangentY ? -1.0f : 1.0f;
  538. VerticesBuilder.SetNormal(Normal);
  539. VerticesBuilder.SetTangent(Tangents[VertexIdx].TangentX);
  540. }
  541. // Update color
  542. if (Colors.Num() > VertexIdx)
  543. {
  544. VerticesBuilder.SetColor(Colors[VertexIdx]);
  545. }
  546. // Update UV0
  547. if (UV0.Num() > VertexIdx)
  548. {
  549. VerticesBuilder.SetUV(0, UV0[VertexIdx]);
  550. }
  551. // Update UV1 if needed
  552. if (UV1.Num() > VertexIdx && VerticesBuilder.HasUVComponent(1))
  553. {
  554. VerticesBuilder.SetUV(1, UV1[VertexIdx]);
  555. }
  556. }
  557. // Loop through additional range to add new data
  558. for (int32 VertexIdx = OldVertexCount; VertexIdx < NewVertexCount; VertexIdx++)
  559. {
  560. VerticesBuilder.Seek(VertexIdx);
  561. // Set position
  562. VerticesBuilder.SetPosition(Positions[VertexIdx]);
  563. // Update bounding box
  564. LocalBoundingBox += Positions[VertexIdx];
  565. // see if we have a new normal and/or tangent
  566. bool HasNormal = Normals.Num() > VertexIdx;
  567. bool HasTangent = Tangents.Num() > VertexIdx;
  568. // Set normal and tangent both
  569. if (HasNormal && HasTangent)
  570. {
  571. FVector4 NewNormal(Normals[VertexIdx], Tangents[VertexIdx].bFlipTangentY ? -1.0f : 1.0f);
  572. VerticesBuilder.SetNormal(NewNormal);
  573. VerticesBuilder.SetTangent(Tangents[VertexIdx].TangentX);
  574. }
  575. // Set normal and default tangent
  576. else if (HasNormal)
  577. {
  578. VerticesBuilder.SetNormal(FVector4(Normals[VertexIdx], 1.0f));
  579. VerticesBuilder.SetTangent(FVector(1.0f, 0.0f, 0.0f));
  580. }
  581. // Default normal and set tangent
  582. else if (HasTangent)
  583. {
  584. VerticesBuilder.SetNormal(FVector4(0.0f, 0.0f, 1.0f, Tangents[VertexIdx].bFlipTangentY ? -1.0f : 1.0f));
  585. VerticesBuilder.SetTangent(Tangents[VertexIdx].TangentX);
  586. }
  587. // Default normal and tangent
  588. else
  589. {
  590. VerticesBuilder.SetNormal(FVector4(0.0f, 0.0f, 1.0f, 1.0f));
  591. VerticesBuilder.SetTangent(FVector(1.0f, 0.0f, 0.0f));
  592. }
  593. // Set color or default
  594. VerticesBuilder.SetColor(Colors.Num() > VertexIdx ? Colors[VertexIdx] : FColor::White);
  595. // Update UV0
  596. VerticesBuilder.SetUV(0, UV0.Num() > VertexIdx ? UV0[VertexIdx] : FVector2D::ZeroVector);
  597. // Update UV1 if needed
  598. if (VerticesBuilder.HasUVComponent(1))
  599. {
  600. VerticesBuilder.SetUV(1, UV1.Num() > VertexIdx ? UV1[VertexIdx] : FVector2D::ZeroVector);
  601. }
  602. }
  603. return true;
  604. }
  605. private:
  606. void SerializeLegacy(FArchive& Ar)
  607. {
  608. int32 VertexBufferLength = VertexBuffer.Num();
  609. Ar << VertexBufferLength;
  610. if (Ar.IsLoading())
  611. {
  612. VertexBuffer.SetNum(VertexBufferLength);
  613. FRuntimeMeshPackedVerticesBuilder<VertexType> VerticesBuilder(&VertexBuffer);
  614. for (int32 Index = 0; Index < VertexBufferLength; Index++)
  615. {
  616. VerticesBuilder.Seek(Index);
  617. FVector TempPosition;
  618. Ar << TempPosition;
  619. VerticesBuilder.SetPosition(TempPosition);
  620. FPackedNormal TempNormal;
  621. Ar << TempNormal;
  622. VerticesBuilder.SetNormal(TempNormal);
  623. Ar << TempNormal;
  624. VerticesBuilder.SetTangent(TempNormal);
  625. FColor TempColor;
  626. Ar << TempColor;
  627. VerticesBuilder.SetColor(TempColor);
  628. if (FRuntimeMeshVertexTraits<VertexType>::HasHighPrecisionUVs)
  629. {
  630. FVector2D TempUV;
  631. Ar << TempUV;
  632. VerticesBuilder.SetUV(0, TempUV);
  633. if (FRuntimeMeshVertexTraits<VertexType>::NumUVChannels > 1)
  634. {
  635. Ar << TempUV;
  636. VerticesBuilder.SetUV(1, TempUV);
  637. }
  638. }
  639. else
  640. {
  641. FVector2DHalf TempUV;
  642. Ar << TempUV;
  643. VerticesBuilder.SetUV(0, TempUV);
  644. if (FRuntimeMeshVertexTraits<VertexType>::NumUVChannels > 1)
  645. {
  646. Ar << TempUV;
  647. VerticesBuilder.SetUV(1, TempUV);
  648. }
  649. }
  650. }
  651. }
  652. else
  653. {
  654. check(false && "Cannot use legacy save.");
  655. }
  656. }
  657. public:
  658. virtual void Serialize(FArchive& Ar) override
  659. {
  660. if (Ar.CustomVer(FRuntimeMeshVersion::GUID) >= FRuntimeMeshVersion::SerializationV2)
  661. {
  662. Ar << VertexBuffer;
  663. FRuntimeMeshSectionInterface::Serialize(Ar);
  664. }
  665. else
  666. {
  667. FRuntimeMeshSectionInterface::Serialize(Ar);
  668. SerializeLegacy(Ar);
  669. }
  670. }
  671. friend class URuntimeMeshComponent;
  672. };
  673. /** Smart pointer to a Runtime Mesh Section */
  674. using RuntimeMeshSectionPtr = TSharedPtr<FRuntimeMeshSectionInterface>;