RuntimeMeshComponentについて


RuntimeMeshComponentとは?

Unreal Engine4にて、動的にサーフェイスメッシュを扱うためには、ProceduralMeshComponent(PMC)があります。RuntimeMeshComponent(RMC)はその代替として開発された、より効率的で多様な機能があって多様なユースケースに対応できるのだそうです。どのくらい優れているかは、以下の指標が端的に示しています。

  1. 50-90% Lower memory usage than PMC (PMCよりメモリ効率が良い)
  2. 30-100% lower render thread cpu time (PMCよりレンダリング時間が短い)
  3. Static draw path for maximum rendering performance (静的なメッシュに対しては、最高のレンダリング性能)
  4. Dynamic Draw path for efficient frequent updates. (高頻度で変化する動的なメッシュに対して効果的)

このライブラリはいろんなところで使われているようなのですが、日本語での解説が少なかったり、提供されているC++のサンプルがそのまま動かなかったりという問題があります。ここでは、簡単なサンプルを試すまでの手順を説明したいと思います。なお、UE4のバージョンは4.25、Visual Studio 2019 Communityを使っています。

インストール

Gitのページでソースコードをダウンロードします。マーケットプレイスにはありません。

適当なプロジェクト(RMCTest)を作り、プロジェクトフォルダの最上位階層に、Pluginsフォルダを作ります。その中に、ソースコードを解凍してできたRuntimeMeshComponentフォルダを配置します。UE4の仕様では、Pluginsフォルダの中にあるxxxx.upluginという拡張子のファイルを再帰的に探して読み込むようです。うまくいくと、ウィンドウ -> デベロッパーツール -> モジュール
内に当該プラグインが発見できます。

簡易的なC++サンプル

ブループリントについては、サンプルプロジェクトを見れば分かるので、ここではC++について触れます。バージョンが違うためか、そのままでは動きません。

まずは、RuntimeMeshActorを継承した適当なクラスを作ります。インストールが成功していれば候補に出てくるはずです。ここではサンプルに倣って、ABasicPMCStyleRMCと名前を付けます。

続いて、C++のプロジェクトで、当該プラグインを読み込ませるための設定を行います。以下のように、PublicDependencyModuleNamesRuntimeMeshComponentを追記します。ここまでやって、リビルドしたところで、RMCTest.uprojectを右クリックしてGenerate Visual Studio Project Filesをしておいた方が良いようです。

RMCTest.Build.cs
using UnrealBuildTool;

public class RMCTest : ModuleRules
{
    public RMCTest(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "RuntimeMeshComponent" });

    }
}

続いて、作成したABasicPMCStyleRMCに簡易的なメッシュに色を付けたものを自動生成するコードを追加します。元のサンプルだと、OnConstructionを使っていたのですが、どうしても呼ばれなかったので、BeginPlay内に生成コードを入れています。結果としては同じになるかと思いますが、もしOnConstructionを使った方がいい場合は誰か教えてください。

ここに書いてあるように、マテリアル情報はきちんとUI上で付与する必要があります。

BasicPMCStyleRMC.h

#pragma once

#include "CoreMinimal.h"
#include "RuntimeMeshActor.h"
#include "BasicPMCStyleRMC.generated.h"

UCLASS()
class ABasicPMCStyleRMC : public ARuntimeMeshActor
{
    GENERATED_BODY()

public: 
    UPROPERTY(EditAnywhere)
    UMaterialInterface* Material;

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;


public: 
    // Sets default values for this actor's properties
    ABasicPMCStyleRMC();
    // Called every frame
    virtual void Tick(float DeltaTime) override;

};

続いて、関数の実装部分です。
StaticProviderを作って、そこに頂点やインデックス、マテリアル情報などを設定していくのは、PMCと同じような考え方です。OBJファイルと同じだと思えば、そんなに混乱はないですね。Blueprintでも勿論かけますが、公式サイトではC++での実装を推奨しています。これは単純に速さのためだそうです。

BasicPMCStyleRMC.cpp
#include "BasicPMCStyleRMC.h"
#include "Providers/RuntimeMeshProviderStatic.h"

// Sets default values
ABasicPMCStyleRMC::ABasicPMCStyleRMC() : Material(nullptr)
{
    // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

}


// Called when the game starts or when spawned
void ABasicPMCStyleRMC::BeginPlay()
{
    Super::BeginPlay();
    UE_LOG(LogTemp, Log, TEXT("BeginPlay"));
    URuntimeMeshProviderStatic* StaticProvider = NewObject<URuntimeMeshProviderStatic>(this, TEXT("RuntimeMeshProvider-Static"));

    if (StaticProvider)
    {
        // The static provider should initialize before we use it
        GetRuntimeMeshComponent()->Initialize(StaticProvider);
        UE_LOG(LogTemp, Log, TEXT("TriMat"));


        // This creates 3 positions for a triangle
        TArray<FVector> Positions{ FVector(0, -50, 20), FVector(0, 0, 100), FVector(0, 50, 0) };

        // This creates 3 vertex colors
        TArray<FColor> Colors{ FColor::Blue, FColor::Red, FColor::Green };

        // This indexes our simple triangle
        TArray<int32> Triangles = { 0, 1, 2 };

        TArray<FVector> EmptyNormals;
        TArray<FVector2D> EmptyTexCoords;
        TArray<FRuntimeMeshTangent> EmptyTangents;
        StaticProvider->CreateSectionFromComponents(0, 0, 0, Positions, Triangles, EmptyNormals, EmptyTexCoords, Colors, EmptyTangents, ERuntimeMeshUpdateFrequency::Infrequent, true);
        StaticProvider->SetupMaterialSlot(0, TEXT("TriMat"), Material);

    }
}

// Called every frame
void ABasicPMCStyleRMC::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

}

続いて、マテリアル情報を作ります。M_Testという名前で作成しています。ここで重要なのは、ベースカラーとしてVertex Colorを充てることです。

次に、作成したABasicPMCStyleRMCをベースにしたブループリントを作ります。BP_BasicPMCStyleRMCとでもして、適当なフォルダに作っておきましょう。作成したブループリントのアクターをレベルに配置して、詳細パネルでMaterialをM_Testに設定します。これで下の画面のように表示されれば成功です。

参考