参考来源
主要参考的资源是https://nerivec.github.io/old-ue4-wiki/pages/procedural-mesh-component-in-cgetting-started.html,不过这并不是官方的链接,因为官方的网页似乎当前有些显示问题。。。
不过,代码上的改动比较大(变得复杂了一些)。主要是原版只生成了一个三角形,而我想要生成有体积的东西做测试。于是借用了上一篇中的数据,当然代码上构建了相同的接口。
步骤
步骤相比于上一篇使用BuildFromMeshDescriptions在运行时构建StaticMesh数据,简单很多,没有太多概念。主要就是使用UProceduralMeshComponent
的接口:
/**
* Create/replace a section for this procedural mesh component.
* This function is deprecated for Blueprints because it uses the unsupported 'Color' type. Use new 'Create Mesh Section' function which uses LinearColor instead.
* @param SectionIndex Index of the section to create or replace.
* @param Vertices Vertex buffer of all vertex positions to use for this mesh section.
* @param Triangles Index buffer indicating which vertices make up each triangle. Length must be a multiple of 3.
* @param Normals Optional array of normal vectors for each vertex. If supplied, must be same length as Vertices array.
* @param UV0 Optional array of texture co-ordinates for each vertex. If supplied, must be same length as Vertices array.
* @param VertexColors Optional array of colors for each vertex. If supplied, must be same length as Vertices array.
* @param Tangents Optional array of tangent vector for each vertex. If supplied, must be same length as Vertices array.
* @param bCreateCollision Indicates whether collision should be created for this section. This adds significant cost.
*/
UFUNCTION(BlueprintCallable, Category = "Components|ProceduralMesh", meta = (DeprecatedFunction, DeprecationMessage = "This function is deprecated for Blueprints because it uses the unsupported 'Color' type. Use new 'Create Mesh Section' function which uses LinearColor instead.", DisplayName = "Create Mesh Section FColor", AutoCreateRefTerm = "Normals,UV0,VertexColors,Tangents"))
void CreateMeshSection(int32 SectionIndex, const TArray<FVector>& Vertices, const TArray<int32>& Triangles, const TArray<FVector>& Normals, const TArray<FVector2D>& UV0, const TArray<FColor>& VertexColors, const TArray<FProcMeshTangent>& Tangents, bool bCreateCollision)
另外要注意,UProceduralMeshComponent
来自于 \Plugins\Runtime\ProceduralMeshComponent\Source\ProceduralMeshComponent模块。
要在.Build.cs
文件中依赖这个模块:
代码
TestRTBuildPMActor.h
:
#pragma once
#include "GameFramework/Actor.h"
#include "TestRTBuildPMActor.generated.h"
UCLASS()
class ATestRTBuildPMActor : public AActor
{
public:
GENERATED_UCLASS_BODY()
UPROPERTY()
class UProceduralMeshComponent *PMC;
/** Overridable native event for when play begins for this actor. */
virtual void BeginPlay() override;
};
TestRTBuildPMActor.cpp
:
#include "TestRTBuildPMActor.h"
#include "ProceduralMeshComponent.h"
ATestRTBuildPMActor::ATestRTBuildPMActor(const FObjectInitializer & ObjectInitializer)
: Super(ObjectInitializer)
{
//创建 ProceduralMeshComponent 对象:
PMC = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("myPMC"), false);
//设定其为根组件:
SetRootComponent(PMC);
}
void ATestRTBuildPMActor::BeginPlay()
{
//指定 5 个顶点各自的位置:
TArray<FVector> VertexPositions;
VertexPositions.Add(FVector(0.0, 0.0, 100.0)); // 顶尖
VertexPositions.Add(FVector(-50.0, 50.0, 0.0)); // 角 1
VertexPositions.Add(FVector(-50.0, -50.0, 0.0)); // 角 2
VertexPositions.Add(FVector(50.0, -50.0, 0.0)); // 角 3
VertexPositions.Add(FVector(50.0, 50.0, 0.0)); // 角 4
//为了方便,定义一个结构体来封装三角形中一个顶点的信息
struct VertexInfo
{
int ID; //对应的顶点ID
FVector Normal; //法线
FVector2D UV; //UV
VertexInfo(int InID, FVector InNormal, FVector2D InUV)
:ID(InID), Normal(InNormal), UV(InUV)
{
}
};
//当前MeshSection的数目
int MeshSectionCount = 0;
//为了方便,创建一个局部函数用来快速根据给定的顶点信息创建三角形
auto AppendTriangle = [this,&MeshSectionCount,&VertexPositions](TArray<VertexInfo> data)
{
TArray<FVector> Vertices;
TArray<int32> Indices;
TArray<FVector> Normals;
TArray<FVector2D> UV0;
TArray<FLinearColor> VertexColors;
TArray<FProcMeshTangent> Tangents;
for (int i = 0; i < 3; i++)
{
Vertices.Add(VertexPositions[data[i].ID]); //位置
Indices.Add(i); //索引
Normals.Add(data[i].Normal); //法线
UV0.Add(data[i].UV); //UV
Tangents.Add(FProcMeshTangent(0, 1, 0)); //切线暂时不需要,所以固定一个无用的值
VertexColors.Add(FLinearColor(1.0, 1.0, 1.0, 1.0)); //顶点色暂时不需要,所以固定成白色
}
//调用 ProceduralMeshComponent 的接口创建三角形!
PMC->CreateMeshSection_LinearColor(
MeshSectionCount, //SectionIndex
Vertices, Indices, Normals, UV0, VertexColors, Tangents, //顶点数据列表
true); //bCreateCollision
MeshSectionCount++;//递增MeshSection
};
//四个面的数据:
// 面 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)) });
// Enable collision data
PMC->ContainsPhysicsTriMeshData(true);
}
效果
将ATestRTBuildPMActor
拖入场景,点击Play后就可以看到金字塔了,看起来应和上一篇一样。
不过,值得注意的是。这次生成的模型碰撞更为精确(测试时将Actor缩放为(10,10,2)了):
不像上一篇使用的BuildFromMeshDescriptions在运行时构建StaticMesh数据,碰撞构建的是简单碰撞: