ALCCActorBase: classe base degli Actor 3DGS
Classe base di ogni LCC Actor, responsabile del posizionamento dei dati 3DGS nel livello. ALCCActor, ALCC2Actor, ASogActor, ASpzActor e APlyActor ereditano tutti da essa.
| Modulo | LCC4UnrealRuntime |
| Header | LCCActorBase.h |
| Classe padre | AActor |
| Blueprint | Ereditabile (BlueprintType) |
#include "LCCActorBase.h"
L'Actor stesso non esegue alcun rendering: contiene un ULCCComponentBase e gli inoltra le operazioni di caricamento. Parametri di rendering, colore, prestazioni e collisioni risiedono tutti sul Component, ottenuto attraverso GetLCCComponent.
Limitazione sulla scala: gli LCC Actor supportano solo la scala uniforme. Non usare scale con valori negativi (come
(-1, 1, 1)) né scale diverse per asse (come(2, 1, 3)), altrimenti compaiono artefatti di rendering, che si manifestano di solito come una linea sullo schermo.
Proprietà
| Proprietà | Tipo | Accesso | Descrizione |
|---|---|---|---|
DefaultSceneRoot | ULCCFocusRootComponent* | Sola lettura | Component radice invisibile. Il suo unico scopo è dare al viewport dell'editor un piccolo bounding box fisso, così che premere F per centrare la vista continui a funzionare anche in una scena enorme. |
LCCComponent | ULCCComponentBase* | Sola lettura | Il component che svolge il lavoro effettivo. Il suo tipo concreto viene deciso alla costruzione della sottoclasse. |
Entrambe le proprietà sono VisibleAnywhere + BlueprintReadOnly: non possono essere sostituite nel pannello Details né in Blueprint, solo lette.
Metodi
Load
UFUNCTION(BlueprintCallable, Category = "XGrids")
virtual void Load(const FString& String) const;
Carica dati 3DGS da un percorso. È il punto di ingresso principale per caricare una scena a runtime.
Parametri:
| Parametro | Tipo | Descrizione |
|---|---|---|
String | const FString& | Percorso del file di dati. Sono supportati sia percorsi assoluti (D:/Data/Tower/Tower.lcc) sia percorsi relativi. I percorsi relativi vengono risolti rispetto alla directory Content del progetto, quindi Tower/Tower.lcc punta a Content/Tower/Tower.lcc. |
La forma di percorso accettata varia per sottoclasse:
| Actor | Cosa passare |
|---|---|
ALCCActor | Percorso di un file .lcc LCC1. Il nome del file non è fisso, e data.bin e index.bin devono esistere nella stessa directory |
ALCC2Actor | Percorso di un file .lcc2 LCC2. Il nome del file non è fisso |
ASogActor | Percorso di un file .sog |
ASpzActor | Percorso di un file .spz |
APlyActor | Percorso di un file .ply; un'estensione diversa da .ply viene rifiutata immediatamente |
Nota: i nomi dei file
.lcce.lcc2sono decisi da chi produce i dati, quindi non dare per scontato che il file si chiami sempremeta.lcc. Determinare il formato dall'estensione, oppure con ULCCUtilLibrary::DetermineFileFormat.
Note d'uso:
- Il metodo è
const, perché il cambio di stato avviene dentroLCCComponente l'Actor stesso non viene modificato. - Il caricamento è asincrono. I dati non sono pronti al ritorno della chiamata, e la versione corrente richiede il polling con
GetLCCComponent()->CheckIfLoaded(). Una callback di completamento del caricamento verrà fornita in una versione successiva, dopo la quale il polling non sarà più necessario. CheckIfLoaded()che restituiscetruesignifica solo che le metainformazioni e l'indice sono stabiliti e che i parametri possono essere letti e configurati in sicurezza; i dati splat continuano ad arrivare in streaming per vista e l'immagine continua a riempirsi.- Per predisporre un percorso nel livello senza scrivere codice, impostare
DefaultLoadPathsul Component nel pannello Details, e il caricamento avviene automaticamente a runtime. - Passare un percorso vuoto equivale a scaricare i dati correnti.
- Quando il percorso passato corrisponde al percorso attualmente caricato, la chiamata ritorna subito e nulla viene ricaricato.
- Per un percorso dubbio, validarlo prima con ULCCUtilLibrary::CheckLCCValid così che un errore di caricamento non finisca solo in un messaggio di log.
Esempio C++:
#include "LCCActor.h"
#include "LCCComponentBase.h"
void AMyGameMode::SpawnLCCScene()
{
// spawn the Actor
ALCCActor* LCCActor = GetWorld()->SpawnActor<ALCCActor>(
ALCCActor::StaticClass(),
FVector::ZeroVector,
FRotator::ZeroRotator);
if (!LCCActor)
{
return;
}
// load from an absolute path
LCCActor->Load(TEXT("D:/Data/Tower/Tower.lcc"));
// or load relative to the Content directory
// LCCActor->Load(TEXT("Tower/Tower.lcc"));
}
Attendere il completamento del caricamento prima di operare sui dati. La versione corrente non ha callback, quindi il polling è l'unica opzione:
void AMyActor::LoadAndConfigure()
{
LCCActor->Load(TEXT("D:/Data/Tower/Tower.lcc"));
// check readiness every 0.2 seconds
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);
// metadata is ready, parameters can be configured safely (splat data is still streaming)
Component->SetRenderMode(ERenderMode::Splatting);
UE_LOG(LogTemp, Log, TEXT("Total splats: %d"), Component->GetSplatNumber());
}
Blueprint come testo:
[Event BeginPlay]
│
▼
[Spawn Actor from Class]
Class = LCCActor
Spawn Transform = (predefinito)
│ Return Value ──┐
▼ │
[Load] ◀────────────────┘
Target = (Return Value del passo precedente)
String = "D:/Data/Tower/Tower.lcc"
UnLoad
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "UnLoad", DisplayPriority = 2))
virtual void UnLoad();
Scarica i dati correnti e rilascia le risorse, inclusi i buffer GPU, le cache dei nodi e i corpi di collisione.
Note d'uso:
- Con
CallInEditor, un pulsante UnLoad compare nella categoria Actions del pannello Details e può essere premuto direttamente nell'editor. - Dopo lo scaricamento, l'Actor resta nel livello e semplicemente non renderizza nulla. Chiamare di nuovo
Loadcarica altri dati. - Quando si passa tra scene di grandi dimensioni, chiamare
UnLoadprima diLoadcosì che due dataset non occupino contemporaneamente la memoria video. - Non serve alcuna chiamata manuale in
EndPlay; il Component si ripulisce da sé quando viene distrutto.
Esempio C++, cambio di scena:
void AMyManager::SwitchScene(const FString& NewPath)
{
// release the old data first, so the video memory peaks do not stack
LCCActor->UnLoad();
LCCActor->Load(NewPath);
}
Refresh
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayPriority = 3))
virtual void Refresh();
Ricarica i dati correnti. Internamente esegue UnLoad() seguito da Load(), quindi il costo corrisponde a un ricaricamento completo e non è un'operazione leggera.
Ricaricare i dati «correnti» è possibile perché un caricamento riuscito scrive anche il percorso in DefaultLoadPath, e Refresh legge quel valore.
Note d'uso:
- Usarlo per rileggere da disco dopo che i file di dati su disco sono stati sostituiti.
- Non usarlo per far ricalcolare il risultato del rendering. Modificare una proprietà tramite il suo Setter innesca automaticamente un aggiornamento; per forzare un singolo fotogramma, usare
ForceUpdate()sul Component, che è l'opzione leggera. - Dopo il ricaricamento, attendere di nuovo che i dati siano pronti, e i parametri a runtime impostati in precedenza sul Component possono richiedere di essere impostati di nuovo.
- Un pulsante corrispondente compare nella categoria Actions del pannello Details nell'editor.
GetLCCComponent
UFUNCTION(BlueprintCallable, Category = "XGrids")
ULCCComponentBase* GetLCCComponent() const;
Restituisce il puntatore al Component contenuto nell'Actor. È il punto di ingresso a ogni funzionalità di rendering.
Valore di ritorno: ULCCComponentBase*. Non nullo in condizioni normali, poiché viene creato alla costruzione dell'Actor.
Note d'uso:
- Eseguire il downcast quando serve una funzionalità specifica di una sottoclasse.
ALCCActorfornisce unULCCComponent, mentreALCC2Actore i tre Actor a file singolo forniscono unULCC2Component. - Eseguire sempre il downcast con
Cast<>, mai con un cast in stile C.Castrestituiscenullptrin caso di tipo non corrispondente, cosa che rende facile un ritorno anticipato.
Esempio C++, modifica dei parametri comuni della classe base:
ULCCComponentBase* Component = LCCActor->GetLCCComponent();
if (Component)
{
Component->SetSplatScale(0.8f);
Component->SetGlobalAlpha(1.0f);
}
Downcast per raggiungere i parametri specifici di LCC2:
#include "LCC2Component.h"
ULCC2Component* LCC2Comp = Cast<ULCC2Component>(LCC2Actor->GetLCCComponent());
if (LCC2Comp)
{
LCC2Comp->SetSHBands(2);
LCC2Comp->NormalMode = ELCC2NormalGenerationMode::Hemispherical;
}
Blueprint come testo; il cast in Blueprint usa un nodo Cast To:
[Get LCC Component]
Target = LCCActor
│ Return Value ──┐
▼ │
[Cast To LCC2Component] ◀┘
Object = (Return Value del passo precedente)
│ Cast Succeeded
▼
[Set SH Bands]
Target = (uscita As LCC2 Component del Cast)
In SH Bands = 2
SelectFile
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Load", DisplayPriority = 1))
virtual void SelectFile();
Apre la finestra di dialogo file di sistema e carica immediatamente la selezione.
Note d'uso:
- Mostrato come pulsante Load nel pannello Details, è il modo più comune di caricare i dati nell'editor.
- Ogni sottoclasse lo sovrascrive per filtrare l'estensione corrispondente:
ASogActorelenca solo.sog,ASpzActorsolo.spz,APlyActorsolo.ply. - Dipende dalle funzionalità di dialogo dell'editor, quindi non usarlo in un runtime pacchettizzato; a runtime usare invece Load.
DebugNodeBound
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Debug Node Bound", DisplayPriority = 4))
void DebugNodeBound();
Attiva e disattiva la visualizzazione dei confini dei nodi dell'octree, disegnando i nodi attualmente caricati come scatole wireframe.
Il colore della scatola corrisponde al Level del nodo: rosso, arancione, giallo, verde, blu e viola in ordine, dove il rosso è il Level più basso (dettaglio più alto) e il bianco è il Level più alto (dettaglio più basso).
Note d'uso:
- Usarlo per indagare i problemi di LOD. Scatole rosse ancora renderizzate a grande distanza significano che
LevelFactorè troppo piccolo oppure cheStartLevelè impostato troppo basso, e le prestazioni vengono sprecate. - Al contrario, scatole di Level alto in colori freddi da vicino significano che il dettaglio è soppresso troppo aggressivamente e l'immagine appare sfocata.
- Chiamarlo di nuovo per disattivarlo; è un interruttore a due stati.
- Efficace solo nell'editor e nelle build di sviluppo.
Stats
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayPriority = 5))
void Stats();
Attiva e disattiva il pannello delle statistiche di rendering, equivalente all'esecuzione di stat XGrids nella console.
Il pannello riporta il numero di splat attualmente renderizzati, il numero di nodi in caricamento e il tempo speso in ogni fase. Osservarlo durante la regolazione dei parametri di prestazione è più affidabile del regolare a sensazione.
ShowCollision
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Show Collision", DisplayPriority = 6))
void ShowCollision();
Attiva e disattiva la visualizzazione wireframe delle collisioni, equivalente all'esecuzione di r.xgrids.DrawCollision nella console.
Note d'uso:
- Richiede che i dati stessi contengano collisione e che
bEnableCollisionsul Component sia abilitato, altrimenti non viene mostrato nulla. - Attivarla per prima cosa quando un personaggio attraversa la geometria o un test dei raggi non colpisce, per verificare se i corpi di collisione siano stati caricati.
- La collisione arriva in streaming per distanza, quindi l'assenza di wireframe a grande distanza è prevista ed è controllata da
Performance.CollisionLoadMaxDistance.
ShowFPS
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Show FPS", DisplayPriority = 7))
void ShowFPS();
Attiva e disattiva la visualizzazione della frequenza dei fotogrammi, equivalente all'esecuzione di stat fps nella console. Usarlo insieme a Stats per osservare fianco a fianco la frequenza dei fotogrammi e il numero di splat.
Esempio completo
Caricare una scena LCC a runtime e configurare i parametri di rendering una volta che è pronta:
// MyLCCLoader.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyLCCLoader.generated.h"
UCLASS()
class AMyLCCLoader : public AActor
{
GENERATED_BODY()
public:
/** Data path to load, absolute or relative to the Content directory */
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);
// metadata is ready, configure as needed
Component->SetRenderMode(ERenderMode::Splatting);
Component->SetSplatScale(0.9f);
Component->SetMaxDistance(200); // render up to 200 meters
Component->SetMaxSplatNum(1500); // at most 15 million splats per frame
Component->SetLCCCollisionEnable(true);
UE_LOG(LogTemp, Log, TEXT("LCC ready, splat number: %d"),
Component->GetSplatNumber());
}
Vedere anche
- ULCCComponentBase: i parametri di rendering e prestazione risiedono qui
- Actor SOG / SPZ / PLY: Actor dedicati ai tre formati a file singolo
- ULCCUtilLibrary: validazione di percorso e formato prima del caricamento