ALCCActorBase: Basisklasse der 3DGS-Actors
Basisklasse jedes LCC-Actors, verantwortlich für das Platzieren von 3DGS-Daten im Level. ALCCActor, ALCC2Actor, ASogActor, ASpzActor und APlyActor erben alle von ihr.
| Modul | LCC4UnrealRuntime |
| Header | LCCActorBase.h |
| Basisklasse | AActor |
| Blueprint | Vererbbar (BlueprintType) |
#include "LCCActorBase.h"
Der Actor selbst rendert nicht: Er hält eine ULCCComponentBase und leitet Ladeoperationen an sie weiter. Rendering-Parameter, Farbe, Leistung und Kollision liegen alle an der Component, die über GetLCCComponent geholt wird.
Einschränkung bei der Skalierung: LCC-Actors unterstützen nur eine gleichmäßige Skalierung. Keine Skalierung mit negativen Werten (etwa
(-1, 1, 1)) und keine je Achse unterschiedliche Skalierung (etwa(2, 1, 3)) verwenden, sonst treten Rendering-Fehler auf, die sich meist als einzelne Linie auf dem Bildschirm zeigen.
Eigenschaften
| Eigenschaft | Typ | Zugriff | Beschreibung |
|---|---|---|---|
DefaultSceneRoot | ULCCFocusRootComponent* | Nur lesen | Unsichtbare Root-Komponente. Ihr einziger Zweck ist, dem Editor-Viewport eine kleine feste Bounding Box zu geben, damit das Fokussieren mit F auch in einer riesigen Szene weiter funktioniert. |
LCCComponent | ULCCComponentBase* | Nur lesen | Die Komponente, die die eigentliche Arbeit erledigt. Ihr konkreter Typ wird beim Konstruieren der Unterklasse festgelegt. |
Beide Eigenschaften sind VisibleAnywhere + BlueprintReadOnly: Sie lassen sich weder im Details-Panel noch in Blueprint ersetzen, sondern nur lesen.
Methoden
Load
UFUNCTION(BlueprintCallable, Category = "XGrids")
virtual void Load(const FString& String) const;
Lädt 3DGS-Daten aus einem Pfad. Das ist der Haupteinstiegspunkt, um eine Szene zur Laufzeit zu laden.
Parameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
String | const FString& | Pfad der Datendatei. Absolute Pfade (D:/Data/Tower/Tower.lcc) und relative Pfade werden beide unterstützt. Relative Pfade werden gegen das Verzeichnis Content des Projekts aufgelöst, Tower/Tower.lcc zeigt also auf Content/Tower/Tower.lcc. |
Die akzeptierte Pfadform unterscheidet sich je Unterklasse:
| Actor | Was zu übergeben ist |
|---|---|
ALCCActor | Pfad einer LCC1-Datei .lcc. Der Dateiname ist nicht festgelegt, und data.bin und index.bin müssen im gleichen Verzeichnis liegen |
ALCC2Actor | Pfad einer LCC2-Datei .lcc2. Der Dateiname ist nicht festgelegt |
ASogActor | Pfad einer .sog-Datei |
ASpzActor | Pfad einer .spz-Datei |
APlyActor | Pfad einer .ply-Datei; eine andere Erweiterung als .ply wird unmittelbar abgewiesen |
Hinweis: Die Dateinamen von
.lccund.lcc2werden von der Datenerzeugung festgelegt, also nicht davon ausgehen, dass die Datei immermeta.lccheißt. Das Format an der Erweiterung bestimmen oder mit ULCCUtilLibrary::DetermineFileFormat.
Hinweise zur Verwendung:
- Die Methode ist
const, weil die Zustandsänderung innerhalb vonLCCComponenterfolgt und der Actor selbst nicht verändert wird. - Das Laden ist asynchron. Beim Rückkehren des Aufrufs sind die Daten noch nicht bereit, und die aktuelle Version erfordert ein Abfragen mit
GetLCCComponent()->CheckIfLoaded(). Ein Callback bei Abschluss des Ladens wird in einer späteren Version bereitgestellt, danach ist das Abfragen nicht mehr nötig. - Gibt
CheckIfLoaded()truezurück, bedeutet das nur, dass Metadaten und Index aufgebaut sind und Parameter sicher gelesen und konfiguriert werden können; Splat-Daten strömen weiterhin je Ansicht nach und das Bild füllt sich weiter auf. - Um einen Pfad im Level ohne Code vorzugeben,
DefaultLoadPathan der Component im Details-Panel setzen; er wird zur Laufzeit automatisch geladen. - Das Übergeben eines leeren Pfads entspricht dem Entladen der aktuellen Daten.
- Stimmt der übergebene Pfad mit dem aktuell geladenen Pfad überein, kehrt der Aufruf sofort zurück und es wird nichts neu geladen.
- Bei einem zweifelhaften Pfad diesen zuerst mit ULCCUtilLibrary::CheckLCCValid prüfen, damit ein Ladefehler nicht nur als Log-Meldung endet.
C++-Beispiel:
#include "LCCActor.h"
#include "LCCComponentBase.h"
void AMyGameMode::SpawnLCCScene()
{
// Den Actor spawnen
ALCCActor* LCCActor = GetWorld()->SpawnActor<ALCCActor>(
ALCCActor::StaticClass(),
FVector::ZeroVector,
FRotator::ZeroRotator);
if (!LCCActor)
{
return;
}
// Aus einem absoluten Pfad laden
LCCActor->Load(TEXT("D:/Data/Tower/Tower.lcc"));
// Oder relativ zum Verzeichnis Content laden
// LCCActor->Load(TEXT("Tower/Tower.lcc"));
}
Vor dem Arbeiten mit den Daten den Abschluss des Ladens abwarten. Die aktuelle Version hat keinen Callback, Abfragen ist daher die einzige Möglichkeit:
void AMyActor::LoadAndConfigure()
{
LCCActor->Load(TEXT("D:/Data/Tower/Tower.lcc"));
// Alle 0,2 Sekunden die Bereitschaft prüfen
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);
// Metadaten sind bereit, Parameter können sicher konfiguriert werden (Splat-Daten strömen noch nach)
Component->SetRenderMode(ERenderMode::Splatting);
UE_LOG(LogTemp, Log, TEXT("Total splats: %d"), Component->GetSplatNumber());
}
Blueprint als Text:
[Event BeginPlay]
│
▼
[Spawn Actor from Class]
Class = LCCActor
Spawn Transform = (Standard)
│ Return Value ──┐
▼ │
[Load] ◀────────────────┘
Target = (Return Value des vorherigen Schritts)
String = "D:/Data/Tower/Tower.lcc"
UnLoad
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "UnLoad", DisplayPriority = 2))
virtual void UnLoad();
Entlädt die aktuellen Daten und gibt Ressourcen frei, darunter Grafikspeicher-Buffer, Node-Caches und Kollisionskörper.
Hinweise zur Verwendung:
- Mit
CallInEditorerscheint unter der Kategorie Actions des Details-Panels eine Schaltfläche UnLoad, die im Editor direkt angeklickt werden kann. - Nach dem Entladen bleibt der Actor im Level und rendert einfach nichts. Ein erneuter Aufruf von
Loadlädt andere Daten. - Beim Wechsel zwischen großen Szenen
UnLoadvorLoadaufrufen, damit nicht zwei Datensätze gleichzeitig Grafikspeicher belegen. - Ein manueller Aufruf in
EndPlayist nicht erforderlich; die Component räumt sich beim Zerstören selbst auf.
C++-Beispiel für einen Szenenwechsel:
void AMyManager::SwitchScene(const FString& NewPath)
{
// Zuerst die alten Daten freigeben, damit sich die Grafikspeicher-Spitzen nicht summieren
LCCActor->UnLoad();
LCCActor->Load(NewPath);
}
Refresh
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayPriority = 3))
virtual void Refresh();
Lädt die aktuellen Daten neu. Intern läuft UnLoad() gefolgt von Load(), die Kosten entsprechen daher einem vollständigen Neuladen und das ist keine leichtgewichtige Operation.
Das Neuladen der „aktuellen“ Daten ist möglich, weil ein erfolgreiches Laden den Pfad auch in DefaultLoadPath schreibt und Refresh diesen Wert liest.
Hinweise zur Verwendung:
- Damit erneut vom Datenträger lesen, nachdem die Datendateien auf dem Datenträger ersetzt wurden.
- Nicht dazu verwenden, das Rendering-Ergebnis neu berechnen zu lassen. Das Ändern einer Eigenschaft über ihren Setter löst automatisch eine Aktualisierung aus; um ein einzelnes Bild anzustoßen,
ForceUpdate()an der Component nutzen, das die leichtgewichtige Option ist. - Nach dem Neuladen erneut die Bereitschaft abwarten, und zuvor an der Component gesetzte Laufzeitparameter müssen möglicherweise erneut gesetzt werden.
- Im Editor erscheint eine passende Schaltfläche unter der Kategorie Actions des Details-Panels.
GetLCCComponent
UFUNCTION(BlueprintCallable, Category = "XGrids")
ULCCComponentBase* GetLCCComponent() const;
Gibt den Zeiger auf die Component innerhalb des Actors zurück. Das ist der Einstiegspunkt zu jeder Rendering-Fähigkeit.
Rückgabewert: ULCCComponentBase*. Unter normalen Bedingungen nicht null, da sie beim Konstruieren des Actors erzeugt wird.
Hinweise zur Verwendung:
- Ein Downcast ist nötig, wenn eine unterklassenspezifische Fähigkeit gebraucht wird.
ALCCActorliefert eineULCCComponent, währendALCC2Actorund die drei Einzeldatei-Actors eineULCC2Componentliefern. - Immer mit
Cast<>casten, niemals mit einem C-Cast.Castgibt bei einem Typ-Mismatchnullptrzurück, was ein frühes Verlassen einfach macht.
C++-Beispiel für das Ändern gemeinsamer Parameter der Basisklasse:
ULCCComponentBase* Component = LCCActor->GetLCCComponent();
if (Component)
{
Component->SetSplatScale(0.8f);
Component->SetGlobalAlpha(1.0f);
}
Downcast, um LCC2-spezifische Parameter zu erreichen:
#include "LCC2Component.h"
ULCC2Component* LCC2Comp = Cast<ULCC2Component>(LCC2Actor->GetLCCComponent());
if (LCC2Comp)
{
LCC2Comp->SetSHBands(2);
LCC2Comp->NormalMode = ELCC2NormalGenerationMode::Hemispherical;
}
Blueprint als Text; das Casten in Blueprint nutzt einen Cast To-Node:
[Get LCC Component]
Target = LCCActor
│ Return Value ──┐
▼ │
[Cast To LCC2Component] ◀┘
Object = (Return Value des vorherigen Schritts)
│ Cast Succeeded
▼
[Set SH Bands]
Target = (Ausgang As LCC2 Component des Cast)
In SH Bands = 2
SelectFile
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Load", DisplayPriority = 1))
virtual void SelectFile();
Öffnet den Dateidialog des Systems und lädt die Auswahl unmittelbar.
Hinweise zur Verwendung:
- Wird im Details-Panel als Schaltfläche Load angezeigt und ist der häufigste Weg, Daten im Editor zu laden.
- Jede Unterklasse überschreibt sie, um die passende Erweiterung zu filtern:
ASogActorlistet nur.sog,ASpzActornur.spz,APlyActornur.ply. - Sie hängt von Dialogfähigkeiten des Editors ab, daher nicht in einer paketierten Laufzeit verwenden; zur Laufzeit stattdessen Load nutzen.
DebugNodeBound
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Debug Node Bound", DisplayPriority = 4))
void DebugNodeBound();
Schaltet die Visualisierung der Octree-Node-Grenzen um und zeichnet die aktuell geladenen Nodes als Drahtgitter-Boxen.
Die Boxfarbe entspricht dem Level des Nodes: Rot, Orange, Gelb, Grün, Blau und Violett in dieser Reihenfolge, wobei Rot das niedrigste Level (höchste Genauigkeit) und Weiß das höchste Level (geringste Genauigkeit) ist.
Hinweise zur Verwendung:
- Damit LOD-Problemen nachgehen. Rote Boxen, die weiterhin in der Ferne gerendert werden, bedeuten, dass
LevelFactorzu klein oderStartLevelzu niedrig gesetzt ist und Leistung verschwendet wird. - Umgekehrt bedeuten kaltfarbige Boxen mit hohem Level in der Nähe, dass Details zu stark unterdrückt werden und das Bild unscharf wirkt.
- Ein erneuter Aufruf schaltet sie aus; es ist ein Umschalter.
- Nur im Editor und in Development-Builds wirksam.
Stats
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayPriority = 5))
void Stats();
Schaltet das Panel der Rendering-Statistiken um, entspricht dem Ausführen von stat XGrids in der Konsole.
Das Panel nennt die aktuell gerenderte Splat-Anzahl, die Anzahl der gerade geladenen Nodes und die in jeder Stufe verbrachte Zeit. Es beim Abstimmen der Leistungsparameter zu beobachten ist verlässlicher als ein Abstimmen nach Gefühl.
ShowCollision
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Show Collision", DisplayPriority = 6))
void ShowCollision();
Schaltet die Drahtgitter-Visualisierung der Kollision um, entspricht dem Ausführen von r.xgrids.DrawCollision in der Konsole.
Hinweise zur Verwendung:
- Sie erfordert, dass die Daten selbst Kollision mitbringen und
bEnableCollisionan der Component aktiviert ist, sonst wird nichts angezeigt. - Zuerst einschalten, wenn ein Charakter durch Geometrie hindurchrutscht oder ein Strahlentest nichts trifft, um zu bestätigen, ob die Kollisionskörper überhaupt geladen wurden.
- Kollision strömt distanzabhängig nach, das Fehlen des Drahtgitters in der Ferne ist daher zu erwarten und wird über
Performance.CollisionLoadMaxDistancegesteuert.
ShowFPS
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Show FPS", DisplayPriority = 7))
void ShowFPS();
Schaltet die Anzeige der Bildrate um, entspricht dem Ausführen von stat fps in der Konsole. Zusammen mit Stats nutzen, um Bildrate und Splat-Anzahl nebeneinander zu beobachten.
Vollständiges Beispiel
Eine LCC-Szene zur Laufzeit laden und die Rendering-Parameter konfigurieren, sobald sie bereit ist:
// MyLCCLoader.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyLCCLoader.generated.h"
UCLASS()
class AMyLCCLoader : public AActor
{
GENERATED_BODY()
public:
/** Zu ladender Datenpfad, absolut oder relativ zum Verzeichnis 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);
// Metadaten sind bereit, nach Bedarf konfigurieren
Component->SetRenderMode(ERenderMode::Splatting);
Component->SetSplatScale(0.9f);
Component->SetMaxDistance(200); // bis 200 Meter rendern
Component->SetMaxSplatNum(1500); // höchstens 15 Millionen Splats pro Bild
Component->SetLCCCollisionEnable(true);
UE_LOG(LogTemp, Log, TEXT("LCC ready, splat number: %d"),
Component->GetSplatNumber());
}
Siehe auch
- ULCCComponentBase: Hier liegen die Rendering- und Leistungsparameter
- SOG- / SPZ- / PLY-Actors: eigene Actors für die drei Einzeldateiformate
- ULCCUtilLibrary: Prüfung von Pfad und Format vor dem Laden