操作过程:

  1. 创建一个新的Actor,命名为TerrainActor,打开它的蓝图或者C++代码。

  2. 定义一个高度图的变量,可以使用UE5自带的Landscape组件来生成高度图,也可以手动导入高度图文件。

  3. 在蓝图或者C++代码中,创建一个网格组件,用于生成地形模型。

  4. 在蓝图或者C++代码中,根据高度图生成地形模型,可以使用UE5自带的Landscape组件,也可以使用第三方库或自己编写的算法。

  5. 添加碰撞体,可以使用UE5自带的碰撞组件或者手动创建碰撞体。

  6. 添加材质,可以使用UE5自带的材质库或者创建自己的材质。

  7. 编译并运行Actor,查看生成的地形模型是否符合预期。

如果使用C++,以下是完整的cpp文件和头文件代码:

TerrainActor.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "TerrainActor.generated.h"

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

public:
    // Sets default values for this actor's properties
    ATerrainActor();

    // Called every frame
    virtual void Tick(float DeltaTime) override;

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

private:
    UPROPERTY(EditAnywhere)
    UTexture2D* HeightMap;

    UPROPERTY(EditAnywhere)
    UStaticMeshComponent* MeshComponent;

    UPROPERTY(EditAnywhere)
    UMaterialInterface* Material;

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

    void GenerateTerrain();
    float GetHeightFromTexture(FColor Color);

public:
    UFUNCTION(BlueprintCallable)
    void SetHeightMap(UTexture2D* InHeightMap);

    UFUNCTION(BlueprintCallable)
    void SetMaterial(UMaterialInterface* InMaterial);
};

TerrainActor.cpp

#include "TerrainActor.h"
#include "Components/StaticMeshComponent.h"
#include "Materials/MaterialInterface.h"
#include "Materials/MaterialInstanceDynamic.h"

// Sets default values
ATerrainActor::ATerrainActor()
{
    PrimaryActorTick.bCanEverTick = true;

    MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent"));
    RootComponent = MeshComponent;
}

// Called when the game starts or when spawned
void ATerrainActor::BeginPlay()
{
    Super::BeginPlay();

    GenerateTerrain();
}

// Called every frame
void ATerrainActor::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
}

void ATerrainActor::SetHeightMap(UTexture2D* InHeightMap)
{
    HeightMap = InHeightMap;
}

void ATerrainActor::SetMaterial(UMaterialInterface* InMaterial)
{
    Material = InMaterial;
}

void ATerrainActor::GenerateTerrain()
{
    if (!HeightMap)
    {
        return;
    }

    // Get the height map data
    TArray<FColor> HeightMapData;
    HeightMap->GetImageData(HeightMapData);

    // Set up the mesh data
    const int32 Width = HeightMap->GetSizeX();
    const int32 Height = HeightMap->GetSizeY();
    const float Scale = 10.0f;
    const int32 NumVertices = Width * Height;
    const int32 NumTriangles = (Width - 1) * (Height - 1) * 2 * 3;

    Vertices.SetNum(NumVertices);
    Triangles.SetNum(NumTriangles);
    Normals.SetNum(NumVertices);
    UVs.SetNum(NumVertices);

    // Generate the vertices
    for (int32 Y = 0; Y < Height; Y++)
    {
        for (int32 X = 0; X < Width; X++)
        {
            const int32 VertexIndex = Y * Width + X;
            const float HeightValue = GetHeightFromTexture(HeightMapData[VertexIndex]);
            const FVector VertexLocation = FVector(X * Scale, Y * Scale, HeightValue * Scale);
            Vertices[VertexIndex] = VertexLocation;
            Normals[VertexIndex] = FVector::UpVector;
            UVs[VertexIndex] = FVector2D(X / (float)Width, Y / (float)Height);
        }
    }

    // Generate the triangles
    int32 TriangleIndex = 0;
    for (int32 Y = 0; Y < Height - 1; Y++)
    {
        for (int32 X = 0; X < Width - 1; X++)
        {
            const int32 VertexIndex = Y * Width + X;
            Triangles[TriangleIndex++] = VertexIndex;
            Triangles[TriangleIndex++] = VertexIndex + 1;
            Triangles[TriangleIndex++] = VertexIndex + Width;

            Triangles[TriangleIndex++] = VertexIndex + 1;
            Triangles[TriangleIndex++] = VertexIndex + Width + 1;
            Triangles[TriangleIndex++] = VertexIndex + Width;
        }
    }

    // Create the mesh
    UStaticMesh* StaticMesh = NewObject<UStaticMesh>(this);
    StaticMesh->InitResources();

    FStaticMeshSourceModel& NewMesh = StaticMesh->AddSourceModel();
    NewMesh.BuildSettings.bRecomputeNormals = false;
    NewMesh.BuildSettings.bRecomputeTangents = false;
    NewMesh.BuildSettings.bRemoveDegenerates = false;
    NewMesh.BuildSettings.bUseMikkTSpace = false;
    NewMesh.BuildSettings.bUseFullPrecisionUVs = false;
    NewMesh.BuildSettings.bGenerateLightmapUVs = true;
    NewMesh.BuildSettings.SrcLightmapIndex = 0;
    NewMesh.BuildSettings.DstLightmapIndex = 1;

    FStaticMeshVertexBuffer& VertexBuffer = NewMesh.VertexBuffers.StaticMeshVertexBuffer;
    VertexBuffer.Init(NumVertices, 0);

    FStaticMeshIndexBuffer32& IndexBuffer = NewMesh.IndexBuffer;
    IndexBuffer.SetIndices(Triangles, Triangles.Num());

    FStaticMeshVertexData& VertexData = NewMesh.VertexData;
    VertexData.PositionComponent = FVertexStreamComponent(&VertexBuffer, STRUCT_OFFSET(FStaticMeshVertex, Position), sizeof(FStaticMeshVertex), VET_Float3);
    VertexData.TextureCoordinateComponent[0] = FVertexStreamComponent(&VertexBuffer, STRUCT_OFFSET(FStaticMeshVertex, TextureCoordinate), sizeof(FStaticMeshVertex), VET_Float2);
    VertexData.TangentBasisComponents[0] = FVertexStreamComponent(&VertexBuffer, STRUCT_OFFSET(FStaticMeshVertex, TangentX), sizeof(FStaticMeshVertex), VET_PackedNormal);
    VertexData.ColorComponent = FVertexStreamComponent(&VertexBuffer, STRUCT_OFFSET(FStaticMeshVertex, Color), sizeof(FStaticMeshVertex), VET_Color);

    for (int32 i = 0; i < NumVertices; i++)
    {
        FStaticMeshVertex& Vertex = VertexBuffer.Vertex(i);
        Vertex.Position = Vertices[i];
        Vertex.TextureCoordinate = UVs[i];
        Vertex.TangentX = FVector::RightVector;
        Vertex.TangentZ = Normals[i];
        Vertex.Color = FColor::White;
    }

    StaticMesh->PostEditChange();

    // Set the mesh and material
    MeshComponent->SetStaticMesh(StaticMesh);
    UMaterialInstanceDynamic* DynamicMaterial = UMaterialInstanceDynamic::Create(Material, this);
    MeshComponent->SetMaterial(0, DynamicMaterial);
}

float ATerrainActor::GetHeightFromTexture(FColor Color)
{
    return (Color.R + Color.G + Color.B) / 3.0f / 255.0f;
}
使用UE5的蓝图或者C++编写一个Actor功能是根据高度图生成地形模型具有碰撞和材质。请详细描述操作过程如果使用C++请提供完整cpp文件和头文件代码

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

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