由于UE5中的Actor类需要继承自AActor类,因此我们需要包含"AActor.h"头文件,并继承自AActor类。此外,我们还需要包含"ProceduralMeshComponent.h"头文件,以便使用ProceduralMeshComponent来生成地形。

以下是一个简单的示例代码:

// MyActor.h

#include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "ProceduralMeshComponent.h" #include "MyActor.generated.h"

UCLASS() class MYPROJECT_API AMyActor : public AActor { GENERATED_BODY()

public: AMyActor();

protected: virtual void BeginPlay() override;

private: UPROPERTY(EditAnywhere) float TerrainSize = 1000.f;

UPROPERTY(EditAnywhere)
int32 TerrainResolution = 100;

UPROPERTY(EditAnywhere)
float TerrainHeight = 100.f;

UPROPERTY(EditAnywhere)
float TerrainNoiseScale = 100.f;

UPROPERTY(EditAnywhere)
float TerrainNoiseHeight = 50.f;

UPROPERTY(EditAnywhere)
int32 TerrainSeed = 0;

UPROPERTY(EditAnywhere)
bool bSmoothTerrain = true;

UPROPERTY(EditAnywhere)
bool bGenerateNormals = true;

UPROPERTY(EditAnywhere)
bool bGenerateTangents = true;

UPROPERTY(EditAnywhere)
bool bGenerateUVs = true;

UPROPERTY(VisibleAnywhere)
UProceduralMeshComponent* ProceduralMeshComponent;

TArray<FVector> Vertices;
TArray<int32> Triangles;
TArray<FVector> Normals;
TArray<FVector2D> UVs;

void GenerateTerrain();

};

// MyActor.cpp

#include "MyActor.h"

AMyActor::AMyActor() { PrimaryActorTick.bCanEverTick = false;

ProceduralMeshComponent = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("ProceduralMeshComponent"));
SetRootComponent(ProceduralMeshComponent);

}

void AMyActor::BeginPlay() { Super::BeginPlay();

GenerateTerrain();

}

void AMyActor::GenerateTerrain() { // Generate vertices for (int32 y = 0; y < TerrainResolution; ++y) { for (int32 x = 0; x < TerrainResolution; ++x) { float u = static_cast(x) / (TerrainResolution - 1); float v = static_cast(y) / (TerrainResolution - 1);

        float noise = FMath::PerlinNoise2D(FVector2D(x, y) / TerrainNoiseScale + TerrainSeed);
        float height = (noise * TerrainNoiseHeight) + TerrainHeight;

        FVector vertex = FVector(u * TerrainSize - TerrainSize / 2.f, v * TerrainSize - TerrainSize / 2.f, height);
        Vertices.Add(vertex);
    }
}

// Generate triangles
for (int32 y = 0; y < TerrainResolution - 1; ++y)
{
    for (int32 x = 0; x < TerrainResolution - 1; ++x)
    {
        int32 i0 = x + y * TerrainResolution;
        int32 i1 = x + (y + 1) * TerrainResolution;
        int32 i2 = (x + 1) + y * TerrainResolution;
        int32 i3 = (x + 1) + (y + 1) * TerrainResolution;

        Triangles.Add(i0);
        Triangles.Add(i1);
        Triangles.Add(i2);

        Triangles.Add(i1);
        Triangles.Add(i3);
        Triangles.Add(i2);
    }
}

// Generate normals
if (bGenerateNormals)
{
    for (int32 i = 0; i < Vertices.Num(); ++i)
    {
        Normals.Add(FVector::ZeroVector);
    }

    for (int32 i = 0; i < Triangles.Num(); i += 3)
    {
        int32 i0 = Triangles[i];
        int32 i1 = Triangles[i + 1];
        int32 i2 = Triangles[i + 2];

        FVector v0 = Vertices[i0];
        FVector v1 = Vertices[i1];
        FVector v2 = Vertices[i2];

        FVector normal = FVector::CrossProduct(v1 - v0, v2 - v0).GetSafeNormal();

        Normals[i0] += normal;
        Normals[i1] += normal;
        Normals[i2] += normal;
    }

    for (int32 i = 0; i < Normals.Num(); ++i)
    {
        Normals[i].Normalize();
    }
}

// Generate tangents
if (bGenerateTangents)
{
    TArray<FVector> Tangents;
    TArray<FProcMeshTangent> ProcTangents;

    for (int32 i = 0; i < Vertices.Num(); ++i)
    {
        Tangents.Add(FVector::ZeroVector);
    }

    for (int32 i = 0; i < Triangles.Num(); i += 3)
    {
        int32 i0 = Triangles[i];
        int32 i1 = Triangles[i + 1];
        int32 i2 = Triangles[i + 2];

        FVector v0 = Vertices[i0];
        FVector v1 = Vertices[i1];
        FVector v2 = Vertices[i2];

        FVector2D uv0 = UVs[i0];
        FVector2D uv1 = UVs[i1];
        FVector2D uv2 = UVs[i2];

        FVector deltaPos1 = v1 - v0;
        FVector deltaPos2 = v2 - v0;

        FVector2D deltaUV1 = uv1 - uv0;
        FVector2D deltaUV2 = uv2 - uv0;

        float r = 1.f / (deltaUV1.X * deltaUV2.Y - deltaUV1.Y * deltaUV2.X);

        FVector tangent = (deltaPos1 * deltaUV2.Y - deltaPos2 * deltaUV1.Y) * r;

        Tangents[i0] += tangent;
        Tangents[i1] += tangent;
        Tangents[i2] += tangent;
    }

    for (int32 i = 0; i < Tangents.Num(); ++i)
    {
        Tangents[i].Normalize();
        ProcTangents.Add(FProcMeshTangent(Tangents[i], false));
    }

    ProceduralMeshComponent->SetTangents(ProcTangents);
}

// Generate UVs
if (bGenerateUVs)
{
    for (int32 y = 0; y < TerrainResolution; ++y)
    {
        for (int32 x = 0; x < TerrainResolution; ++x)
        {
            float u = static_cast<float>(x) / (TerrainResolution - 1);
            float v = static_cast<float>(y) / (TerrainResolution - 1);

            UVs.Add(FVector2D(u, v));
        }
    }
}

// Smooth terrain
if (bSmoothTerrain)
{
    TArray<FVector> SmoothedVertices;

    for (int32 y = 0; y < TerrainResolution; ++y)
    {
        for (int32 x = 0; x < TerrainResolution; ++x)
        {
            int32 i = x + y * TerrainResolution;

            FVector vertex = Vertices[i];
            FVector normal = Normals[i];

            FVector smoothedVertex = vertex;

            TArray<int32> NeighborIndices;

            if (x > 0)
            {
                NeighborIndices.Add(i - 1);
            }

            if (x < TerrainResolution - 1)
            {
                NeighborIndices.Add(i + 1);
            }

            if (y > 0)
            {
                NeighborIndices.Add(i - TerrainResolution);
            }

            if (y < TerrainResolution - 1)
            {
                NeighborIndices.Add(i + TerrainResolution);
            }

            for (int32 j = 0; j < NeighborIndices.Num(); ++j)
            {
                int32 neighborIndex = NeighborIndices[j];

                FVector neighborVertex = Vertices[neighborIndex];
                FVector neighborNormal = Normals[neighborIndex];

                float dot = FVector::DotProduct(normal, neighborNormal);

                if (dot > 0.5f)
                {
                    smoothedVertex += neighborVertex;
                }
            }

            smoothedVertex /= (NeighborIndices.Num() + 1);

            SmoothedVertices.Add(smoothedVertex);
        }
    }

    Vertices = SmoothedVertices;
}

// Update procedural mesh component
ProceduralMeshComponent->CreateMeshSection_LinearColor(0, Vertices, Triangles, Normals, UVs, TArray<FLinearColor>(), TArray<FProcMeshTangent>(), bGenerateNormals, bGenerateTangents, EProcMeshUpdateFlags::None);

}

使用过程:

1.在UE5中创建一个新的C++类,并将其继承自AMyActor。

2.在C++类中添加GenerateTerrain()函数,该函数用于生成随机地形。

3.在C++类的构造函数中创建一个ProceduralMeshComponent,并将其设置为根组件。

4.在GenerateTerrain()函数中,根据输入的尺寸和参数生成随机地形。可以根据需要调整参数以获得所需的地形。

5.在BeginPlay()函数中调用GenerateTerrain()函数以生成地形。

6.在UE5中将该Actor添加到场景中,即可看到生成的随机地形。


原文地址: https://www.cveoy.top/t/topic/bRJB 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录