ALCCActorBase:3DGS Actor の基底クラス
すべての LCC Actor の基底クラスで、3DGS データをレベルに配置する役割を持つ。ALCCActor、ALCC2Actor、ASogActor、ASpzActor、APlyActor はいずれもこれを継承する。
| モジュール | LCC4UnrealRuntime |
| ヘッダーファイル | LCCActorBase.h |
| 親クラス | AActor |
| Blueprint | 継承できる(BlueprintType) |
#include "LCCActorBase.h"
Actor 自体はレンダリングを行わない。ULCCComponentBase を 1 つ保持し、読み込み系の操作をそこへ転送する。レンダリングのパラメーター、カラー、パフォーマンス、コリジョンはすべて Component 側にあり、GetLCCComponent で取得する。
スケールの制限:LCC 系の Actor は等比のスケールにのみ対応する。 負の値を含むスケール(
(-1, 1, 1)など)や、軸ごとに値が異なるスケール((2, 1, 3)など)は使わない。使うとレンダリングの異常が起き、画面上では通常線が 1 本入るように見える。
Properties
| プロパティ | 型 | アクセス | 説明 |
|---|---|---|---|
DefaultSceneRoot | ULCCFocusRootComponent* | 読み取り専用 | 見えないルートコンポーネント。存在する目的はエディターのビューポートに固定の小さなバウンディングボックスを与えることだけであり、F でフォーカスするときにシーンが巨大なために機能しなくなるのを防ぐ。 |
LCCComponent | ULCCComponentBase* | 読み取り専用 | 実際に処理を行うコンポーネント。具体的な型はサブクラスの構築時に決まる。 |
2 つのプロパティはいずれも VisibleAnywhere + BlueprintReadOnly であり、Details パネルや Blueprint から差し替えることはできず、読み取りのみできる。
Methods
Load
UFUNCTION(BlueprintCallable, Category = "XGrids")
virtual void Load(const FString& String) const;
パスを指定して 3DGS データを読み込む。これが実行時にシーンを読み込む主な入口である。
パラメーター:
| パラメーター | 型 | 説明 |
|---|---|---|
String | const FString& | データファイルのパス。絶対パス(D:/Data/Tower/Tower.lcc)と相対パスに対応する。相対パスはプロジェクトの Content ディレクトリを基準にする。たとえば Tower/Tower.lcc は Content/Tower/Tower.lcc を指す。 |
サブクラスによって受け付けるパスの形態が異なる。
| Actor | 何を渡すか |
|---|---|
ALCCActor | LCC1 の .lcc ファイルのパス。ファイル名は固定ではなく、同じディレクトリに data.bin と index.bin が必要である |
ALCC2Actor | LCC2 の .lcc2 ファイルのパス。ファイル名は固定ではない |
ASogActor | .sog ファイルのパス |
ASpzActor | .spz ファイルのパス |
APlyActor | .ply ファイルのパス。拡張子が .ply でない場合は直接拒否される |
注:
.lccと.lcc2のファイル名はデータの作成側が決めるので、必ずmeta.lccという名前だと決めつけない。形式を判定するには拡張子を見るか、ULCCUtilLibrary::DetermineFileFormat を使う。
使い方の要点:
- このメソッドは
constである。状態の変更はLCCComponentの内部で起き、Actor 自身は変更しないためである。 - 読み込みは非同期である。呼び出しから戻った時点ではデータはまだ準備できていないので、現在のバージョンでは
GetLCCComponent()->CheckIfLoaded()でポーリングする必要がある。今後のバージョンで読み込み完了のコールバックを提供する予定であり、その時点でポーリングは不要になる。 CheckIfLoaded()がtrueを返すのは、メタ情報とインデックスが構築されてパラメーターの読み書きを安全に行えることを意味するだけである。Splat のデータは引き続き視点に応じてストリーミング読み込みされ、画面は補完され続ける。- コードを書かずにレベル上でパスを事前設定したい場合は、Details パネルで Component の
DefaultLoadPathを設定すれば、実行時に自動的に読み込まれる。 - 空のパスを渡すと現在のデータをアンロードするのと同じになる。
- 渡したパスが現在読み込まれているパスと同じ場合、呼び出しは何もせずに戻り、再読み込みはされない。
- パスが疑わしい場合は先に ULCCUtilLibrary::CheckLCCValid で検証し、読み込みの失敗がログにだけ出る状況を避ける。
C++ の例:
#include "LCCActor.h"
#include "LCCComponentBase.h"
void AMyGameMode::SpawnLCCScene()
{
// Actor を生成する
ALCCActor* LCCActor = GetWorld()->SpawnActor<ALCCActor>(
ALCCActor::StaticClass(),
FVector::ZeroVector,
FRotator::ZeroRotator);
if (!LCCActor)
{
return;
}
// 絶対パスで読み込む
LCCActor->Load(TEXT("D:/Data/Tower/Tower.lcc"));
// または Content ディレクトリからの相対パスで読み込む
// LCCActor->Load(TEXT("Tower/Tower.lcc"));
}
読み込みの完了を待ってから操作する。現在のバージョンにはコールバックがないため、ポーリングするしかない。
void AMyActor::LoadAndConfigure()
{
LCCActor->Load(TEXT("D:/Data/Tower/Tower.lcc"));
// 0.2 秒ごとに準備できたかを確認する
GetWorld()->GetTimerManager().SetTimer(
LoadCheckTimer, this, &AMyActor::OnCheckLoaded, 0.2f, true);
}
void AMyActor::OnCheckLoaded()
{
ULCCComponentBase* Component = LCCActor->GetLCCComponent();
if (!Component || !Component->CheckIfLoaded())
{
return;
}
GetWorld()->GetTimerManager().ClearTimer(LoadCheckTimer);
// メタ情報が準備できたので、安全にパラメーターを設定できる(Splat データは引き続きストリーミング読み込み中)
Component->SetRenderMode(ERenderMode::Splatting);
UE_LOG(LogTemp, Log, TEXT("Total splats: %d"), Component->GetSplatNumber());
}
テキスト形式の Blueprint:
[Event BeginPlay]
│
▼
[Spawn Actor from Class]
Class = LCCActor
Spawn Transform = (既定値)
│ Return Value ──┐
▼ │
[Load] ◀────────────────┘
Target = (前の手順の Return Value)
String = "D:/Data/Tower/Tower.lcc"
UnLoad
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "UnLoad", DisplayPriority = 2))
virtual void UnLoad();
現在のデータをアンロードしてリソースを解放する。GPU のバッファ、ノードのキャッシュ、コリジョンボディを含む。
使い方の要点:
CallInEditorが付いているため、Details パネルの Actions カテゴリーに UnLoad ボタンがあり、エディターから直接クリックできる。- アンロードした後も Actor はレベルに残り、内容をレンダリングしなくなるだけである。再度
Loadを呼べば別のデータを読み込める。 - 大きなシーンを切り替えるときは先に
UnLoadしてからLoadし、2 つのデータが同時にビデオメモリを占有するのを避ける。 EndPlayで手動で呼ぶ必要はない。Component が破棄されるときに自動でクリーンアップされる。
C++ の例。シーンを切り替える。
void AMyManager::SwitchScene(const FString& NewPath)
{
// 先に古いデータを解放し、ビデオメモリのピークが重なるのを防ぐ
LCCActor->UnLoad();
LCCActor->Load(NewPath);
}
Refresh
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayPriority = 3))
virtual void Refresh();
現在のデータを再読み込みする。内部の実装は先に UnLoad() してから Load() するものなので、コストは完全な再読み込み 1 回と同等であり、軽い操作ではない。
「現在の」データを再読み込みできるのは、読み込みが成功したときにパスが DefaultLoadPath に同期して書き込まれるためであり、Refresh はこの値を取る。
使い方の要点:
- ディスク上のデータファイルが差し替えられた後、これでディスクから読み直す。
- レンダリング結果を計算し直したいだけの目的では使わない。プロパティは Setter を通せば自動的に更新がトリガーされる。1 フレーム押す必要が実際にある場合は Component の
ForceUpdate()を使う。そちらが軽い操作である。 - 再読み込みした後は改めて準備完了を待つ必要があり、それまでに Component に設定した実行時のパラメーターは状況に応じて再設定する必要がある。
- エディターの Details パネルの Actions カテゴリーに対応するボタンがある。
GetLCCComponent
UFUNCTION(BlueprintCallable, Category = "XGrids")
ULCCComponentBase* GetLCCComponent() const;
Actor 内部の Component のポインターを返す。これがすべてのレンダリング機能へアクセスする入口である。
戻り値:ULCCComponentBase*。通常は非 null であり、Actor の構築時に作成されている。
使い方の要点:
- サブクラス専用の機能が必要な場合はダウンキャストする。
ALCCActorから取得できるのはULCCComponent、ALCC2Actorと 3 つの単一ファイル Actor から取得できるのはULCC2Componentである。 - キャストには必ず
Cast<>を使い、C スタイルのキャストは使わない。型が一致しない場合Castはnullptrを返すので、早期リターンしやすい。
C++ の例。基底クラス共通のパラメーターを変更する。
ULCCComponentBase* Component = LCCActor->GetLCCComponent();
if (Component)
{
Component->SetSplatScale(0.8f);
Component->SetGlobalAlpha(1.0f);
}
ダウンキャストして LCC2 専用のパラメーターにアクセスする。
#include "LCC2Component.h"
ULCC2Component* LCC2Comp = Cast<ULCC2Component>(LCC2Actor->GetLCCComponent());
if (LCC2Comp)
{
LCC2Comp->SetSHBands(2);
LCC2Comp->NormalMode = ELCC2NormalGenerationMode::Hemispherical;
}
テキスト形式の Blueprint。Blueprint でのキャストは Cast To ノードを使う。
[Get LCC Component]
Target = LCCActor
│ Return Value ──┐
▼ │
[Cast To LCC2Component] ◀┘
Object = (前の手順の Return Value)
│ Cast Succeeded
▼
[Set SH Bands]
Target = (Cast の出力の As LCC2 Component)
In SH Bands = 2
SelectFile
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Load", DisplayPriority = 1))
virtual void SelectFile();
システムのファイル選択ダイアログを表示し、選択後すぐに読み込む。
使い方の要点:
- Details パネルでは Load ボタンとして表示され、エディターでデータを読み込むもっとも一般的な入口である。
- 各サブクラスがこれをオーバーライドして対応する拡張子でフィルターする。
ASogActorは.sogのみ、ASpzActorは.spzのみ、APlyActorは.plyのみを一覧に出す。 - エディターのダイアログ機能に依存するため、パッケージ化した後の実行時には使わない。実行時は Load を使う。
DebugNodeBound
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Debug Node Bound", DisplayPriority = 4))
void DebugNodeBound();
八分木ノードの境界の可視化を切り替え、現在読み込まれているノードをワイヤーフレームのボックスで描画する。
ボックスのカラーはノードの Level に対応する。赤、橙、黄、緑、青、紫の順に進み、赤が最も低い Level(ディテールが最も高い)、白が最も高い Level(ディテールが最も低い)である。
使い方の要点:
- LOD の問題を調べるときに使う。遠くでまだ赤いボックスがレンダリングされている場合、
LevelFactorが小さいかStartLevelが低く設定されすぎており、パフォーマンスが無駄になっている。 - 逆に近くが高い Level の寒色のボックスばかりの場合、ディテールが抑えられすぎていて画面がぼやける。
- もう一度呼ぶとオフになる、切り替え式である。
- エディターと開発ビルドでのみ有効である。
Stats
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayPriority = 5))
void Stats();
レンダリングの統計パネルを切り替える。コンソールで stat XGrids を実行するのと同等である。
パネルは現在レンダリングしている Splat 数、読み込み中のノード数、各段階の処理時間を示す。パフォーマンスのパラメーターを調整するときはこれを見ながら効果を確認するほうが、感覚で調整するより確実である。
ShowCollision
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Show Collision", DisplayPriority = 6))
void ShowCollision();
コリジョンのワイヤーフレームの可視化を切り替える。コンソールで r.xgrids.DrawCollision を実行するのと同等である。
使い方の要点:
- 前提としてデータ自体にコリジョンがあり、かつ Component の
bEnableCollisionがオンになっている必要がある。そうでないと何も表示されない。 - キャラクターがすり抜ける、レイキャストが当たらないときはまずこれを開いて、コリジョンボディが実際に読み込まれているかを確認する。
- コリジョンは距離に応じたストリーミング読み込みなので、遠くにワイヤーフレームがないのは正常な挙動であり、
Performance.CollisionLoadMaxDistanceで制御される。
ShowFPS
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Show FPS", DisplayPriority = 7))
void ShowFPS();
フレームレートの表示を切り替える。コンソールで stat fps を実行するのと同等である。Stats と合わせて使い、フレームレートと Splat 数を同時に見る。
Complete Example
実行時に LCC のシーンを 1 つ読み込み、準備できたらレンダリングのパラメーターを設定する。
// MyLCCLoader.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyLCCLoader.generated.h"
UCLASS()
class AMyLCCLoader : public AActor
{
GENERATED_BODY()
public:
/** 読み込むデータのパス。絶対パスまたは Content ディレクトリからの相対パス */
UPROPERTY(EditAnywhere, Category = "MyLCC")
FString ScenePath = TEXT("Tower/Tower.lcc");
protected:
virtual void BeginPlay() override;
private:
void OnLoadCheck();
UPROPERTY()
TObjectPtr<class ALCCActor> LCCActor;
FTimerHandle LoadCheckTimer;
};
// MyLCCLoader.cpp
#include "MyLCCLoader.h"
#include "LCCActor.h"
#include "LCCComponentBase.h"
void AMyLCCLoader::BeginPlay()
{
Super::BeginPlay();
LCCActor = GetWorld()->SpawnActor<ALCCActor>(
ALCCActor::StaticClass(), GetActorTransform());
if (!LCCActor)
{
return;
}
LCCActor->Load(ScenePath);
GetWorld()->GetTimerManager().SetTimer(
LoadCheckTimer, this, &AMyLCCLoader::OnLoadCheck, 0.2f, true);
}
void AMyLCCLoader::OnLoadCheck()
{
ULCCComponentBase* Component = LCCActor ? LCCActor->GetLCCComponent() : nullptr;
if (!Component || !Component->CheckIfLoaded())
{
return;
}
GetWorld()->GetTimerManager().ClearTimer(LoadCheckTimer);
// メタ情報が準備できたので、必要に応じて設定する
Component->SetRenderMode(ERenderMode::Splatting);
Component->SetSplatScale(0.9f);
Component->SetMaxDistance(200); // 最大 200 メートルまでレンダリングする
Component->SetMaxSplatNum(1500); // 1 フレーム最大 1500 万個の Splat
Component->SetLCCCollisionEnable(true);
UE_LOG(LogTemp, Log, TEXT("LCC ready, splat number: %d"),
Component->GetSplatNumber());
}
See Also
- ULCCComponentBase:レンダリングとパフォーマンスのパラメーターはすべてここにある
- SOG / SPZ / PLY Actors:3 つの単一ファイル形式の専用 Actor
- ULCCUtilLibrary:読み込み前のパスと形式の検証