SOG / SPZ / PLY Actors:單文件 3DGS 加載
ASogActor、ASpzActor、APlyActor 三個 Actor 分別對應 .sog、.spz、.ply 三種格式,用於加載單個 3DGS 文件,不需要 LCC 目錄結構。它們都繼承 ALCCActorBase。
| 模塊 | LCC4UnrealRuntime |
| 頭文件 | SogActor.h、SpzActor.h、PlyActor.h |
| 父類 | ALCCActorBase |
| 內部 Component | ULCC2Component |
#include "SogActor.h"
#include "SpzActor.h"
#include "PlyActor.h"
三者內部都通過構造虛擬的 FLCC2MetaInfo 復用完整的 LCC2 渲染管線。也就是說,LCC2 的能力對這三種格式同樣可用,包括球諧階數控制、光照法線模式、裁剪剖切、顏色調整。同理,LCC2 管線的限制也一併繼承,比如多視口接口不生效。
Supported Formats
| Actor | 擴展名 | 適用場景 |
|---|---|---|
ASogActor | .sog | 壓縮格式,體積小,加載快 |
ASpzActor | .spz | 壓縮格式 |
APlyActor | .ply | 通用點雲 / 3DGS 交換格式,多數訓練工具的原生輸出 |
各格式的支持範圍見介紹 - 支持格式。
Comparison with LCC Directory Formats
.sog / .spz / .ply | LCC / LCC2 目錄 | |
|---|---|---|
| 文件組織 | 一個文件 | 元信息文件 + 多個數據分塊 |
| LOD 分層 | 無 | 有,按距離流式加載 |
| 適用規模 | 中小場景 | 大場景 |
| 碰撞數據 | 無 | 可有 |
| 分發便利性 | 高,單個文件 | 需要保持目錄完整 |
選擇依據:數據量不大、想快速驗證效果、需要單文件分發時用這三種格式。大場景要靠 LOD 控性能,必須用 LCC / LCC2 目錄格式。
Methods
三個 Actor 的公開接口全部繼承自 ALCCActorBase,僅重寫了下列方法。
SelectFile
// ASogActor
virtual void SelectFile() override; // 對話框只列 .sog
// ASpzActor
virtual void SelectFile() override; // 對話框只列 .spz
// APlyActor
virtual void SelectFile() override; // 對話框只列 .ply
彈出文件選擇對話框,各自過濾對應擴展名。細節面板上顯示為 Load 按鈕。
僅編輯器可用,打包後的運行時請用 Load。
Load(僅 APlyActor 重寫)
// APlyActor
virtual void Load(const FString& String) const override;
加載 .ply 文件。擴展名不是 .ply 的路徑會被直接拒絕,不會嘗試解析。
ASogActor 與 ASpzActor 沒有重寫 Load,使用基類實現。
Examples
加載單個 .sog 文件
#include "SogActor.h"
#include "LCC2Component.h"
void AMyLoader::LoadSogFile()
{
ASogActor* SogActor = GetWorld()->SpawnActor<ASogActor>(
ASogActor::StaticClass(), FVector::ZeroVector, FRotator::ZeroRotator);
if (!SogActor)
{
return;
}
SogActor->Load(TEXT("D:/Data/scene.sog"));
// 內部是 ULCC2Component,LCC2 的能力都能用
ULCC2Component* Comp = Cast<ULCC2Component>(SogActor->GetLCCComponent());
if (Comp)
{
Comp->SetSHBands(2);
Comp->SetSplatScale(0.9f);
}
}
按擴展名自動選擇 Actor
每種格式各有專用 Actor,實際項目裏通常需要按擴展名分發。
注意不要依賴 DetermineFileFormat 來做這件事,它只識別 .lcc、.splats、.las、.ply,對 .lcc2、.sog、.spz 一律返回 None。直接判斷擴展名更可靠:
#include "Tools/LCCUtilLibrary.h"
#include "LCCActor.h"
#include "LCC2Actor.h"
#include "SogActor.h"
#include "SpzActor.h"
#include "PlyActor.h"
ALCCActorBase* AMyLoader::LoadAnyFormat(const FString& Path)
{
if (!ULCCUtilLibrary::CheckPathValid(Path))
{
UE_LOG(LogTemp, Error, TEXT("Path does not exist: %s"), *Path);
return nullptr;
}
const FString Ext = FPaths::GetExtension(Path).ToLower();
UClass* ActorClass = nullptr;
if (Ext == TEXT("lcc")) ActorClass = ALCCActor::StaticClass();
else if (Ext == TEXT("lcc2")) ActorClass = ALCC2Actor::StaticClass();
else if (Ext == TEXT("sog")) ActorClass = ASogActor::StaticClass();
else if (Ext == TEXT("spz")) ActorClass = ASpzActor::StaticClass();
else if (Ext == TEXT("ply")) ActorClass = APlyActor::StaticClass();
if (!ActorClass)
{
UE_LOG(LogTemp, Error, TEXT("Unsupported format: %s"), *Path);
return nullptr;
}
ALCCActorBase* Actor = GetWorld()->SpawnActor<ALCCActorBase>(
ActorClass, FVector::ZeroVector, FRotator::ZeroRotator);
if (Actor)
{
Actor->Load(Path);
}
return Actor;
}
藍圖裏沒有直接取擴展名的節點,可以用字符串判斷:
[Custom Event: LoadAnyFormat]
Path (String)
│
▼
[Check Path Valid]
Path = Path
│ Return Value ──┐
▼ │
[Branch] ◀───────────────┘
│ True
▼
[Ends With]
Source String = Path
In Suffix = ".sog"
Search Case = Ignore Case
│ Return Value ──┐
▼ │
[Branch] ◀───────────────┘
│ True
▼
[Spawn Actor from Class]
Class = SogActor
│ Return Value ──┐
▼ │
[Load] ◀─────────────────┘
Target = (Return Value)
String = Path
(False 分支繼續用 Ends With 判斷 ".spz"、".ply"、".lcc2"、".lcc")
Notes
- 這三種格式沒有 LOD 分層。加載時構造的是單層單節點的樹(總層數為 1、根節點無子節點),因此
StartLevel、EndLevel、LevelFactor這些 LOD 參數雖然仍會被讀取,但沒有可供選擇的層級,實際不產生效果。控制性能主要靠MaxSplatNum與SplatScale。 - 這三種格式不帶碰撞數據,替代方案見碰撞 - 單文件格式的替代方案。
- 數據量大的文件會一次性全部加載,顯存佔用恆定,不隨視角變化。加載上限與計算方式見渲染 - 單文件格式的加載上限。
- 走的是 LCC2 渲染管線,因此基類上的多視口接口不適用。
- 三者構造時都把 Component 的
bUseMipFilter設為false(基類默認true),並把 Actor 旋轉設為(0, 0, 90)。 .ply有多種子格式,插件支持的是含 3DGS 屬性的變體。普通幾何網格.ply加載會失敗。
See Also
- ALCCActorBase:繼承來的全部接口
- ULCC2Component:這三個 Actor 內部使用的組件
- ULCCUtilLibrary:格式識別與路徑校驗