Download

Getting Access Violation most of the time when using Async Task, Dynamic Delegate and Proc Mesh

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);
    }
};

MeshCalc.cpp


#include "MeshCalc.h"


void AMeshCalc::OnConstruction(const FTransform& Transform)
{
    TArray<FVector> orientations = { GetActorUpVector(), GetActorUpVector() * -1, GetActorRightVector(), GetActorRightVector() * -1, GetActorForwardVector(), GetActorForwardVector() * -1 };
    FCalcDelegate.BindUFunction(this, FName("CreateSection"));
    (new FAutoDeleteAsyncTask<FAsyncMeshCalc>(0, resolution, orientations[0], FCalcDelegate))->StartBackgroundTask(); //index 0 = mesh section index

}


void AMeshCalc::CreateSection(int32 index, TArray<FVector> vertices, TArray<int32> triangles, TArray<FVector2D> uv, TArray<FLinearColor> vertexcolors, TArray<FProcMeshTangent> tangents, TArray<FVector> normals)
{
    mesh->CreateMeshSection_LinearColor(index, vertices, triangles, normals, uv, vertexcolors, tangents, true);
}

Since it does work sometimes, I thought I might be on the right path, but now I don’t know what to do next. Has anybody any ideas?