Search code examples
unreal-engine4unreal-engine5

Create UStaticMesh from triangle datas


I trying to find the way for create UStaticMesh from triangle data. Here is my result so far. It make app crash with error “Array index out of bounds: 0 from an array of size 0”. Any contribution will be appreciated :D

UStaticMesh* staticMesh = NewObject<UStaticMesh>();

// Create the static mesh render data
TUniquePtr<FStaticMeshRenderData> renderData = MakeUnique<FStaticMeshRenderData>();
staticMesh->SetRenderData(MoveTemp(renderData));
FStaticMeshLODResources* lODResource = new FStaticMeshLODResources();
staticMesh->GetRenderData()->LODResources.Add(lODResource);

//For vertices
numberItem2 = data["vertices"].size() / 3;
lODResource->VertexBuffers.PositionVertexBuffer.Init(numberItem2);
lODResource->VertexBuffers.StaticMeshVertexBuffer.Init(numberItem2, 1);
lODResource->VertexBuffers.ColorVertexBuffer.Init(numberItem2);
for (size_t j = 0; j < numberItem2; j++)
{
    FVector3f vertex = FVector3f(data["vertices"][j * 3].get<float>(),
    data["vertices"][j * 3 + 1].get<float>(), data["vertices"][j * 3 + 2].get<float>());

        lODResource->VertexBuffers.PositionVertexBuffer.VertexPosition(j) = vertex;
    lODResource->VertexBuffers.StaticMeshVertexBuffer.SetVertexTangents(j, FVector3f::ZeroVector, FVector3f::ZeroVector, FVector3f::ZeroVector);
    lODResource->VertexBuffers.StaticMeshVertexBuffer.SetVertexUV(j, 0, FVector2f(vertex));
    lODResource->VertexBuffers.ColorVertexBuffer.VertexColor(j) = FColor::White;
}

//For triangle
numberItem2 = data["triangles"].size();
TArray<uint32> indexBuffer;
indexBuffer.SetNum(numberItem2);
for (size_t j = 0; j < numberItem2; j++) {
    indexBuffer[j] = data["triangles"][j].get<uint32>();
}
lODResource->IndexBuffer.SetIndices(indexBuffer, EIndexBufferStride::Type::AutoDetect);

FStaticMeshSourceModel& SourceModel = staticMesh->AddSourceModel();
/*SourceModel.BuildSettings.bRecomputeNormals = true;
SourceModel.BuildSettings.bRecomputeTangents = true;
SourceModel.BuildSettings.bRemoveDegenerates = true;*/
//SourceModel.BuildSettings.bBuildReversedIndexBuffer = true;
/*SourceModel.BuildSettings.bUseFullPrecisionUVs = true;
SourceModel.BuildSettings.bGenerateLightmapUVs = true;
SourceModel.BuildSettings.SrcLightmapIndex = 0;
SourceModel.BuildSettings.DstLightmapIndex = 0;*/

staticMesh->PostEditChange();
staticMesh->MarkPackageDirty();
staticMesh->Build(false);


Solution

  • There is a built-in Mesh Component class in Unreal called Procedural Mesh Component, which can be used for this. To use it, make sure "procedural mesh component" is enabled in the plugin list of your project.

    To make your mesh from lists of triangle data, you need to add a Procedural Mesh to an actor, and then use the CreateMeshSection function. It has a signature like so:

    void CreateMeshSection
    (
        int32 SectionIndex,
        const TArray< FVector > & Vertices,
        const TArray< int32 > & Triangles,
        const TArray< FVector > & Normals,
        const TArray< FVector2D > & UV0,
        const TArray< FVector2D > & UV1,
        const TArray< FVector2D > & UV2,
        const TArray< FVector2D > & UV3,
        const TArray< FColor > & VertexColors,
        const TArray< FProcMeshTangent > & Tangents,
        bool bCreateCollision
    )
    

    If you don't need some things, like several sets of UVs, or vertex colors, you can simply provide empty arrays to those inputs, they are optional.

    To note, the mentioned built-in component is good enough for this use case, but there is also a more flexible and optimized alternative: a third-party component plugin called RealtimeMeshComponent. It has a very similar CreateMeshSection function (see docs).