UE4尝试用C++生成一个最简单的StaticMesh

128 篇文章 150 订阅

目标

通常,一个StaticMesh资源由一个模型文件(如fbx)导入得到。不过如果需要和某种程序化生成工具(如Houdini)交互,则需要用C++代码从特定数据中读取顶点数据然后生成StaticMesh。我想了解下这个过程。
我发现基础的步骤并不复杂,概括讲:

  1. 生成一个空的UStaticMesh
  2. 创建一个FRawMesh
  3. UStaticMesh中添加一个FStaticMeshSourceModel,然后调用SaveRawMesh接口来将FRawMesh保存进去。
  4. 调用UStaticMeshBuild接口。

本篇目标是创建一个插件,其中点击一个按钮可以生成一个最简单的StaticMesh。

0.插件

Editor Toolbar Button为模板创建一个插件。(其实这里对模板并没有什么严格的要求,选它是因为会在界面上生成一个按钮,比较方便)
插件名为TestCodeMeshPlg在这里插入图片描述
在这里插入图片描述
接下来就可以在FTestCodeMeshPlgModule::PluginButtonClicked()中指定这个按钮点击后的操作了。

1.创建StaticMesh资源

//设定模型名字
FString MeshName = "TestSM";	
//设定包的路径
FString PackageName = "/Game/"+ MeshName;	
//创建包
UPackage * MeshPackage = CreatePackage(nullptr, *PackageName);	
//创建StaticMesh资源
UStaticMesh *StaticMesh = NewObject< UStaticMesh >(MeshPackage, FName(*MeshName), RF_Public | RF_Standalone);

2. 创建RawMesh

在创建之前,需要知道FRawMesh有一个接口,负责检查当前的数据是否有效

/** 
 * Returns true if the mesh contains valid information.
 *  - Validates that stream sizes match.
 *  - Validates that there is at least one texture coordinate.
 *  - Validates that indices are valid positions in the vertex stream.
 */
RAWMESH_API bool IsValid() const;

他检查的具体内容如下:

bool FRawMesh::IsValid() const
{
	int32 NumVertices = VertexPositions.Num();
	int32 NumWedges = WedgeIndices.Num();
	int32 NumFaces = NumWedges / 3;

	bool bValid = NumVertices > 0
		&& NumWedges > 0
		&& NumFaces > 0
		&& (NumWedges / 3) == NumFaces
		&& ValidateArraySize(FaceMaterialIndices, NumFaces)
		&& ValidateArraySize(FaceSmoothingMasks, NumFaces)
		&& ValidateArraySize(WedgeTangentX, NumWedges)
		&& ValidateArraySize(WedgeTangentY, NumWedges)
		&& ValidateArraySize(WedgeTangentZ, NumWedges)
		&& ValidateArraySize(WedgeColors, NumWedges)
		// All meshes must have a valid texture coordinate.
		&& WedgeTexCoords[0].Num() == NumWedges; 

	for (int32 TexCoordIndex = 1; TexCoordIndex < MAX_MESH_TEXTURE_COORDS; ++TexCoordIndex)
	{
		bValid = bValid && ValidateArraySize(WedgeTexCoords[TexCoordIndex], NumWedges);
	}

	int32 WedgeIndex = 0;
	while (bValid && WedgeIndex < NumWedges)
	{
		bValid = bValid && ( WedgeIndices[WedgeIndex] < (uint32)NumVertices );
		WedgeIndex++;
	}

	return bValid;
}

这样就需要注意,创建的FRawMesh的数据要通过上面的检查。


下面是为了测试所创建的一个最简单的RawMesh,只是一个直角三角形。

//测试RawMesh
FRawMesh RawMesh;
//顶点位置数据,一个直角三角形
RawMesh.VertexPositions.Add(FVector(0, 0, 0));
RawMesh.VertexPositions.Add(FVector(1, 0, 0));
RawMesh.VertexPositions.Add(FVector(1, 1, 0));
//索引数据
RawMesh.WedgeIndices.Add(0);
RawMesh.WedgeIndices.Add(1);
RawMesh.WedgeIndices.Add(2);
//接下来的数据并不重要,只是需要满足Array的长度以能通过 FRawMesh::IsValid()
RawMesh.WedgeTexCoords->Add(FVector2D(0, 0));
RawMesh.WedgeTexCoords->Add(FVector2D(1, 0));
RawMesh.WedgeTexCoords->Add(FVector2D(1, 1));
RawMesh.FaceMaterialIndices.Add(0);
RawMesh.FaceSmoothingMasks.Add(0);
RawMesh.WedgeTangentX.Add(FVector(1,0,0));
RawMesh.WedgeTangentX.Add(FVector(1, 0, 0));
RawMesh.WedgeTangentX.Add(FVector(1, 0, 0));
RawMesh.WedgeTangentY.Add(FVector(0, 1, 0));
RawMesh.WedgeTangentY.Add(FVector(0, 1, 0));
RawMesh.WedgeTangentY.Add(FVector(0, 1, 0));
RawMesh.WedgeTangentZ.Add(FVector(0, 0, 1));
RawMesh.WedgeTangentZ.Add(FVector(0, 0, 1));
RawMesh.WedgeTangentZ.Add(FVector(0, 0, 1));

另外要注意的是,需要让插件的模块依赖RawMesh这个模块:
在这里插入图片描述

3. 创建StaticMeshSourceModel

先标注需要开始编辑这个StaticMesh了:

StaticMesh->PreEditChange(nullptr);

添加一个FStaticMeshSourceModel

FStaticMeshSourceModel & SrcModel = StaticMesh->AddSourceModel();

保存RawMesh

SrcModel.SaveRawMesh(RawMesh);

4. 对StaticMesh进行Build

TArray< FText > BuildErrors;
StaticMesh->Build(true, &BuildErrors);

随后通知Asset创建

FAssetRegistryModule::AssetCreated(StaticMesh);

效果

点击按钮后可看到创建了一个StaticMesh
在这里插入图片描述
打开可看到小三角形:
在这里插入图片描述

  • 11
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值