ALCCActorBase: базовый класс Actor 3DGS
Базовый класс всех Actor LCC, отвечающий за размещение данных 3DGS в уровне. От него наследуются ALCCActor, ALCC2Actor, ASogActor, ASpzActor и APlyActor.
| Модуль | LCC4UnrealRuntime |
| Заголовочный файл | LCCActorBase.h |
| Родительский класс | AActor |
| Blueprint | Наследуемый (BlueprintType) |
#include "LCCActorBase.h"
Сам Actor не выполняет рендеринг: он содержит ULCCComponentBase и перенаправляет туда операции загрузки. Параметры рендеринга, цвет, производительность и коллизии находятся на Component, который получают через GetLCCComponent.
Ограничение масштабирования: Actor семейства LCC поддерживают только равномерное масштабирование. Не используй масштаб с отрицательными значениями (например
(-1, 1, 1)) или разный масштаб по осям (например(2, 1, 3)), иначе возникнут ошибки рендеринга, которые обычно выглядят как одна линия на экране.
Свойства
| Свойство | Тип | Доступ | Описание |
|---|---|---|---|
DefaultSceneRoot | ULCCFocusRootComponent* | Только чтение | Невидимый корневой компонент. Единственная его цель — дать вьюпорту редактора небольшой фиксированный габаритный бокс, чтобы фокусировка по F не переставала работать из-за огромной сцены. |
LCCComponent | ULCCComponentBase* | Только чтение | Компонент, который выполняет реальную работу. Его конкретный тип определяется при конструировании подкласса. |
Оба свойства помечены VisibleAnywhere + BlueprintReadOnly: их нельзя заменить ни в панели Details, ни в Blueprint, только прочитать.
Методы
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 | Путь к файлу .lcc формата LCC1. Имя файла не фиксировано, и в том же каталоге обязательно должны быть 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 продолжают подгружаться потоково по текущему ракурсу, и изображение продолжает дополняться. - Чтобы задать путь в уровне без кода, укажи
DefaultLoadPathу Component в панели Details; он загрузится автоматически во время выполнения. - Передача пустого пути равносильна выгрузке текущих данных.
- Если переданный путь совпадает с уже загруженным, вызов сразу возвращается и повторная загрузка не выполняется.
- При сомнительном пути сначала проверь его через ULCCUtilLibrary::CheckLCCValid, чтобы ошибка загрузки не осталась только записью в журнале.
Пример на 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"));
}
Перед работой с данными дождись завершения загрузки. В текущей версии обратного вызова нет, поэтому опрос — единственный способ:
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 в виде текста:
[Event BeginPlay]
│
▼
[Spawn Actor from Class]
Class = LCCActor
Spawn Transform = (default)
│ Return Value ──┐
▼ │
[Load] ◀────────────────┘
Target = (Return Value from the previous step)
String = "D:/Data/Tower/Tower.lcc"
UnLoad
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayName = "UnLoad", DisplayPriority = 2))
virtual void UnLoad();
Выгружает текущие данные и освобождает ресурсы, включая буферы в видеопамяти, кэши узлов и тела коллизий.
Замечания по применению:
- Из-за
CallInEditorв категории Actions панели Details появляется кнопка UnLoad, которую можно нажать прямо в редакторе. - После выгрузки Actor остаётся в уровне и просто ничего не отображает. Повторный вызов
Loadзагрузит другие данные. - При переключении между большими сценами вызывай
UnLoadпередLoad, чтобы два набора данных не занимали видеопамять одновременно. - Вызывать вручную в
EndPlayне нужно; Component очищает себя сам при уничтожении.
Пример на C++ для смены сцены:
void AMyManager::SwitchScene(const FString& NewPath)
{
// Release the old data first so that peak video memory usage does not add up
LCCActor->UnLoad();
LCCActor->Load(NewPath);
}
Refresh
UFUNCTION(BlueprintCallable, CallInEditor, Category = "Actions",
meta = (DisplayPriority = 3))
virtual void Refresh();
Перезагружает текущие данные. Внутри выполняется UnLoad() с последующим Load(), поэтому стоимость равна полной перезагрузке, и это не легковесная операция.
Перезагрузка «текущих» данных возможна потому, что при успешной загрузке путь также записывается в DefaultLoadPath, и Refresh читает это значение.
Замечания по применению:
- Используй, чтобы повторно прочитать данные с диска после того, как файлы данных на диске были заменены.
- Не используй для того, чтобы пересчитать результат рендеринга. Изменение свойства через его сеттер автоматически вызывает обновление; чтобы протолкнуть один кадр, используй
ForceUpdate()у Component — это лёгкий вариант. - После перезагрузки снова дождись готовности, а параметры времени выполнения, ранее заданные у Component, возможно, потребуется задать заново.
- В редакторе соответствующая кнопка появляется в категории Actions панели Details.
GetLCCComponent
UFUNCTION(BlueprintCallable, Category = "XGrids")
ULCCComponentBase* GetLCCComponent() const;
Возвращает указатель на Component внутри Actor. Это точка входа ко всем возможностям рендеринга.
Возвращаемое значение: ULCCComponentBase*. В обычных условиях не равен null, так как создаётся при конструировании Actor.
Замечания по применению:
- Приведение вниз нужно, когда требуется возможность, специфичная для подкласса.
ALCCActorвозвращаетULCCComponent, аALCC2Actorи три 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 from the previous step)
│ Cast Succeeded
▼
[Set SH Bands]
Target = (As LCC2 Component output of the Cast)
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();
Переключает визуализацию границ узлов октодерева и рисует текущие загруженные узлы каркасными боксами.
Цвет бокса соответствует уровню узла: красный, оранжевый, жёлтый, зелёный, синий и фиолетовый в этом порядке, где красный — самый низкий уровень (наибольшая детализация), а белый — самый высокий уровень (наименьшая детализация).
Замечания по применению:
- Используй для разбора проблем с LOD. Красные боксы, которые продолжают отображаться в отдалении, означают, что
LevelFactorслишком мал илиStartLevelзадан слишком низко, и производительность расходуется напрасно. - И наоборот, боксы холодных цветов с высоким уровнем вблизи означают, что детализация подавлена слишком сильно и изображение выглядит размытым.
- Повторный вызов отключает визуализацию; это переключатель.
- Работает только в редакторе и в сборках Development.
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 рядом.
Полный пример
Загрузка сцены LCC во время выполнения и настройка параметров рендеринга после её готовности:
// 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());
}
Смотрите также
- ULCCComponentBase: здесь находятся параметры рендеринга и производительности
- Actor SOG / SPZ / PLY: отдельные Actor для трёх форматов одиночных файлов
- ULCCUtilLibrary: проверка пути и формата перед загрузкой