【UE5 C++】“ProceduralMeshComponent”的使用记录
效果
如下所示,通过“ProceduralMeshComponent”创建了一个自定义形状的Mesh,并且该Mesh包含碰撞信息,然后2s后更新Mesh形状。
步骤
1. 在“xxx.Build.cs”中引入“ProceduralMeshComponent”模块
2. 新建一个Actor类,这里命名为“DrawMeshActor”
在“DrawMeshActor.h”中引入“ProceduralMeshComponent.h”
定义“程序化网格组件”和创建自定义Mesh的方法“GenerateMesh”。其中函数“GenerateMesh”需要传入材质、三角形网格数组“Triangles”和一个布尔值“bCreateCollision”,“bCreateCollision”表示是否要生成碰撞。
三角形网格数组“Triangles”中的元素是结构体“FTriangleData”,该结构体定义如下,主要由三个点的位置构成
3. 在“DrawMeshActor.cpp”中,先引入"Materials/MaterialInterface.h",然后在“DrawMeshActor”构造时添加“ProceduralMeshComponent”组件
最后实现函数“GenerateMesh”如下
void ADrawMeshActor::GenerateMesh(UMaterialInterface* InMaterial, const TArray<FTriangleData>& Triangles, bool bCreateCollision)
{if (!ProceduralMesh){UE_LOG(LogTemp, Error, TEXT("GenerateMeshFromTriangles: ProceduralMesh component is null."));return;}if (Triangles.Num() == 0){UE_LOG(LogTemp, Warning, TEXT("GenerateMeshFromTriangles: Input Triangles array is empty. Clearing mesh."));ProceduralMesh->ClearMeshSection(0);return;}//清除之前的网格ProceduralMesh->ClearMeshSection(0);//根据三角形数量计算顶点个数int32 NumTriangles = Triangles.Num();int32 NumVertices = NumTriangles * 3;TArray<FVector> Vertices;TArray<int32> TriangleIndices;TArray<FVector> Normals;TArray<FVector2D> UV0;TArray<FProcMeshTangent> Tangents;TArray<FLinearColor> VertexColors;//预留空间Vertices.Reserve(NumVertices);TriangleIndices.Reserve(NumVertices);Normals.Reserve(NumVertices);UV0.Reserve(NumVertices);//循环添加每一个三角形网格数据for (int32 TriIndex = 0; TriIndex < NumTriangles; ++TriIndex){const FTriangleData& CurrentTriangle = Triangles[TriIndex];int32 BaseVertexIndex = TriIndex * 3;//为三角形添加顶点Vertices.Add(CurrentTriangle.Point1);Vertices.Add(CurrentTriangle.Point2);Vertices.Add(CurrentTriangle.Point3);//添加三角形索引TriangleIndices.Add(BaseVertexIndex + 0);TriangleIndices.Add(BaseVertexIndex + 1);TriangleIndices.Add(BaseVertexIndex + 2);// 计算三角形法线FVector Normal = FVector::CrossProduct(CurrentTriangle.Point3 - CurrentTriangle.Point1, CurrentTriangle.Point2 - CurrentTriangle.Point1);Normal.Normalize();//为三角形的所有3个顶点添加相同的法线Normals.Add(Normal);Normals.Add(Normal);Normals.Add(Normal);//添加UVUV0.Add(FVector2D(0.0f, 1.0f)); // UV for Point1UV0.Add(FVector2D(1.0f, 1.0f)); // UV for Point2UV0.Add(FVector2D(0.0f, 0.0f)); // UV for Point3}//创建网格ProceduralMesh->CreateMeshSection_LinearColor(0,Vertices,TriangleIndices,Normals,UV0,VertexColors,Tangents,bCreateCollision);//设置材质if (InMaterial){ProceduralMesh->SetMaterial(0, InMaterial);}else{UE_LOG(LogTemp, Warning, TEXT("GenerateMeshFromTriangles: Input Material (InMaterial) is null. Mesh section 0 might have default material."));// if (DefaultMaterial) ProceduralMesh->SetMaterial(0, DefaultMaterial);}
}
源码:
// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ProceduralMeshComponent.h"
#include "DrawMeshActor.generated.h"USTRUCT(BlueprintType)
struct FTriangleData
{GENERATED_BODY()UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Triangle Data")FVector Point1 = FVector::ZeroVector;UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Triangle Data")FVector Point2 = FVector::ZeroVector;UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Triangle Data")FVector Point3 = FVector::ZeroVector;FTriangleData() {}FTriangleData(const FVector& InP1, const FVector& InP2, const FVector& InP3): Point1(InP1), Point2(InP2), Point3(InP3) {}
};UCLASS()
class TESTPROJECT2_API ADrawMeshActor : public AActor
{GENERATED_BODY()public: ADrawMeshActor();protected:virtual void BeginPlay() override;public: virtual void Tick(float DeltaTime) override;public:// 程序化网格组件UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")UProceduralMeshComponent* ProceduralMesh;UFUNCTION(BlueprintCallable)void GenerateMesh(UMaterialInterface* InMaterial, const TArray<FTriangleData>& Triangles, bool bCreateCollision);
};
// Fill out your copyright notice in the Description page of Project Settings.#include "DrawMeshActor.h"
#include "Materials/MaterialInterface.h"ADrawMeshActor::ADrawMeshActor()
{PrimaryActorTick.bCanEverTick = false;// 创建程序化网格组件并设为根组件ProceduralMesh = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("ProceduralMesh"));SetRootComponent(ProceduralMesh);ProceduralMesh->bUseAsyncCooking = true; // 可选:在单独线程准备物理数据}// Called when the game starts or when spawned
void ADrawMeshActor::BeginPlay()
{Super::BeginPlay();}// Called every frame
void ADrawMeshActor::Tick(float DeltaTime)
{Super::Tick(DeltaTime);}void ADrawMeshActor::GenerateMesh(UMaterialInterface* InMaterial, const TArray<FTriangleData>& Triangles, bool bCreateCollision)
{if (!ProceduralMesh){UE_LOG(LogTemp, Error, TEXT("GenerateMeshFromTriangles: ProceduralMesh component is null."));return;}if (Triangles.Num() == 0){UE_LOG(LogTemp, Warning, TEXT("GenerateMeshFromTriangles: Input Triangles array is empty. Clearing mesh."));ProceduralMesh->ClearMeshSection(0);return;}//清除之前的网格ProceduralMesh->ClearMeshSection(0);//根据三角形数量计算顶点个数int32 NumTriangles = Triangles.Num();int32 NumVertices = NumTriangles * 3;TArray<FVector> Vertices;TArray<int32> TriangleIndices;TArray<FVector> Normals;TArray<FVector2D> UV0;TArray<FProcMeshTangent> Tangents;TArray<FLinearColor> VertexColors;//预留空间Vertices.Reserve(NumVertices);TriangleIndices.Reserve(NumVertices);Normals.Reserve(NumVertices);UV0.Reserve(NumVertices);//循环添加每一个三角形网格数据for (int32 TriIndex = 0; TriIndex < NumTriangles; ++TriIndex){const FTriangleData& CurrentTriangle = Triangles[TriIndex];int32 BaseVertexIndex = TriIndex * 3;//为三角形添加顶点Vertices.Add(CurrentTriangle.Point1);Vertices.Add(CurrentTriangle.Point2);Vertices.Add(CurrentTriangle.Point3);//添加三角形索引TriangleIndices.Add(BaseVertexIndex + 0);TriangleIndices.Add(BaseVertexIndex + 1);TriangleIndices.Add(BaseVertexIndex + 2);// 计算三角形法线FVector Normal = FVector::CrossProduct(CurrentTriangle.Point3 - CurrentTriangle.Point1, CurrentTriangle.Point2 - CurrentTriangle.Point1);Normal.Normalize();//为三角形的所有3个顶点添加相同的法线Normals.Add(Normal);Normals.Add(Normal);Normals.Add(Normal);//添加UVUV0.Add(FVector2D(0.0f, 1.0f)); // UV for Point1UV0.Add(FVector2D(1.0f, 1.0f)); // UV for Point2UV0.Add(FVector2D(0.0f, 0.0f)); // UV for Point3}//创建网格ProceduralMesh->CreateMeshSection_LinearColor(0,Vertices,TriangleIndices,Normals,UV0,VertexColors,Tangents,bCreateCollision);//设置材质if (InMaterial){ProceduralMesh->SetMaterial(0, InMaterial);}else{UE_LOG(LogTemp, Warning, TEXT("GenerateMeshFromTriangles: Input Material (InMaterial) is null. Mesh section 0 might have default material."));// if (DefaultMaterial) ProceduralMesh->SetMaterial(0, DefaultMaterial);}
}
4. 在UE编辑器中创建基于“DrawMeshActor”的蓝图派生类“BP_DrawMeshActor”,再创建一个材质
在“BP_DrawMeshActor”事件图表中调用函数“GenerateMesh”来生成自定义网格体
最终效果如文章开头所示。