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.