学习使用BuildFromMeshDescriptions在运行时构建StaticMesh数据

128 篇文章 154 订阅

参考来源

主要参考:Building a StaticMesh in C++ during runtime

步骤

有一些概念还不太清楚,不过大体上是:

  1. 创建 UStaticMesh 资源
  2. 声明一个 FMeshDescription 对象
  3. 使用 FMeshDescription 来创建 FStaticMeshAttributes 并注册。
  4. FMeshDescription 来创建一个 FMeshDescriptionBuilder 协助构建数据。
  5. 使用 FMeshDescriptionBuilder 的方法来构建顶点和三角形数据。
  6. 调用 UStaticMesh 的函数BuildFromMeshDescriptions来进行构建数据。此函数参数是 FMeshDescription
  7. UStaticMeshComponent 设置 UStaticMesh 。

其中:

  • FMeshDescription 来源于 \Runtime\MeshDescription 模块 。
  • FStaticMeshAttributes 来源于 \Runtime\StaticMeshDescription 模块 。
  • FMeshDescriptionBuilder 来源于 \Plugins\Experimental\GeometryProcessing\Source\MeshConversion 模块。正如注释所说:Utility class to construct MeshDescription instances. 它是为了更方便构造 FMeshDescription 而存在的。

要想使用它们,需要在模块的.Build.cs中添加对这些模块的依赖:
在这里插入图片描述

代码

我这里的代码对原始版本稍加了改动。一是注释方面,二是做了些重构使得在指定数据方面代码量不那么大且更容易看清数据。

TestRTBuildSMActor.h

#pragma once

#include "GameFramework/Actor.h"
#include "TestRTBuildSMActor.generated.h"

UCLASS()
class ATestRTBuildSMActor : public AActor
{
public:
	GENERATED_UCLASS_BODY()

	UPROPERTY()
	UStaticMeshComponent *_smComp;

	/** Overridable native event for when play begins for this actor. */
	virtual void BeginPlay() override;
};

TestRTBuildSMActor.cpp

#include"TestRTBuildSMActor.h"

#include "MeshDescription.h"
#include "MeshDescriptionBuilder.h"
#include "StaticMeshAttributes.h"

ATestRTBuildSMActor::ATestRTBuildSMActor(const FObjectInitializer & ObjectInitializer)
	: Super(ObjectInitializer)
{
	//创建 StaticMeshComponent 对象:
	_smComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("smComp"), false);
	
	//设定其为根组件:
	SetRootComponent(_smComp);
}

void ATestRTBuildSMActor::BeginPlay()
{
	// 构建一个简单的金字塔

	// 创建 StaticMesh 资源
	UStaticMesh* staticMesh = NewObject<UStaticMesh>(this);
	staticMesh->GetStaticMaterials().Add(FStaticMaterial());//至少添加一个材质

	// MeshDescription 将会描述StaticMesh的信息,包括几何,UV,法线 等
	FMeshDescription meshDesc;
	
	FStaticMeshAttributes Attributes(meshDesc);
	Attributes.Register();

	//为 MeshDescription 创建一个 MeshDescriptionBuilder 协助构建数据
	FMeshDescriptionBuilder meshDescBuilder;
	meshDescBuilder.SetMeshDescription(&meshDesc);
	meshDescBuilder.EnablePolyGroups();
	meshDescBuilder.SetNumUVLayers(1);

	//使用 MeshDescriptionBuilder 来构建数据:
	{
		// 创建 5 个顶点 
		TArray< FVertexID > vertexIDs;
		vertexIDs.SetNum(5);

		//指定 5 个顶点各自的位置:
		vertexIDs[0] = meshDescBuilder.AppendVertex(FVector(0.0, 0.0, 100.0));		// 顶尖
		vertexIDs[1] = meshDescBuilder.AppendVertex(FVector(-50.0, 50.0, 0.0));		// 角 1
		vertexIDs[2] = meshDescBuilder.AppendVertex(FVector(-50.0, -50.0, 0.0));	// 角 2
		vertexIDs[3] = meshDescBuilder.AppendVertex(FVector(50.0, -50.0, 0.0));		// 角 3
		vertexIDs[4] = meshDescBuilder.AppendVertex(FVector(50.0, 50.0, 0.0));		// 角 4

		// 分配一个 polygon group
		FPolygonGroupID polygonGroup = meshDescBuilder.AppendPolygonGroup();

		//为了方便,定义一个结构体来封装三角形中一个顶点的信息
		struct VertexInfo 
		{
			int ID;					//对应的顶点ID
			FVector InstanceNormal;	//此三角形中顶点的法线
			FVector2D InstanceUV;	//此三角形中顶点的UV
			VertexInfo(int InID, FVector InInstanceNormal, FVector2D InInstanceUV)
				:ID(InID), InstanceNormal(InInstanceNormal), InstanceUV(InInstanceUV)
			{
			}
		};

		//为了方便,创建一个局部函数用来快速根据给定的顶点信息创建三角形
		auto AppendTriangle = [&meshDescBuilder, &vertexIDs, polygonGroup](TArray<VertexInfo> vertex)
		{
			TArray< FVertexInstanceID > vertexInsts;//三角形中的每个顶点
			for (int i = 0; i < 3; i++)
			{
				FVertexInstanceID instance = meshDescBuilder.AppendInstance(vertexIDs[vertex[i].ID]);
				meshDescBuilder.SetInstanceNormal(instance, vertex[i].InstanceNormal);			//法线
				meshDescBuilder.SetInstanceUV(instance, vertex[i].InstanceUV, 0);				//UV
				meshDescBuilder.SetInstanceColor(instance, FVector4(1.0f, 1.0f, 1.0f, 1.0f));	//顶点色
				vertexInsts.Add(instance);
			}
			//增加此三角形
			meshDescBuilder.AppendTriangle(vertexInsts[0], vertexInsts[1], vertexInsts[2], polygonGroup);
		};

		//四个面的数据:

		// 面 1 (朝向 -X) 三角型的顶点数据:
		AppendTriangle({
			VertexInfo(0,FVector(-0.7071, 0, 0.7071),FVector2D(0, 1)),
			VertexInfo(2,FVector(-0.7071, 0, 0.7071),FVector2D(1, 0)),
			VertexInfo(1,FVector(-0.7071, 0, 0.7071),FVector2D(0, 0)) });
		// 面 2 (朝向 -Y) 三角型的顶点数据:
		AppendTriangle({
			VertexInfo(0,FVector(0, -0.7071, 0.7071),FVector2D(0, 1)),
			VertexInfo(3,FVector(0, -0.7071, 0.7071),FVector2D(1, 0)),
			VertexInfo(2,FVector(0, -0.7071, 0.7071),FVector2D(0, 0)) });
		// 面 3 (朝向 +X) 三角型的顶点数据:
		AppendTriangle({
			VertexInfo(0,FVector(0.7071, 0, 0.7071),FVector2D(0, 1)),
			VertexInfo(4,FVector(0.7071, 0, 0.7071),FVector2D(1, 0)),
			VertexInfo(3,FVector(0.7071, 0, 0.7071),FVector2D(0, 0)) });
		// 面 4 (朝向 +Y) 三角型的顶点数据:
		AppendTriangle({
			VertexInfo(0,FVector(0, 0.7071, 0.7071),FVector2D(0, 1)),
			VertexInfo(1,FVector(0, 0.7071, 0.7071),FVector2D(1, 0)),
			VertexInfo(4,FVector(0, 0.7071, 0.7071),FVector2D(0, 0)) });
	}

	// MeshDescription 参数
	UStaticMesh::FBuildMeshDescriptionsParams mdParams;
	mdParams.bBuildSimpleCollision = true;
	mdParams.bFastBuild = true;

	// 创建一个列表容纳 MeshDescription。(因为 BuildFromMeshDescriptions 函数的参数需要列表)
	TArray<const FMeshDescription*> meshDescPtrs;
	meshDescPtrs.Emplace(&meshDesc);

	//构建!
	staticMesh->BuildFromMeshDescriptions(meshDescPtrs, mdParams);

	// 将 StaticMesh 指定给 StaticMeshComponent组件
	_smComp->SetStaticMesh(staticMesh);
}

效果

拖动 TestRTBuildSMActor 到场景中,然后点击Play后可以看到金字塔几何体:
在这里插入图片描述

在控制台输入show Collision后,可以看到这个StaticMesh的碰撞是简单碰撞:
在这里插入图片描述

要将ProceduralMesh转换为StaticMesh,你需要执行以下步骤: 1. 创建一个StaticMesh对象,可以使用`CreateDefaultSubobject<UStaticMesh>(TEXT("StaticMesh"))`来创建。 2. 创建一个StaticMeshComponent对象,并将StaticMesh对象分配给它,可以使用`CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComponent"))`来创建。 3. 创建一个用于存储顶点和面信息的ProceduralMeshComponent对象。 4. 使用ProceduralMeshComponent的函数(如`GetProcMeshSection`)获取ProceduralMesh的顶点和面信息。 5. 使用StaticMesh对象的函数(如`CreateSectionFromProcMesh`)将ProceduralMesh的顶点和面信息分配给StaticMesh。 6. 使用StaticMesh对象的函数(如`Build`)来构建StaticMesh。 下面是一个示例代码,演示了如何将ProceduralMesh转换为StaticMesh: ```cpp // 创建StaticMesh对象 UStaticMesh* StaticMesh = CreateDefaultSubobject<UStaticMesh>(TEXT("StaticMesh")); // 创建StaticMeshComponent对象并分配StaticMesh UStaticMeshComponent* StaticMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComponent")); StaticMeshComponent->SetStaticMesh(StaticMesh); // 创建ProceduralMeshComponent对象 UProceduralMeshComponent* ProceduralMeshComponent = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("ProceduralMeshComponent")); // 获取ProceduralMesh的顶点和面信息 FProcMeshSection ProcMeshSection; ProceduralMeshComponent->GetProcMeshSection(0, ProcMeshSection); // 将ProceduralMesh的顶点和面信息分配给StaticMesh StaticMesh->CreateSectionFromProcMesh(0, ProcMeshSection); // 构建StaticMesh StaticMesh->Build(); ``` 请注意,这只是一个基本示例,并且可能需要根据你的具体需求进行修改。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值