用C++写一个在UE5中使用的actor类功能是根据输入的尺寸生成随机地形。请提供完整的代码文件包括cpp和头文件并说明详细的使用过程
由于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
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 著作权归作者所有。请勿转载和采集!