Using Slate to draw a Grid Pattern to Screen - Any tips for faster line rendering?

I’ve been playing with a procedural mesh based approach. Currently I’m still drawing in world space but on a custom depth pass with the material posted by me above here in this thread.

Performance is pretty good (consider I tested this at home on a MacBook Pro with a 750M), difference between grid turned off and a 50x50 grid is 0.81ms and a 100x100 grid is 1.26ms.

Now this is on world-coords. It would be nice to have the matrix to apply to send it to screen space, I’ll work on this later. Or does any of the Epic devs have a method for that?


GridProceduralMeshComponent.h



#pragma once

#include "ProceduralMeshComponent.h"
#include "GridProceduralMeshComponent.generated.h"

/**
 * 
 */
UCLASS()
class CTANDROID_API UGridProceduralMeshComponent : public UProceduralMeshComponent
{
	GENERATED_BODY()
	
public:

	void UGridProceduralMeshComponent::CreateProcGrid(int numRows, int numColumns, float stepDist, float thickness);
	void UpdatePoints(float time);

	FVector2D GetNormalOf2DSegment(FVector2D startPoint, FVector2D endPoint);

protected:
	TArray<FVector>		Vertices;
	TArray<int>			Triangles;
	TArray<FVector>		Normals;
	TArray<FVector2D>		UVs;

	float					m_thickness;
	int					m_numColumns;
	int					m_numRows;
	float					m_stepDist;
};



GridProceduralMeshComponent.cpp



#include "GridProceduralMeshComponent.h"



void UGridProceduralMeshComponent::CreateProcGrid(int numRows, int numColumns, float stepDist, float thickness) {

	m_thickness = thickness;
	m_numColumns = numColumns;
	m_numRows = numRows;
	m_stepDist = stepDist;

	for (size_t c = 1; c < numColumns; c++)
	{
		for (size_t r = 1; r < numRows; r++)
		{
			FVector startPoint = FVector(c - 1, (r - 1) * stepDist, 0);
			FVector endPoint = FVector(c - 1, r * stepDist, 0);

			FVector normal = FVector(GetNormalOf2DSegment(FVector2D(startPoint.X, startPoint.Y), FVector2D(endPoint.X, endPoint.Y)).X,
									GetNormalOf2DSegment(FVector2D(startPoint.X, startPoint.Y), FVector2D(endPoint.X, endPoint.Y)).Y,
									0);

			float halfThick = thickness / 2;

			int idx = Vertices.Num() - 1;

			Vertices.Add(startPoint - (halfThick * normal));
			Vertices.Add(endPoint - (halfThick * normal));
			Vertices.Add(endPoint + (halfThick * normal));
			Vertices.Add(startPoint + (halfThick * normal));

			Triangles.Add(1 + idx);
			Triangles.Add(2 + idx);
			Triangles.Add(4 + idx);

			Triangles.Add(2 + idx);
			Triangles.Add(3 + idx);
			Triangles.Add(4 + idx);

			Normals.Add(FVector(0, 0, 1));
			Normals.Add(FVector(0, 0, 1));
			Normals.Add(FVector(0, 0, 1));
			Normals.Add(FVector(0, 0, 1));

			UVs.Add(FVector2D(0, 0));
			UVs.Add(FVector2D(0, 1));
			UVs.Add(FVector2D(1, 1));
			UVs.Add(FVector2D(1, 0));

		}
	}

	for (size_t r = 1; r < numRows; r++)
	{
		for (size_t c = 1; c < numColumns; c++)
		{
			FVector startPoint = FVector((c - 1) * stepDist, r - 1, 0);
			FVector endPoint = FVector(c * stepDist, r - 1 , 0);

			FVector normal = FVector(GetNormalOf2DSegment(FVector2D(startPoint.X, startPoint.Y), FVector2D(endPoint.X, endPoint.Y)).X,
				GetNormalOf2DSegment(FVector2D(startPoint.X, startPoint.Y), FVector2D(endPoint.X, endPoint.Y)).Y,
				0);

			float halfThick = thickness / 2;

			int idx = Vertices.Num();

			Vertices.Add(startPoint - (halfThick * normal));
			Vertices.Add(endPoint - (halfThick * normal));
			Vertices.Add(endPoint + (halfThick * normal));
			Vertices.Add(startPoint + (halfThick * normal));

			Triangles.Add(0 + idx);
			Triangles.Add(1 + idx);
			Triangles.Add(3 + idx);

			Triangles.Add(1 + idx);
			Triangles.Add(2 + idx);
			Triangles.Add(3 + idx);

			Normals.Add(FVector(0, 0, 1));
			Normals.Add(FVector(0, 0, 1));
			Normals.Add(FVector(0, 0, 1));
			Normals.Add(FVector(0, 0, 1));

			UVs.Add(FVector2D(0, 0));
			UVs.Add(FVector2D(0, 1));
			UVs.Add(FVector2D(1, 1));
			UVs.Add(FVector2D(1, 0));

		}
	}



	CreateMeshSection(0, Vertices, Triangles, Normals, UVs, TArray<FColor>(), TArray<FProcMeshTangent>(), false);

}


void UGridProceduralMeshComponent::UpdatePoints(float time) {

	Vertices.Reset();

	float baseZ = 300;

	for (size_t c = 1; c < m_numColumns; c++)
	{
		for (size_t r = 1; r < m_numRows; r++)
		{
			FVector startPoint = FVector((c - 1)* m_stepDist, (r - 1) * m_stepDist, 10 * cos(time + r-1) + baseZ);
			FVector endPoint = FVector((c - 1)* m_stepDist, r * m_stepDist, 10 * cos(time + r) + baseZ);

			FVector normal = FVector(GetNormalOf2DSegment(FVector2D(startPoint.X, startPoint.Y), FVector2D(endPoint.X, endPoint.Y)).X,
									GetNormalOf2DSegment(FVector2D(startPoint.X, startPoint.Y), FVector2D(endPoint.X, endPoint.Y)).Y,
									0);

			float halfThick = m_thickness / 2;

			int idx = Vertices.Num() - 1;

			Vertices.Add(startPoint - (halfThick * normal));
			Vertices.Add(endPoint - (halfThick * normal));
			Vertices.Add(endPoint + (halfThick * normal));
			Vertices.Add(startPoint + (halfThick * normal));

		}
	}

	for (size_t r = 1; r < m_numRows; r++)
	{
		for (size_t c = 1; c < m_numColumns; c++)
		{
			FVector startPoint = FVector((c - 1) * m_stepDist, (r - 1)* m_stepDist, 10 * cos(time + r-1) + baseZ);
			FVector endPoint = FVector(c * m_stepDist, (r - 1)* m_stepDist, 10 * cos(time + r-1) + baseZ);

			FVector normal = FVector(GetNormalOf2DSegment(FVector2D(startPoint.X, startPoint.Y), FVector2D(endPoint.X, endPoint.Y)).X,
									GetNormalOf2DSegment(FVector2D(startPoint.X, startPoint.Y), FVector2D(endPoint.X, endPoint.Y)).Y,
									0);

			float halfThick = m_thickness / 2;

			Vertices.Add(startPoint - (halfThick * normal));
			Vertices.Add(endPoint - (halfThick * normal));
			Vertices.Add(endPoint + (halfThick * normal));
			Vertices.Add(startPoint + (halfThick * normal));


		}
	}

	UpdateMeshSection(0, Vertices, Normals, UVs, TArray<FColor>(), TArray<FProcMeshTangent>());

}


FVector2D UGridProceduralMeshComponent::GetNormalOf2DSegment(FVector2D startPoint, FVector2D endPoint) {
	FVector2D norm = FVector2D(endPoint.Y - startPoint.Y, -(endPoint.X - startPoint.X));
	return norm.GetSafeNormal();

}


(the video here looks slow, the problem is of the screen capture software I’m using, it’s causing all that spikes on the CPU thread)