ALCCActorBase: clase base de los Actors 3DGS
Clase base de todos los Actors LCC, responsable de colocar los datos 3DGS en el nivel. ALCCActor, ALCC2Actor, ASogActor, ASpzActor y APlyActor heredan todos de ella.
| Módulo | LCC4UnrealRuntime |
| Cabecera | LCCActorBase.h |
| Clase padre | AActor |
| Blueprint | Heredable (BlueprintType) |
#include "LCCActorBase.h"
El Actor en sí no renderiza nada: contiene un ULCCComponentBase y le reenvía las operaciones de carga. Los parámetros de renderizado, el color, el rendimiento y la colisión residen todos en el Component, que se obtiene mediante GetLCCComponent.
Limitación de escalado: los Actors LCC solo admiten el escalado uniforme. No usar escalas con valores negativos (como
(-1, 1, 1)) ni escalas que difieran por eje (como(2, 1, 3)), ya que aparecen artefactos de renderizado, normalmente en forma de una única línea en pantalla.
Propiedades
| Propiedad | Tipo | Acceso | Descripción |
|---|---|---|---|
DefaultSceneRoot | ULCCFocusRootComponent* | Solo lectura | Componente raíz invisible. Su única finalidad es dar al viewport del editor una caja delimitadora pequeña y fija, para que pulsar F para enfocar siga funcionando incluso en una escena enorme. |
LCCComponent | ULCCComponentBase* | Solo lectura | El componente que hace el trabajo real. Su tipo concreto se decide al construir la subclase. |
Ambas propiedades son VisibleAnywhere + BlueprintReadOnly: no se pueden sustituir en el panel Details ni en Blueprint, solo leer.
Métodos
Load
UFUNCTION(BlueprintCallable, Category = "XGrids")
virtual void Load(const FString& String) const;
Carga datos 3DGS desde una ruta. Es el punto de entrada principal para cargar una escena en tiempo de ejecución.
Parámetros:
| Parámetro | Tipo | Descripción |
|---|---|---|
String | const FString& | Ruta del archivo de datos. Se admiten tanto rutas absolutas (D:/Data/Tower/Tower.lcc) como rutas relativas. Las rutas relativas se resuelven respecto al directorio Content del proyecto, así que Tower/Tower.lcc apunta a Content/Tower/Tower.lcc. |
La forma de ruta aceptada difiere según la subclase:
| Actor | Qué pasarle |
|---|---|
ALCCActor | Ruta de un archivo .lcc de LCC1. El nombre del archivo no es fijo, y data.bin e index.bin deben existir en el mismo directorio |
ALCC2Actor | Ruta de un archivo .lcc2 de LCC2. El nombre del archivo no es fijo |
ASogActor | Ruta de un archivo .sog |
ASpzActor | Ruta de un archivo .spz |
APlyActor | Ruta de un archivo .ply; una extensión distinta de .ply se rechaza directamente |
Nota: los nombres de los archivos
.lccy.lcc2los decide quien produce los datos, así que no conviene suponer que el archivo siempre se llamameta.lcc. Determinar el formato a partir de la extensión, o con ULCCUtilLibrary::DetermineFileFormat.
Notas de uso:
- El método es
const, porque el cambio de estado ocurre dentro deLCCComponenty el Actor en sí no se modifica. - La carga es asíncrona. Los datos no están listos cuando la llamada retorna, y la versión actual requiere consultarlo periódicamente con
GetLCCComponent()->CheckIfLoaded(). Una versión posterior proporcionará una llamada de retorno de finalización de la carga, tras lo cual la consulta periódica dejará de ser necesaria. - Que
CheckIfLoaded()devuelvatruesolo significa que los metadatos y el índice están establecidos y que se pueden leer y configurar parámetros con seguridad; los datos de splats siguen transmitiéndose según la vista y la imagen se sigue completando. - Para preestablecer una ruta en el nivel sin escribir código, establecer
DefaultLoadPathen el Component desde el panel Details y se carga automáticamente en tiempo de ejecución. - Pasar una ruta vacía equivale a descargar los datos actuales.
- Cuando la ruta que se pasa coincide con la ruta cargada actualmente, la llamada retorna de inmediato y no se recarga nada.
- Para una ruta dudosa, validarla primero con ULCCUtilLibrary::CheckLCCValid para que un fallo de carga no acabe siendo solo un mensaje de log.
Ejemplo en C++:
#include "LCCActor.h"
#include "LCCComponentBase.h"
void AMyGameMode::SpawnLCCScene()
{
// generar el Actor
ALCCActor* LCCActor = GetWorld()->SpawnActor<ALCCActor>(
ALCCActor::StaticClass(),
FVector::ZeroVector,
FRotator::ZeroRotator);
if (!LCCActor)
{
return;
}
// cargar desde una ruta absoluta
LCCActor->Load(TEXT("D:/Data/Tower/Tower.lcc"));
// o cargar de forma relativa al directorio Content
// LCCActor->Load(TEXT("Tower/Tower.lcc"));
}
Esperar a que la carga termine antes de operar con los datos. La versión actual no tiene llamada de retorno, así que la consulta periódica es la única opción:
void AMyActor::LoadAndConfigure()
{
LCCActor->Load(TEXT("D:/Data/Tower/Tower.lcc"));
// comprobar la disponibilidad cada 0,2 segundos
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);
// los metadatos están listos, los parámetros se pueden configurar con seguridad (los datos de splats siguen transmitiéndose)
Component->SetRenderMode(ERenderMode::Splatting);
UE_LOG(LogTemp, Log, TEXT("Total splats: %d"), Component->GetSplatNumber());
}
Blueprint como texto:
[Event BeginPlay]
│
▼
[Spawn Actor from Class]
Class = LCCActor
Spawn Transform = (predeterminado)
│ Return Value ──┐
▼ │
[Load] ◀────────────────┘
Target = (Return Value del paso anterior)
String = "D:/Data/Tower/Tower.lcc"
UnLoad
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "UnLoad", DisplayPriority = 2))
virtual void UnLoad();
Descarga los datos actuales y libera los recursos, incluidos los buffers de GPU, las cachés de nodos y los cuerpos de colisión.
Notas de uso:
- Con
CallInEditor, aparece un botón UnLoad en la categoría Actions del panel Details y se puede pulsar directamente en el editor. - Después de descargar, el Actor permanece en el nivel y simplemente no renderiza nada. Llamar de nuevo a
Loadcarga otros datos. - Al cambiar entre escenas grandes, llamar a
UnLoadantes deLoadpara que dos conjuntos de datos no ocupen memoria de vídeo a la vez. - No se requiere ninguna llamada manual en
EndPlay; el Component se limpia solo al destruirse.
Ejemplo en C++, cambiando de escena:
void AMyManager::SwitchScene(const FString& NewPath)
{
// liberar primero los datos antiguos, para que los picos de memoria de vídeo no se acumulen
LCCActor->UnLoad();
LCCActor->Load(NewPath);
}
Refresh
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayPriority = 3))
virtual void Refresh();
Recarga los datos actuales. Internamente ejecuta UnLoad() seguido de Load(), así que el coste equivale a una recarga completa y no es una operación ligera.
Recargar los datos «actuales» es posible porque una carga correcta también escribe la ruta en DefaultLoadPath, y Refresh lee ese valor.
Notas de uso:
- Usarlo para volver a leer del disco después de haber sustituido los archivos de datos en el disco.
- No usarlo para que el resultado del renderizado se recalcule. Cambiar una propiedad mediante su Setter provoca una actualización automáticamente; para forzar un solo fotograma, usar
ForceUpdate()en el Component, que es la opción ligera. - Después de recargar, esperar de nuevo la disponibilidad, y puede ser necesario volver a establecer los parámetros de tiempo de ejecución que se hubieran configurado en el Component.
- En el editor aparece un botón correspondiente en la categoría Actions del panel Details.
GetLCCComponent
UFUNCTION(BlueprintCallable, Category = "XGrids")
ULCCComponentBase* GetLCCComponent() const;
Devuelve el puntero al Component que hay dentro del Actor. Es el punto de entrada a todas las capacidades de renderizado.
Valor de retorno: ULCCComponentBase*. No nulo en condiciones normales, ya que se crea al construir el Actor.
Notas de uso:
- Realizar una conversión descendente cuando se necesita una capacidad específica de una subclase.
ALCCActorda unULCCComponent, mientras queALCC2Actory los tres Actors de archivo único dan unULCC2Component. - Realizar siempre la conversión descendente con
Cast<>, nunca con una conversión al estilo de C.Castdevuelvenullptrcuando el tipo no coincide, lo que facilita un retorno temprano.
Ejemplo en C++, cambiando parámetros comunes de la clase base:
ULCCComponentBase* Component = LCCActor->GetLCCComponent();
if (Component)
{
Component->SetSplatScale(0.8f);
Component->SetGlobalAlpha(1.0f);
}
Conversión descendente para acceder a los parámetros específicos de LCC2:
#include "LCC2Component.h"
ULCC2Component* LCC2Comp = Cast<ULCC2Component>(LCC2Actor->GetLCCComponent());
if (LCC2Comp)
{
LCC2Comp->SetSHBands(2);
LCC2Comp->NormalMode = ELCC2NormalGenerationMode::Hemispherical;
}
Blueprint como texto; la conversión en Blueprint usa un nodo Cast To:
[Get LCC Component]
Target = LCCActor
│ Return Value ──┐
▼ │
[Cast To LCC2Component] ◀┘
Object = (Return Value del paso anterior)
│ Cast Succeeded
▼
[Set SH Bands]
Target = (salida As LCC2 Component del Cast)
In SH Bands = 2
SelectFile
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Load", DisplayPriority = 1))
virtual void SelectFile();
Abre el diálogo de archivos del sistema y carga la selección de inmediato.
Notas de uso:
- Se muestra como un botón Load en el panel Details, la forma más habitual de cargar datos en el editor.
- Todas las subclases lo sobrescriben para filtrar la extensión correspondiente:
ASogActorsolo lista.sog,ASpzActorsolo.spz,APlyActorsolo.ply. - Depende de las capacidades de diálogo del editor, así que no se debe usar en un tiempo de ejecución empaquetado; usar Load en tiempo de ejecución.
DebugNodeBound
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Debug Node Bound", DisplayPriority = 4))
void DebugNodeBound();
Alterna la visualización de los límites de los nodos del octree, dibujando los nodos cargados actualmente como cajas de estructura alámbrica.
El color de la caja corresponde al Level del nodo: rojo, naranja, amarillo, verde, azul y morado por orden, donde el rojo es el Level más bajo (la precisión más alta) y el blanco es el Level más alto (la precisión más baja).
Notas de uso:
- Usarlo para investigar problemas de LOD. Las cajas rojas que siguen renderizándose a lo lejos indican que
LevelFactores demasiado pequeño o queStartLevelestá establecido en un valor demasiado bajo, y se desperdicia rendimiento. - A la inversa, las cajas de colores fríos y de Level alto de cerca indican que la precisión se ha reducido en exceso y la imagen parece borrosa.
- Llamarlo de nuevo para desactivarlo; es un interruptor.
- Solo surte efecto en el editor y en las compilaciones de desarrollo.
Stats
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayPriority = 5))
void Stats();
Alterna el panel de estadísticas de renderizado, equivalente a ejecutar stat XGrids en la consola.
El panel indica el número de splats renderizados actualmente, el número de nodos que se están cargando y el tiempo empleado en cada etapa. Observarlo mientras se ajustan los parámetros de rendimiento es más fiable que ajustar a ojo.
ShowCollision
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Show Collision", DisplayPriority = 6))
void ShowCollision();
Alterna la visualización de la estructura alámbrica de la colisión, equivalente a ejecutar r.xgrids.DrawCollision en la consola.
Notas de uso:
- Requiere que los propios datos incluyan colisión y que
bEnableCollisionesté activado en el Component; de lo contrario no se muestra nada. - Activarlo primero cuando un personaje atraviesa la geometría o una prueba de rayos no impacta, para confirmar si los cuerpos de colisión se cargaron realmente.
- La colisión se transmite por distancia, así que la ausencia de estructura alámbrica a lo lejos es lo esperado y lo controla
Performance.CollisionLoadMaxDistance.
ShowFPS
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "Show FPS", DisplayPriority = 7))
void ShowFPS();
Alterna la visualización de la tasa de fotogramas, equivalente a ejecutar stat fps en la consola. Usarlo junto con Stats para observar a la vez la tasa de fotogramas y el número de splats.
Ejemplo completo
Cargar una escena LCC en tiempo de ejecución y configurar los parámetros de renderizado una vez que está lista:
// MyLCCLoader.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyLCCLoader.generated.h"
UCLASS()
class AMyLCCLoader : public AActor
{
GENERATED_BODY()
public:
/** Ruta de datos a cargar, absoluta o relativa al directorio 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);
// los metadatos están listos, configurar según convenga
Component->SetRenderMode(ERenderMode::Splatting);
Component->SetSplatScale(0.9f);
Component->SetMaxDistance(200); // renderizar hasta 200 metros
Component->SetMaxSplatNum(1500); // como máximo 15 millones de splats por fotograma
Component->SetLCCCollisionEnable(true);
UE_LOG(LogTemp, Log, TEXT("LCC ready, splat number: %d"),
Component->GetSplatNumber());
}
Véase también
- ULCCComponentBase: aquí residen los parámetros de renderizado y rendimiento
- Actors SOG / SPZ / PLY: Actors dedicados a los tres formatos de archivo único
- ULCCUtilLibrary: validación de rutas y formatos antes de cargar