Procedural mesh doesn't render

Hi, I am trying to convert one of my blueprints to cpp. I created this blueprint by following this tutorial Unreal Engine 4 - Optimized Grid Tutorial (1/4) - YouTube (BP_GRID).

Grid.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "ProceduralMeshComponent.h"

#include "GameFramework/Actor.h"
#include "Grid.generated.h"

#define TILE_VALID(Row, Column) ((Row >= 0) && (Row < NumRows) && (Column >= 0) && (Column < NumColumns))

UCLASS()
class FORTRESS_API AGrid : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AGrid();
	// Called every frame
	virtual void Tick(float DeltaTime) override;
	
	virtual void PostActorCreated() override;
	
	UFUNCTION(BlueprintCallable)
	bool LocationToTile(FVector Location, int32& Row, int32& Column) const;
	
	UFUNCTION(BlueprintCallable)
	bool TileToGridLocation(int32 Row, int32 Column, bool IsCentred, FVector2D& GridLocation) const;

	UFUNCTION(BlueprintCallable)
    void SetSelectedTile(int32 Row, int32 Column) const;

	UPROPERTY(EditAnywhere)
	int32 NumRows;
	
	UPROPERTY(EditAnywhere)
	int32 NumColumns;
	
	UPROPERTY(EditAnywhere)
	float TileSize;
	
	UPROPERTY(EditAnywhere)
	float LineThickness;
	
	UPROPERTY(EditAnywhere)
	FLinearColor LineColor;
	
	UPROPERTY(EditAnywhere)
	FLinearColor SelectionColor;
	
	UPROPERTY(EditAnywhere)
	float LineOpacity;
	
	UPROPERTY(EditAnywhere)
	float SelectionOpacity;

	UPROPERTY(EditAnywhere)
	UMaterialInterface* GridMaterial;

	UPROPERTY(BlueprintReadOnly)
	UProceduralMeshComponent* SelectionProceduralMesh;
	
	UPROPERTY(BlueprintReadOnly)
	UProceduralMeshComponent* LineProceduralMesh;

	UPROPERTY(BlueprintReadOnly)
	UMaterialInstance* LineMaterial;
	
	UPROPERTY(BlueprintReadOnly)
	UMaterialInstance* SelectionMaterial;

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
private:
	float GridWidth() const;
	float GridHeight() const;
	static void CreateLine(FVector Start, FVector End, float Thickness, TArray<FVector> Vertices, TArray<int32> Triangles);
	UMaterialInstanceDynamic* CreateMaterialInstance(FLinearColor Color, float Opacity, FName Name);
};

Grid.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include "Fortress/Public/Grid.h"

#include "Math/UnrealPlatformMathSSE.h"

// Sets default values
AGrid::AGrid()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
	
	LineProceduralMesh = CreateDefaultSubobject<UProceduralMeshComponent>("LineProceduralMesh");
	SelectionProceduralMesh = CreateDefaultSubobject<UProceduralMeshComponent>("SelectionProceduralMesh");

	TArray<FVector> LineVertices;
	TArray<int32> LineTriangles;
	
	for (int32 i = 0; i <= NumRows; i++) // maybe i <= NumRows
	{
		const float LineStart = i * TileSize;
		const float LineEnd = GridWidth();
		CreateLine(FVector(LineStart, 0.f, 0.f), FVector(LineStart, LineEnd, 0.f), LineThickness, LineVertices, LineTriangles);
	}	
	
	for (int32 i = 0; i <= NumColumns; i++) // maybe i <= NumRows
	{
		const float LineStart = i * TileSize;
		const float LineEnd = GridHeight();
		CreateLine(FVector(0.f, LineStart, 0.f), FVector(LineEnd, LineStart, 0.f), LineThickness, LineVertices, LineTriangles);
	}

	TArray<FVector> normals;
	normals.Add(FVector(1, 0, 0));
	normals.Add(FVector(1, 0, 0));
	normals.Add(FVector(1, 0, 0));

	TArray<FVector2D> UV0;
	UV0.Add(FVector2D(0, 0));
	UV0.Add(FVector2D(10, 0));
	UV0.Add(FVector2D(0, 10));
	

	TArray<FProcMeshTangent> Tangents;
	Tangents.Add(FProcMeshTangent(0, 1, 0));
	Tangents.Add(FProcMeshTangent(0, 1, 0));
	Tangents.Add(FProcMeshTangent(0, 1, 0));

	TArray<FLinearColor> VertexColors;
	VertexColors.Add(FLinearColor(0.75, 0.75, 0.75, 1.0));
	VertexColors.Add(FLinearColor(0.75, 0.75, 0.75, 1.0));
	VertexColors.Add(FLinearColor(0.75, 0.75, 0.75, 1.0));
	
	LineProceduralMesh->CreateMeshSection_LinearColor(0, LineVertices, LineTriangles, normals, UV0, VertexColors, Tangents, false);
	LineProceduralMesh->SetMaterial(0, LineMaterial);

	TArray<FVector> SelectionVertices;
	TArray<int32> SelectionTriangles;
	CreateLine(FVector(0.f, TileSize / 2.f, 0.f), FVector(TileSize, TileSize / 2.f, 0.f), TileSize, SelectionVertices, SelectionTriangles);
	SelectionProceduralMesh->SetVisibility(false);
	SelectionProceduralMesh->CreateMeshSection_LinearColor(0, SelectionVertices, SelectionTriangles, normals, UV0, VertexColors, Tangents, false);
	SelectionProceduralMesh->SetMaterial(0, SelectionMaterial);
}

void AGrid::PostActorCreated()
{
	LineMaterial = CreateMaterialInstance(LineColor, LineOpacity, FName(TEXT("Line Material Instance")));
	SelectionMaterial = CreateMaterialInstance(SelectionColor, SelectionOpacity, FName(TEXT("Selection Material Instance")));
}

// Called when the game starts or when spawned
void AGrid::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AGrid::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

bool AGrid::LocationToTile(const FVector Location, int32& Row, int32& Column) const
{
	const FVector ActorLocation = GetActorLocation();
	Row = UE4::SSE::FloorToInt(NumRows * ((Location.X - ActorLocation.X) / GridWidth()));
	Column = UE4::SSE::FloorToInt(NumColumns * ((Location.Y - ActorLocation.Y) / GridHeight()));
	return TILE_VALID(Row, Column);
}

bool AGrid::TileToGridLocation(const int32 Row, const int32 Column, const bool IsCentred, FVector2D& GridLocation) const
{
	const FVector Location = GetActorLocation();
	if (IsCentred)
	{
		GridLocation.X = TileSize / 2.f + Location.X + Row * TileSize;
		GridLocation.Y = TileSize / 2.f + Location.Y + Column * TileSize;
	} else
	{
		GridLocation.X = Location.X + Row * TileSize;
		GridLocation.Y = Location.Y + Column * TileSize;
	}
	return TILE_VALID(Row, Column);
}

void AGrid::SetSelectedTile(const int32 Row, const int32 Column) const
{
	FVector2D GridLocation;
	if (TileToGridLocation(Row, Column, false, GridLocation))
	{
		SelectionProceduralMesh->SetVisibility(true);
		SelectionProceduralMesh->SetWorldLocation(FVector(GridLocation.X, GridLocation.Y, GetActorLocation().Z));
	} else
	{
		SelectionProceduralMesh->SetVisibility(false);
	}
}

float AGrid::GridWidth() const
{
	return NumColumns * TileSize;
}

float AGrid::GridHeight() const
{
	return NumRows * TileSize;
}

void AGrid::CreateLine(const FVector Start, const FVector End, const float Thickness, TArray<FVector> Vertices, TArray<int32> Triangles)
{
	const float HalfThickness = Thickness / 2.f;
	
	FVector Diff = Start - End;
	Diff.Normalize(.0001f); // may be wrong

	const FVector ThicknessDirection = FVector::CrossProduct(Diff, FVector(0.0f, 0.0f, 1.0f));

	const TArray<int32> TrianglesArray = {
		Vertices.Num() + 2,
		Vertices.Num() + 1,
		Vertices.Num() + 0,
		Vertices.Num() + 2,
		Vertices.Num() + 3,
		Vertices.Num() + 1,
	};
	Triangles.Append(TrianglesArray);

	const TArray<FVector> VerticesArray = {
		Start + ThicknessDirection * HalfThickness,
		End + ThicknessDirection * HalfThickness,
		Start - ThicknessDirection * HalfThickness,
		End - ThicknessDirection * HalfThickness,		
	};
	Vertices.Append(VerticesArray);
}

UMaterialInstanceDynamic* AGrid::CreateMaterialInstance(const FLinearColor Color, const float Opacity, FName Name)
{
	UMaterialInstanceDynamic* DynamicMaterial = UMaterialInstanceDynamic::Create(GridMaterial, this, Name);
	DynamicMaterial->SetVectorParameterValue("Color", Color);
    DynamicMaterial->SetScalarParameterValue("Opacity", Opacity);
	return DynamicMaterial;
}

Currently I can add the Grid actor to the scene but none of the procedural meshes show up in the viewport or when I run it.

1 Like

I found a solution. Probably this issue is caused by some unreal internal serialization of the properties that are part of the reflection system. I bet that is related with the Live Coding too. So, the solution is easy, just rename your properties variables and component names, this way you’ll reset any information stored by unreal about that component.

I’m experiencing the same here. When you create two components of the type UProceduralMeshComponent the first one is hidden and only the second is shown.

I’m investigating that, if I found some solution I will ping you @anonymous_user_d44a8e8a

If you want to render the components in editor, override function OnConstruction() inherit from AActor and place your render code there.

Check following reference:

Also check remarks of AActor about how Actor init inside unreal: