| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812 |
- // Copyright 2016 Chris Conway (Koderz). All Rights Reserved.
- #pragma once
- #include "Engine.h"
- #include "Components/MeshComponent.h"
- #include "RuntimeMeshProfiling.h"
- #include "RuntimeMeshVersion.h"
- #include "RuntimeMeshSectionProxy.h"
- #include "RuntimeMeshBuilder.h"
- #include "RuntimeMeshLibrary.h"
- /** Interface class for a single mesh section */
- class FRuntimeMeshSectionInterface
- {
- protected:
- const bool bNeedsPositionOnlyBuffer;
- public:
- /** Position only vertex buffer for this section */
- TArray<FVector> PositionVertexBuffer;
- /** Index buffer for this section */
- TArray<int32> IndexBuffer;
- /** Index buffer used for tessellation containing the needed adjacency info */
- TArray<int32> TessellationIndexBuffer;
- /** Local bounding box of section */
- FBox LocalBoundingBox;
- /** Should we build collision data for triangles in this section */
- bool CollisionEnabled;
- /** Should we display this section */
- bool bIsVisible;
- /** Should this section cast a shadow */
- bool bCastsShadow;
- /** If this section is currently using an adjacency index buffer */
- bool bShouldUseAdjacencyIndexBuffer;
- /** Update frequency of this section */
- EUpdateFrequency UpdateFrequency;
- FRuntimeMeshSectionInterface(bool bInNeedsPositionOnlyBuffer) :
- bNeedsPositionOnlyBuffer(bInNeedsPositionOnlyBuffer),
- LocalBoundingBox(EForceInit::ForceInitToZero),
- CollisionEnabled(false),
- bIsVisible(true),
- bCastsShadow(true),
- bIsLegacySectionType(false)
- {}
- virtual ~FRuntimeMeshSectionInterface() { }
- protected:
- /** Is this an internal section type. */
- bool bIsLegacySectionType;
- bool IsDualBufferSection() const { return bNeedsPositionOnlyBuffer; }
- /* Updates the vertex position buffer, returns whether we have a new bounding box */
- bool UpdateVertexPositionBuffer(TArray<FVector>& Positions, const FBox* BoundingBox, bool bShouldMoveArray)
- {
- // Holds the new bounding box after this update.
- FBox NewBoundingBox(EForceInit::ForceInitToZero);
- if (bShouldMoveArray)
- {
- // Move buffer data
- PositionVertexBuffer = MoveTemp(Positions);
- // Calculate the bounding box if one doesn't exist.
- if (BoundingBox == nullptr)
- {
- for (int32 VertexIdx = 0; VertexIdx < PositionVertexBuffer.Num(); VertexIdx++)
- {
- NewBoundingBox += PositionVertexBuffer[VertexIdx];
- }
- }
- else
- {
- // Copy the supplied bounding box instead of calculating it.
- NewBoundingBox = *BoundingBox;
- }
- }
- else
- {
- if (BoundingBox == nullptr)
- {
- // Copy the buffer and calculate the bounding box at the same time
- int32 NumVertices = Positions.Num();
- PositionVertexBuffer.SetNumUninitialized(NumVertices);
- for (int32 VertexIdx = 0; VertexIdx < NumVertices; VertexIdx++)
- {
- NewBoundingBox += Positions[VertexIdx];
- PositionVertexBuffer[VertexIdx] = Positions[VertexIdx];
- }
- }
- else
- {
- // Copy the buffer
- PositionVertexBuffer = Positions;
- // Copy the supplied bounding box instead of calculating it.
- NewBoundingBox = *BoundingBox;
- }
- }
- // Update the bounding box if necessary and alert our caller if we did
- if (!(LocalBoundingBox == NewBoundingBox))
- {
- LocalBoundingBox = NewBoundingBox;
- return true;
- }
- return false;
- }
- virtual void UpdateVertexBuffer(IRuntimeMeshVerticesBuilder& Vertices, const FBox* BoundingBox, bool bShouldMoveArray) = 0;
- void UpdateIndexBuffer(TArray<int32>& Triangles, bool bShouldMoveArray)
- {
- if (bShouldMoveArray)
- {
- IndexBuffer = MoveTemp(Triangles);
- }
- else
- {
- IndexBuffer = Triangles;
- }
- }
- void UpdateIndexBuffer(FRuntimeMeshIndicesBuilder& Triangles, bool bShouldMoveArray)
- {
- if (bShouldMoveArray)
- {
- IndexBuffer = MoveTemp(*Triangles.GetIndices());
- Triangles.Reset();
- }
- else
- {
- IndexBuffer = *Triangles.GetIndices();
- }
- }
- void UpdateTessellationIndexBuffer(TArray<int32>& Triangles, bool bShouldMoveArray)
- {
- if (bShouldMoveArray)
- {
- TessellationIndexBuffer = MoveTemp(Triangles);
- }
- else
- {
- TessellationIndexBuffer = Triangles;
- }
- }
- virtual FRuntimeMeshSectionCreateDataInterface* GetSectionCreationData(FSceneInterface* InScene, UMaterialInterface* InMaterial) const = 0;
- virtual FRuntimeMeshRenderThreadCommandInterface* GetSectionUpdateData(bool bIncludePositionVertices, bool bIncludeVertices, bool bIncludeIndices) const = 0;
- virtual FRuntimeMeshRenderThreadCommandInterface* GetSectionPositionUpdateData() const = 0;
- virtual void RecalculateBoundingBox() = 0;
- #if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 13
- virtual int32 GetCollisionInformation(TArray<FVector>& Positions, TArray<TArray<FVector2D>>& UVs, bool bIncludeUVs) = 0;
- #else
- virtual int32 GetCollisionInformation(TArray<FVector>& Positions) = 0;
- #endif
- virtual void GetInternalVertexComponents(int32& NumUVChannels, bool& WantsHalfPrecisionUVs) { }
- // This is only meant for internal use for supporting the old style create/update sections
- 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; }
-
- virtual void GetSectionMesh(IRuntimeMeshVerticesBuilder*& Vertices, FRuntimeMeshIndicesBuilder*& Indices) = 0;
- virtual const FRuntimeMeshVertexTypeInfo* GetVertexType() const = 0;
- virtual void GenerateNormalTangent() = 0;
- virtual void GenerateTessellationIndices() = 0;
- virtual void Serialize(FArchive& Ar)
- {
- if (Ar.CustomVer(FRuntimeMeshVersion::GUID) >= FRuntimeMeshVersion::SerializationV2)
- {
- if (bNeedsPositionOnlyBuffer)
- {
- Ar << PositionVertexBuffer;
- }
- Ar << IndexBuffer;
- Ar << TessellationIndexBuffer;
- Ar << LocalBoundingBox;
- Ar << CollisionEnabled;
- Ar << bIsVisible;
- Ar << bCastsShadow;
- Ar << bShouldUseAdjacencyIndexBuffer;
- // Serialize the update frequency as an int32
- int32 UpdateFreq = (int32)UpdateFrequency;
- Ar << UpdateFreq;
- UpdateFrequency = (EUpdateFrequency)UpdateFreq;
- Ar << bIsLegacySectionType;
- }
- else
- {
- if (Ar.CustomVer(FRuntimeMeshVersion::GUID) >= FRuntimeMeshVersion::DualVertexBuffer)
- {
- Ar << PositionVertexBuffer;
- }
- Ar << IndexBuffer;
- Ar << LocalBoundingBox;
- Ar << CollisionEnabled;
- Ar << bIsVisible;
- int32 UpdateFreq = (int32)UpdateFrequency;
- Ar << UpdateFreq;
- UpdateFrequency = (EUpdateFrequency)UpdateFreq;
- }
- }
-
- friend class FRuntimeMeshSceneProxy;
- friend class URuntimeMeshComponent;
- };
- namespace RuntimeMeshSectionInternal
- {
- template<typename Type>
- static typename TEnableIf<FRuntimeMeshVertexTraits<Type>::HasPosition, int32>::Type
- GetAllVertexPositions(const TArray<Type>& VertexBuffer, const TArray<FVector>& PositionVertexBuffer, TArray<FVector>& Positions)
- {
- int32 VertexCount = VertexBuffer.Num();
- for (int32 VertIdx = 0; VertIdx < VertexCount; VertIdx++)
- {
- Positions.Add(VertexBuffer[VertIdx].Position);
- }
- return VertexCount;
- }
- template<typename Type>
- static typename TEnableIf<!FRuntimeMeshVertexTraits<Type>::HasPosition, int32>::Type
- GetAllVertexPositions(const TArray<Type>& VertexBuffer, const TArray<FVector>& PositionVertexBuffer, TArray<FVector>& Positions)
- {
- Positions.Append(PositionVertexBuffer);
- return PositionVertexBuffer.Num();
- }
- template<typename Type>
- static typename TEnableIf<FRuntimeMeshVertexTraits<Type>::HasPosition, bool>::Type
- UpdateVertexBufferInternal(TArray<Type>& VertexBuffer, FBox& LocalBoundingBox, TArray<Type>& Vertices, const FBox* BoundingBox, bool bShouldMoveArray)
- {
- // Holds the new bounding box after this update.
- FBox NewBoundingBox(EForceInit::ForceInitToZero);
- if (bShouldMoveArray)
- {
- // Move buffer data
- VertexBuffer = MoveTemp(Vertices);
- // Calculate the bounding box if one doesn't exist.
- if (BoundingBox == nullptr)
- {
- for (int32 VertexIdx = 0; VertexIdx < VertexBuffer.Num(); VertexIdx++)
- {
- NewBoundingBox += VertexBuffer[VertexIdx].Position;
- }
- }
- else
- {
- // Copy the supplied bounding box instead of calculating it.
- NewBoundingBox = *BoundingBox;
- }
- }
- else
- {
- if (BoundingBox == nullptr)
- {
- // Copy the buffer and calculate the bounding box at the same time
- int32 NumVertices = Vertices.Num();
- VertexBuffer.SetNumUninitialized(NumVertices);
- for (int32 VertexIdx = 0; VertexIdx < NumVertices; VertexIdx++)
- {
- NewBoundingBox += Vertices[VertexIdx].Position;
- VertexBuffer[VertexIdx] = Vertices[VertexIdx];
- }
- }
- else
- {
- // Copy the buffer
- VertexBuffer = Vertices;
- // Copy the supplied bounding box instead of calculating it.
- NewBoundingBox = *BoundingBox;
- }
- }
- // Update the bounding box if necessary and alert our caller if we did
- if (!(LocalBoundingBox == NewBoundingBox))
- {
- LocalBoundingBox = NewBoundingBox;
- return true;
- }
- return false;
- }
- template<typename Type>
- static typename TEnableIf<!FRuntimeMeshVertexTraits<Type>::HasPosition, bool>::Type
- UpdateVertexBufferInternal(TArray<Type>& VertexBuffer, FBox& LocalBoundingBox, TArray<Type>& Vertices, const FBox* BoundingBox, bool bShouldMoveArray)
- {
- if (bShouldMoveArray)
- {
- VertexBuffer = MoveTemp(Vertices);
- }
- else
- {
- VertexBuffer = Vertices;
- }
- return false;
- }
- template<typename Type>
- static typename TEnableIf<FRuntimeMeshVertexTraits<Type>::HasPosition>::Type RecalculateBoundingBox(TArray<Type>& VertexBuffer, FBox& BoundingBox)
- {
- for (int32 Index = 0; Index < VertexBuffer.Num(); Index++)
- {
- BoundingBox += VertexBuffer[Index].Position;
- }
- }
- template<typename Type>
- static typename TEnableIf<!FRuntimeMeshVertexTraits<Type>::HasPosition>::Type RecalculateBoundingBox(TArray<Type>& VertexBuffer, FBox& BoundingBox)
- {
- }
- }
- /** Templated class for a single mesh section */
- template<typename VertexType>
- class FRuntimeMeshSection : public FRuntimeMeshSectionInterface
- {
- public:
- /** Vertex buffer for this section */
- TArray<VertexType> VertexBuffer;
- FRuntimeMeshSection(bool bInNeedsPositionOnlyBuffer) : FRuntimeMeshSectionInterface(bInNeedsPositionOnlyBuffer) { }
- virtual ~FRuntimeMeshSection() override { }
- protected:
- bool UpdateVertexBuffer(TArray<VertexType>& Vertices, const FBox* BoundingBox, bool bShouldMoveArray)
- {
- return RuntimeMeshSectionInternal::UpdateVertexBufferInternal<VertexType>(VertexBuffer, LocalBoundingBox, Vertices, BoundingBox, bShouldMoveArray);
- }
- virtual void UpdateVertexBuffer(IRuntimeMeshVerticesBuilder& Vertices, const FBox* BoundingBox, bool bShouldMoveArray) override
- {
- if (Vertices.GetBuilderType() == ERuntimeMeshVerticesBuilderType::Component)
- {
- FRuntimeMeshComponentVerticesBuilder* VerticesBuilder = static_cast<FRuntimeMeshComponentVerticesBuilder*>(&Vertices);
- TArray<FVector>* Positions = VerticesBuilder->GetPositions();
- TArray<FVector>* Normals = VerticesBuilder->GetNormals();
- TArray<FRuntimeMeshTangent>* Tangents = VerticesBuilder->GetTangents();
- TArray<FColor>* Colors = VerticesBuilder->GetColors();
- TArray<FVector2D>* UV0s = VerticesBuilder->GetUV0s();
- TArray<FVector2D>* UV1s = VerticesBuilder->GetUV1s();
-
- UpdateVertexBufferInternal(
- Positions ? *Positions : TArray<FVector>(),
- Normals ? *Normals : TArray<FVector>(),
- Tangents ? *Tangents : TArray<FRuntimeMeshTangent>(),
- UV0s ? *UV0s : TArray<FVector2D>(),
- UV1s ? *UV1s : TArray<FVector2D>(),
- Colors ? *Colors : TArray<FColor>());
- if (BoundingBox)
- {
- LocalBoundingBox = *BoundingBox;
- }
- else
- {
- LocalBoundingBox = FBox(*Positions);
- }
- if (bShouldMoveArray)
- {
- // This is just to keep similar behavior to the packed vertices builder.
- Vertices.Reset();
- }
- }
- else
- {
- // Make sure section type is the same
- Vertices.GetVertexType()->EnsureEquals<VertexType>();
- FRuntimeMeshPackedVerticesBuilder<VertexType>* VerticesBuilder = static_cast<FRuntimeMeshPackedVerticesBuilder<VertexType>*>(&Vertices);
- RuntimeMeshSectionInternal::UpdateVertexBufferInternal<VertexType>(VertexBuffer, LocalBoundingBox, *VerticesBuilder->GetVertices(), BoundingBox, bShouldMoveArray);
- if (BoundingBox == nullptr && VerticesBuilder->WantsSeparatePositionBuffer())
- {
- LocalBoundingBox = FBox(*VerticesBuilder->GetPositions());
- }
- }
- }
- virtual FRuntimeMeshSectionCreateDataInterface* GetSectionCreationData(FSceneInterface* InScene, UMaterialInterface* InMaterial) const override
- {
- auto UpdateData = new FRuntimeMeshSectionCreateData<VertexType>();
- FMaterialRelevance MaterialRelevance = (InMaterial != nullptr)
- ? InMaterial->GetRelevance(InScene->GetFeatureLevel())
- : UMaterial::GetDefaultMaterial(MD_Surface)->GetRelevance(InScene->GetFeatureLevel());
- // Create new section proxy based on whether we need separate position buffer
- if (IsDualBufferSection())
- {
- UpdateData->NewProxy = new FRuntimeMeshSectionProxy<VertexType, true>(InScene, UpdateFrequency, bIsVisible, bCastsShadow, InMaterial, MaterialRelevance);
- UpdateData->PositionVertexBuffer = PositionVertexBuffer;
- }
- else
- {
- UpdateData->NewProxy = new FRuntimeMeshSectionProxy<VertexType, false>(InScene, UpdateFrequency, bIsVisible, bCastsShadow, InMaterial, MaterialRelevance);
- }
- const_cast<FRuntimeMeshSection*>(this)->bShouldUseAdjacencyIndexBuffer = UpdateData->NewProxy->ShouldUseAdjacencyIndexBuffer();
- UpdateData->VertexBuffer = VertexBuffer;
- // Switch between normal/tessellation indices
- if (bShouldUseAdjacencyIndexBuffer && TessellationIndexBuffer.Num() > 0)
- {
- UpdateData->IndexBuffer = TessellationIndexBuffer;
- UpdateData->bIsAdjacencyIndexBuffer = true;
- }
- else
- {
- UpdateData->IndexBuffer = IndexBuffer;
- UpdateData->bIsAdjacencyIndexBuffer = false;
- }
- return UpdateData;
- }
- virtual FRuntimeMeshRenderThreadCommandInterface* GetSectionUpdateData(bool bIncludePositionVertices, bool bIncludeVertices, bool bIncludeIndices) const override
- {
- auto UpdateData = new FRuntimeMeshSectionUpdateData<VertexType>();
- UpdateData->bIncludeVertexBuffer = bIncludeVertices;
- UpdateData->bIncludePositionBuffer = bIncludePositionVertices;
- UpdateData->bIncludeIndices = bIncludeIndices;
- if (bIncludePositionVertices)
- {
- UpdateData->PositionVertexBuffer = PositionVertexBuffer;
- }
- if (bIncludeVertices)
- {
- UpdateData->VertexBuffer = VertexBuffer;
- }
- if (bIncludeIndices)
- {
- if (bShouldUseAdjacencyIndexBuffer && TessellationIndexBuffer.Num() > 0)
- {
- UpdateData->IndexBuffer = TessellationIndexBuffer;
- UpdateData->bIsAdjacencyIndexBuffer = true;
- }
- else
- {
- UpdateData->IndexBuffer = IndexBuffer;
- UpdateData->bIsAdjacencyIndexBuffer = false;
- }
- }
- return UpdateData;
- }
- virtual FRuntimeMeshRenderThreadCommandInterface* GetSectionPositionUpdateData() const override
- {
- auto UpdateData = new FRuntimeMeshSectionPositionOnlyUpdateData<VertexType>();
- UpdateData->PositionVertexBuffer = PositionVertexBuffer;
- return UpdateData;
- }
- #if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 13
- virtual int32 GetCollisionInformation(TArray<FVector>& Positions, TArray<TArray<FVector2D>>& UVs, bool bIncludeUVs) override
- #else
- virtual int32 GetCollisionInformation(TArray<FVector>& Positions) override
- #endif
- {
- FRuntimeMeshPackedVerticesBuilder<VertexType> VerticesBuilder(&VertexBuffer, bNeedsPositionOnlyBuffer ? &PositionVertexBuffer : nullptr);
- int32 PositionStart = Positions.Num();
- Positions.SetNum(PositionStart + VerticesBuilder.Length());
- #if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 13
- if (bIncludeUVs)
- {
- UVs[0].SetNumZeroed(PositionStart + VerticesBuilder.Length());
- }
- #endif
- for (int VertexIdx = 0; VertexIdx < VerticesBuilder.Length(); VertexIdx++)
- {
- Positions[PositionStart + VertexIdx] = VerticesBuilder.GetPosition(VertexIdx);
- #if ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION >= 13
- if (bIncludeUVs && VerticesBuilder.HasUVComponent(0))
- {
- UVs[0][PositionStart + VertexIdx] = VerticesBuilder.GetUV(0);
- }
- #endif
- }
- return VerticesBuilder.Length();
- }
- virtual void GetSectionMesh(IRuntimeMeshVerticesBuilder*& Vertices, FRuntimeMeshIndicesBuilder*& Indices) override
- {
- Vertices = new FRuntimeMeshPackedVerticesBuilder<VertexType>(&VertexBuffer);
- Indices = new FRuntimeMeshIndicesBuilder(&IndexBuffer);
- }
- virtual const FRuntimeMeshVertexTypeInfo* GetVertexType() const { return &VertexType::TypeInfo; }
- virtual void GenerateNormalTangent()
- {
- if (IsDualBufferSection())
- {
- URuntimeMeshLibrary::CalculateTangentsForMesh<VertexType>(PositionVertexBuffer, VertexBuffer, IndexBuffer);
- }
- else
- {
- URuntimeMeshLibrary::CalculateTangentsForMesh<VertexType>(VertexBuffer, IndexBuffer);
- }
- }
- virtual void GenerateTessellationIndices()
- {
- TArray<int32> TessellationIndices;
- if (IsDualBufferSection())
- {
- URuntimeMeshLibrary::GenerateTessellationIndexBuffer<VertexType>(PositionVertexBuffer, VertexBuffer, IndexBuffer, TessellationIndices);
- }
- else
- {
- URuntimeMeshLibrary::GenerateTessellationIndexBuffer<VertexType>(VertexBuffer, IndexBuffer, TessellationIndices);
- }
- UpdateTessellationIndexBuffer(TessellationIndices, true);
- }
- virtual void RecalculateBoundingBox() override
- {
- LocalBoundingBox.Init();
- if (IsDualBufferSection())
- {
- for (int32 Index = 0; Index < PositionVertexBuffer.Num(); Index++)
- {
- LocalBoundingBox += PositionVertexBuffer[Index];
- }
- }
- else
- {
- RuntimeMeshSectionInternal::RecalculateBoundingBox<VertexType>(VertexBuffer, LocalBoundingBox);
- }
- }
- virtual void GetInternalVertexComponents(int32& NumUVChannels, bool& WantsHalfPrecisionUVs) override
- {
- NumUVChannels = FRuntimeMeshVertexTraits<VertexType>::NumUVChannels;
- WantsHalfPrecisionUVs = !FRuntimeMeshVertexTraits<VertexType>::HasHighPrecisionUVs;
- }
- 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
- {
- // Check existence of data components
- const bool HasPositions = Positions.Num() > 0;
- int32 NewVertexCount = HasPositions ? Positions.Num() : VertexBuffer.Num();
- int32 OldVertexCount = FMath::Min(VertexBuffer.Num(), NewVertexCount);
- // Size the vertex buffer correctly
- if (NewVertexCount != VertexBuffer.Num())
- {
- VertexBuffer.SetNumZeroed(NewVertexCount);
- }
- // Clear the bounding box if we have new positions
- if (HasPositions)
- {
- LocalBoundingBox.Init();
- }
- FRuntimeMeshPackedVerticesBuilder<VertexType> VerticesBuilder(&VertexBuffer);
-
- // Loop through existing range to update data
- for (int32 VertexIdx = 0; VertexIdx < OldVertexCount; VertexIdx++)
- {
- VerticesBuilder.Seek(VertexIdx);
- // Update position and bounding box
- if (HasPositions)
- {
- VerticesBuilder.SetPosition(Positions[VertexIdx]);
- LocalBoundingBox += Positions[VertexIdx];
- }
-
- // see if we have a new normal and/or tangent
- bool HasNormal = Normals.Num() > VertexIdx;
- bool HasTangent = Tangents.Num() > VertexIdx;
- // Update normal and tangent together
- if (HasNormal && HasTangent)
- {
- FVector4 NewNormal(Normals[VertexIdx], Tangents[VertexIdx].bFlipTangentY ? -1.0f : 1.0f);
- VerticesBuilder.SetNormal(NewNormal);
- VerticesBuilder.SetTangent(Tangents[VertexIdx].TangentX);
- }
- // Else update only normal keeping the W component
- else if (HasNormal)
- {
- float W = VerticesBuilder.GetNormal().W;
- VerticesBuilder.SetNormal(FVector4(Normals[VertexIdx], W));
- }
- // Else update tangent updating the normals W component
- else if (HasTangent)
- {
- FVector4 Normal = VerticesBuilder.GetNormal();
- Normal.W = Tangents[VertexIdx].bFlipTangentY ? -1.0f : 1.0f;
- VerticesBuilder.SetNormal(Normal);
- VerticesBuilder.SetTangent(Tangents[VertexIdx].TangentX);
- }
- // Update color
- if (Colors.Num() > VertexIdx)
- {
- VerticesBuilder.SetColor(Colors[VertexIdx]);
- }
- // Update UV0
- if (UV0.Num() > VertexIdx)
- {
- VerticesBuilder.SetUV(0, UV0[VertexIdx]);
- }
- // Update UV1 if needed
- if (UV1.Num() > VertexIdx && VerticesBuilder.HasUVComponent(1))
- {
- VerticesBuilder.SetUV(1, UV1[VertexIdx]);
- }
- }
- // Loop through additional range to add new data
- for (int32 VertexIdx = OldVertexCount; VertexIdx < NewVertexCount; VertexIdx++)
- {
- VerticesBuilder.Seek(VertexIdx);
- // Set position
- VerticesBuilder.SetPosition(Positions[VertexIdx]);
- // Update bounding box
- LocalBoundingBox += Positions[VertexIdx];
- // see if we have a new normal and/or tangent
- bool HasNormal = Normals.Num() > VertexIdx;
- bool HasTangent = Tangents.Num() > VertexIdx;
- // Set normal and tangent both
- if (HasNormal && HasTangent)
- {
- FVector4 NewNormal(Normals[VertexIdx], Tangents[VertexIdx].bFlipTangentY ? -1.0f : 1.0f);
- VerticesBuilder.SetNormal(NewNormal);
- VerticesBuilder.SetTangent(Tangents[VertexIdx].TangentX);
- }
- // Set normal and default tangent
- else if (HasNormal)
- {
- VerticesBuilder.SetNormal(FVector4(Normals[VertexIdx], 1.0f));
- VerticesBuilder.SetTangent(FVector(1.0f, 0.0f, 0.0f));
- }
- // Default normal and set tangent
- else if (HasTangent)
- {
- VerticesBuilder.SetNormal(FVector4(0.0f, 0.0f, 1.0f, Tangents[VertexIdx].bFlipTangentY ? -1.0f : 1.0f));
- VerticesBuilder.SetTangent(Tangents[VertexIdx].TangentX);
- }
- // Default normal and tangent
- else
- {
- VerticesBuilder.SetNormal(FVector4(0.0f, 0.0f, 1.0f, 1.0f));
- VerticesBuilder.SetTangent(FVector(1.0f, 0.0f, 0.0f));
- }
- // Set color or default
- VerticesBuilder.SetColor(Colors.Num() > VertexIdx ? Colors[VertexIdx] : FColor::White);
- // Update UV0
- VerticesBuilder.SetUV(0, UV0.Num() > VertexIdx ? UV0[VertexIdx] : FVector2D::ZeroVector);
- // Update UV1 if needed
- if (VerticesBuilder.HasUVComponent(1))
- {
- VerticesBuilder.SetUV(1, UV1.Num() > VertexIdx ? UV1[VertexIdx] : FVector2D::ZeroVector);
- }
- }
- return true;
- }
- private:
- void SerializeLegacy(FArchive& Ar)
- {
- int32 VertexBufferLength = VertexBuffer.Num();
- Ar << VertexBufferLength;
- if (Ar.IsLoading())
- {
- VertexBuffer.SetNum(VertexBufferLength);
- FRuntimeMeshPackedVerticesBuilder<VertexType> VerticesBuilder(&VertexBuffer);
- for (int32 Index = 0; Index < VertexBufferLength; Index++)
- {
- VerticesBuilder.Seek(Index);
- FVector TempPosition;
- Ar << TempPosition;
- VerticesBuilder.SetPosition(TempPosition);
- FPackedNormal TempNormal;
- Ar << TempNormal;
- VerticesBuilder.SetNormal(TempNormal);
- Ar << TempNormal;
- VerticesBuilder.SetTangent(TempNormal);
- FColor TempColor;
- Ar << TempColor;
- VerticesBuilder.SetColor(TempColor);
- if (FRuntimeMeshVertexTraits<VertexType>::HasHighPrecisionUVs)
- {
- FVector2D TempUV;
- Ar << TempUV;
- VerticesBuilder.SetUV(0, TempUV);
- if (FRuntimeMeshVertexTraits<VertexType>::NumUVChannels > 1)
- {
- Ar << TempUV;
- VerticesBuilder.SetUV(1, TempUV);
- }
- }
- else
- {
- FVector2DHalf TempUV;
- Ar << TempUV;
- VerticesBuilder.SetUV(0, TempUV);
- if (FRuntimeMeshVertexTraits<VertexType>::NumUVChannels > 1)
- {
- Ar << TempUV;
- VerticesBuilder.SetUV(1, TempUV);
- }
- }
- }
- }
- else
- {
- check(false && "Cannot use legacy save.");
- }
- }
- public:
- virtual void Serialize(FArchive& Ar) override
- {
- if (Ar.CustomVer(FRuntimeMeshVersion::GUID) >= FRuntimeMeshVersion::SerializationV2)
- {
- Ar << VertexBuffer;
- FRuntimeMeshSectionInterface::Serialize(Ar);
- }
- else
- {
- FRuntimeMeshSectionInterface::Serialize(Ar);
- SerializeLegacy(Ar);
- }
- }
- friend class URuntimeMeshComponent;
- };
- /** Smart pointer to a Runtime Mesh Section */
- using RuntimeMeshSectionPtr = TSharedPtr<FRuntimeMeshSectionInterface>;
|