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:
When I apply it to my randomly generated procedural mesh however, I see the following:
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:
ProceduralTerrainActor.h
// This is very truncated for brevity sake please let me know if you'd like to see more of this file
public:
UPROPERTY(Category = "Voxel Terrain - Terrain Settings", BlueprintReadWrite, EditAnywhere) UMaterialInterface* Material;
private:
TSharedPtr<PolyVox::PagedVolume<PolyVox::MaterialDensityPair88>> VoxelVolume;
ProceduralTerrainActor.cpp
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->RegisterComponent();
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);
UV0.Add(UVA);
UV0.Add(UVB);
UV0.Add(UVC);
/*****************************/
const FVector TangentX = Edge01.GetUnsafeNormal();
FVector TangentZ = (Edge01 ^ Edge02).GetUnsafeNormal();
for (int32 j = 0; j < 3; j++)
{
Tangents.Add(FProcMeshTangent(TangentX, false));
Normals.Add(TangentX);
}
}
// 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!
EDIT:
I should probably include the tri-planar material I'm using:
Normals.Add(TangentX);
Are you saying I need normals for the textures in the material as well? \$\endgroup\$