I am having a lot of trouble texturing a procedural mesh in UE4. I am using perlin noise from Accidental Noise Library with PolyVox to generate randomized marching cube terrain.

Accidental Noise Library: https://github.com/LtBrandon/accidental-noise-library PolyVox: https://bitbucket.org/volumesoffun/polyvox/src/develop/

I've tried to make a Triplanar material, and it seems to work great when I apply it to an imported mesh:

Triplanar material applied to the free 'ProceduralNaturePack' rock asset

When I apply it to my randomly generated procedural mesh however, I see the following:

UProceduralMeshComponent overlapping texture

I have a suspicion that my issue is either UV0 or Normals but I just do not understand this issue enough to effectively troubleshoot. Here is the code for the important part of generation for my mesh. I'm not including a lot for brevity sake, please let me know if you need to see includes and whatnot:


// This is very truncated for brevity sake please let me know if you'd like to see more of this file
    UPROPERTY(Category = "Voxel Terrain - Terrain Settings", BlueprintReadWrite, EditAnywhere) UMaterialInterface* Material;

    TSharedPtr<PolyVox::PagedVolume<PolyVox::MaterialDensityPair88>> VoxelVolume;


bool AProceduralTerrainActor::GenerateChunk(int32 X, int32 Y, int32 Z) {

    int32 ChunkSize = 64;
    // The offset is important if I want to create more than one chunk
    int32 OffsetX = (X * ChunkSize);
    int32 OffsetY = (Y * ChunkSize);
    int32 OffsetZ = (Z * ChunkSize);

    //PolyVox does its magic
    PolyVox::Region ToExtract(Vector3DInt32(OffsetX, OffsetY, OffsetZ), Vector3DInt32(OffsetX + ChunkSize, OffsetY + ChunkSize, OffsetZ + ChunkSize));

    auto ExtractedMesh = extractMarchingCubesMesh(VoxelVolume.Get(), ToExtract);
    auto DecodedMesh = decodeMesh(ExtractedMesh);
    if (DecodedMesh.getNoOfIndices() == 0) {
        return false;

    //Creating my mesh
    FGuid UniqueIdentifier = FGuid::NewGuid();
    FString MeshName = "VoxelMesh_" + UniqueIdentifier.ToString();
    UProceduralMeshComponent* Mesh = NewObject<UProceduralMeshComponent>(this, FName(*FString::Printf(TEXT("VoxelMesh_%s"), *MeshName)));

    Mesh->AttachToComponent(GetRootComponent(), FAttachmentTransformRules(EAttachmentRule::KeepRelative, false));
    Mesh->SetMaterial(0, Material);

    auto Vertices = TArray<FVector>();
    auto Indices = TArray<int32>();
    auto Normals = TArray<FVector>();
    auto UV0 = TArray<FVector2D>(); // I know for sure I'm calculating these incorrectly
    auto Colors = TArray<FColor>(); // I'm not calculating these yet as I don't know how
    auto Tangents = TArray<FProcMeshTangent>();

    FVector OffsetLocation(OffsetX, OffsetY, OffsetZ);

    // Loop over all of the triangle vertex indices
    for (uint32 i = 0; i < DecodedMesh.getNoOfIndices() - 2; i += 3)
        // We need to add the vertices of each triangle in reverse or the mesh will be upside down
        auto Index = DecodedMesh.getIndex(i + 2);
        auto Vertex2 = DecodedMesh.getVertex(Index);
        auto TriangleMaterial = Vertex2.data.getMaterial();

        Indices.Add(Vertices.Add((FPolyVoxVector(Vertex2.position) + OffsetLocation) * 100.f));

        Index = DecodedMesh.getIndex(i + 1);
        auto Vertex1 = DecodedMesh.getVertex(Index);
        Indices.Add(Vertices.Add((FPolyVoxVector(Vertex1.position) + OffsetLocation) * 100.f));

        Index = DecodedMesh.getIndex(i);
        auto Vertex0 = DecodedMesh.getVertex(Index);
        Indices.Add(Vertices.Add((FPolyVoxVector(Vertex0.position) + OffsetLocation) * 100.f));

        // Calculate the tangents of our triangle
        const FVector Edge01 = FPolyVoxVector(Vertex1.position - Vertex0.position);
        const FVector Edge02 = FPolyVoxVector(Vertex2.position - Vertex0.position);

         * Here is my attempt at creating UVs.. big yikes.
        // Triangle vertices and center point
        FVector A = (FPolyVoxVector(Vertex0.position) + OffsetLocation) * 100.f; //A
        FVector B = (FPolyVoxVector(Vertex1.position) + OffsetLocation) * 100.f; //B
        FVector C = (FPolyVoxVector(Vertex2.position) + OffsetLocation) * 100.f; //C
        FVector P = FVector((A.X + B.X + C.X) / 3, (A.Y + B.Y + C.Y) / 3, 0);

        // Mesh box extend
        auto b = Mesh->Bounds.BoxExtent;// (transform);

        // Vertex UVs (?)
        auto UVA = FVector2D(A.X / b.X, A.Z / b.Z);
        auto UVB = FVector2D(B.X / b.X, B.Z / b.Z);
        auto UVC = FVector2D(C.X / b.X, C.Z / b.Z);



        const FVector TangentX = Edge01.GetUnsafeNormal();
        FVector TangentZ = (Edge01 ^ Edge02).GetUnsafeNormal();

        for (int32 j = 0; j < 3; j++)
            Tangents.Add(FProcMeshTangent(TangentX, false));

    // Finally create the mesh
    Mesh->CreateMeshSection(0, Vertices, Indices, Normals, UV0, Colors, Tangents, true);

    return true;

Thank you for reading my very lengthy post, please let me know if I'm not providing details you need!


I should probably include the tri-planar material I'm using:

Triplanar material

  • \$\begingroup\$ It looks flat - try to add some to world offset and or normal. You material works by world normal - but the mesh seems to be flat and also no normal map is plugged. \$\endgroup\$ – ColdSteel Nov 15 '19 at 14:26
  • \$\begingroup\$ @ColdSteel Perhaps I could have used a better screenshot - it looks like that even on slopes. In the code I am adding normals (Though probably not correctly) Normals.Add(TangentX); Are you saying I need normals for the textures in the material as well? \$\endgroup\$ – Skettenring Nov 15 '19 at 15:11
  • \$\begingroup\$ I don't know, if you will add a normal texture it will just add a little bit more details - but I doubt it will be noticeable IMO. iw ould plug something just for the experiment - sometimes it helps tbh. \$\endgroup\$ – ColdSteel Nov 15 '19 at 15:19
  • \$\begingroup\$ @ColdSteel Ok i'll try that out! Thanks! \$\endgroup\$ – Skettenring Nov 15 '19 at 16:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.