Hi, I want to do the calculations for my procedural mesh generation in the background using async task. A dynamic delegate passes the results to the method that creates the mesh section. I used to have 6 mesh sections, but for experimenting I stayed at 1. Sometimes it works and the calculated mesh looks fine, but most of the time the editor crashes when I type in a different resolution value, no matter if it is higher or lower. And then the editor wants me to report this to epic:
I use UE4.25 source from github to learn. When I follow the breakpoints while debugging, I just can’t recognize any null pointer violation or something like that, but maybe I didn’t look close enough? I was reading a lot of tutorials about mesh generation and async tasks and thus I have achieved this code:
MeshCalc.h
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ProceduralMeshComponent.h"
#include "Kismetproceduralmeshlibrary.h"
#include "MeshCalc.generated.h"
DECLARE_DYNAMIC_DELEGATE_SevenParams(FCreateMeshSection, int32, index, TArray<FVector>, vertices, TArray<int32>, triangles, TArray<FVector2D>, uv, TArray<FLinearColor>, vertexcolors, TArray<FProcMeshTangent>, tangents, TArray<FVector>, normals);
UCLASS()
class ANDROID2020_API AMeshCalc : public AActor
{
GENERATED_BODY()
private:
public:
UFUNCTION()
void CreateSection(int32 index, TArray<FVector> vertices, TArray<int32> triangles, TArray<FVector2D> uv, TArray<FLinearColor> vertexcolors, TArray<FProcMeshTangent> tangents, TArray<FVector> normals);
FCreateMeshSection FCalcDelegate;
//and the other casual stuff...
};
class FAsyncMeshCalc : public FNonAbandonableTask
{
friend class FAutoDeleteAsyncTask<FAsyncMeshCalc>;
int32 index;
int32 resolution;
FVector orientation;
FCreateMeshSection callback;
FCreateMeshSection FCalcDelegate;
FAsyncMeshCalc(int32 inIndex, int32 inResolution, FVector inOrientation, FCreateMeshSection inCalcDelegate) : index(inIndex), resolution(inResolution), orientation(inOrientation), FCalcDelegate(inCalcDelegate)
{
}
void DoWork() // This function runs automatically
{
TArray<FVector> Vertices;
TArray<FVector2D> UV;
TArray<FLinearColor> VertexColors;
TArray<int32> Triangles;
TArray<FVector> normals;
TArray<FProcMeshTangent> tangents;
float uvSpacing = (1.0f / FMath::Max(resolution, resolution));
FVector axisX = FVector(orientation.Y, orientation.Z, orientation.X);
FVector axisY = FVector().CrossProduct(orientation, axisX);
//vertex calculation
for (int32 y = 0; y < resolution; y++)
{
for (int32 x = 0; x < resolution; x++)
{
FVector2D percent = FVector2D(x, y) / (resolution - 1);
Vertices.Add(FVector(orientation + (percent.X - 0.5F) * 2 * axisX + (percent.Y - 0.5F) * 2 * axisY).GetUnsafeNormal());
UV.Add(FVector2D(x * uvSpacing, y * uvSpacing));
VertexColors.Add(FLinearColor(0.0f, 0.0f, 0.0f, 1.0f));
}
}
//triangle calculation
for (int32 y = 0; y < resolution - 1; y++)
{
for (int32 x = 0; x < resolution - 1; x++)
{
Triangles.Add(x + (y * resolution)); //current vertex
Triangles.Add(x + (y * resolution) + resolution); //current vertex + row
Triangles.Add(x + (y * resolution) + resolution + 1); //current vertex + row + one right
Triangles.Add(x + (y * resolution)); //current vertex
Triangles.Add(x + (y * resolution) + resolution + 1); //current vertex + row + one right
Triangles.Add(x + (y * resolution) + 1); //current vertex + one right
}
}
UKismetProceduralMeshLibrary::CalculateTangentsForMesh(Vertices, Triangles, UV, normals, tangents);
FCalcDelegate.ExecuteIfBound(index, Vertices, Triangles, UV, VertexColors, tangents, normals);
}
// This next section of code needs to be here. Not important as to why.
FORCEINLINE TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FAsyncMeshCalc, STATGROUP_ThreadPoolAsyncTasks);
}
};