執筆者 / M.M
はじめに
UE4にてプロシージャルメッシュを触ることがありましたので、自分自身の知見を深めると同時に情報をまとめるために記事を書かせていただきました。
プロシージャルメッシュとは、簡単に説明するとランタイムでメッシュの作成や修正を可能にするもののことを言います。例えば、オブジェクトを切る演出をしたいときや、メッシュ自身をすりつぶしたりする形を作りたいときに使える手法です。
プロシージャルメッシュを作る手法はスタティックメッシュから作成していくパターンと頂点やマテリアルの情報等から作成していくパターンの2つがあります。本記事では後者である頂点、マテリアルの情報からプロシージャルメッシュを作成していく手法を紹介していきます。
用意するもの
・Unreal Engine 4.26
・Visual Studio 2019
実装手順
まずはC++側から作成していきます。実際プロシージャルメッシュを作成するためのブループリントはエンジンに用意されていますのでC++を書かなくても実装できますが、前述でも話した通り、自身の知見のためC++を織り交ぜていきます。
まずはC++側でプロシージャルメッシュを作成するためのプラグインProceduralMeshComponentを使用するためBuild.csを修正していきます。
// Fill out your copyright notice in the Description page of Project Settings.
using UnrealBuildTool;
public class ProceduralMesh : ModuleRules
{
public ProceduralMesh(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "ProceduralMeshComponent" });
PrivateDependencyModuleNames.AddRange(new string[] { });
// Uncomment if you are using Slate UI
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
// Uncomment if you are using online features
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
}
}
デフォルトで作成されたBuild.csのPublicDependencyModuleNames.AddRangeにProceduralMeshComponentを追加しただけになります。
次にUnrealEngineからC++クラスを作成します。
UnrealEngineのコンテンツブラウザから「新規/インポート」→「新規C++クラス」を選択します。
出現したウィンドウの右上にある「全てのクラスを表示」にチェックを入れます。
検索からProceduralMeshComponentを選択して次へを選択します。
任意のファイル名を選択して作成します。
作成したファイルを以下のように編集します。
#pragma once
#include "CoreMinimal.h"
#include "ProceduralMeshComponent.h"
#include "MyProceduralMeshComponent.generated.h"
/**
*
*/
UCLASS(meta = (BlueprintSpawnableComponent), ClassGroup = Rendering)
class PROCEDURALMESH_API UMyProceduralMeshComponent : public UProceduralMeshComponent
{
GENERATED_BODY()
public:
UFUNCTION(Category = "MyProceduralMeshComponent", BlueprintCallable)
void CreateMesh();
};
#include "MyProceduralMeshComponent.h"
#include "Kismet/KismetMathLibrary.h"
void UMyProceduralMeshComponent::CreateMesh()
{
TArray<FVector> Vertices;
Vertices.Add(FVector(0, 0, 0));
Vertices.Add(FVector(0, 100, 0));
Vertices.Add(FVector(0, 50, 100));
Vertices.Add(FVector(100, 0, 0));
Vertices.Add(FVector(100, 100, 0));
Vertices.Add(FVector(100, 50, 100));
TArray<int32> Triangles;
Triangles.Add(0);
Triangles.Add(1);
Triangles.Add(2);
Triangles.Add(5);
Triangles.Add(4);
Triangles.Add(3);
Triangles.Add(0);
Triangles.Add(3);
Triangles.Add(4);
Triangles.Add(4);
Triangles.Add(1);
Triangles.Add(0);
Triangles.Add(1);
Triangles.Add(4);
Triangles.Add(5);
Triangles.Add(5);
Triangles.Add(2);
Triangles.Add(1);
Triangles.Add(0);
Triangles.Add(2);
Triangles.Add(5);
Triangles.Add(5);
Triangles.Add(3);
Triangles.Add(0);
CreateMeshSection(
0,
Vertices,
Triangles,
TArray<FVector>(),
TArray<FVector2D>(),
TArray<FColor>{},
TArray<FProcMeshTangent>{},
true
);
}
最後に作成したコンポーネントを適応させるアクターを作ります。
アクターを作成したら先ほど作ったコンポーネントを追加し、以下のようにブループリントを作成してください。SetMaterialノードには任意のマテリアルを設定してください。
最後に任意のマップにアクターを配置して準備完了です。
実行
実行することでアクターを配置した場所に三角柱が表示されていることが確認できます。
出現したこの三角柱こそがプロシージャルメッシュで作られたものになります。
面を作成する場合の補足
上記コードにあるTrianglesが面のデータとなるのですが、3つごとに指定された頂点の間に三角形の面を作成します。
例えば上記コードですと、最初に0,1,2の3つを追加していますが、これは点の情報であるVerticesの要素数を指定しており、それぞれの座標点(0はFVector(0, 0, 0)で三角柱の前面の左下、1はFVector(0, 100, 0)で三角柱の前面の右下、2はFVector(0, 50, 100)で三角柱の前面の上)を結ぶ面を作成してます。
ここで注意するべきポイントは、座標を半時計回りに指定するか時計回りに指定するかで面の向きが異なることに注意してください。例えば上記Trianglesにおいて
最初に追加する順番を0,1,2ではなく2,1,0にした場合以下のような形になり面の向きが外側ではなく内側になります。内側になったことで透けているように見えてしまいます。
まとめ
今回は簡易的にプロシージャルメッシュを作成してみました。
まだ原因はわかりませんが、「Slice ProceduralMesh」がうまく実行されないようで、プロシージャルメッシュの利点が活かせてないため、実際ゲーム等でプロシージャルメッシュを使う場合は点や面のデータから作るよりも、スタティックメッシュから作る形が望ましいかもしれません。
しかし点と面のデータを保持しているためか、部分的なメッシュの移動を行うのであればこちらの方法がスタティックメッシュから作るよりも都合の良い場合もあるのかと思いました。
プロシージャルメッシュを作成する方の参考になりましたら幸いです。