Руководство по разработке освещения в реальном времени
LCC Unity SDK поддерживает освещение в реальном времени от динамических точечных источников света и прожекторов. Ниже на примере точечного источника света, движущегося по круговой траектории, описаны полные шаги по реализации освещения в реальном времени.
Шаг 1: Создайте сцену и GameObject
Создайте совершенно новую сцену в Unity. Unity по умолчанию создаёт Main Camera и Directional Light.
Настройте Main Camera
Выберите Main Camera в окне Hierarchy и задайте его свойства в окне Inspector, как показано ниже.

Настройка свойств Main Camera
Создайте LCCManager
Щёлкните правой кнопкой мыши в пустой области окна Hierarchy, выберите Create Empty во всплывающем меню, чтобы создать пустой GameObject, назовите его LCCManager, нормализуйте его Transform и добавьте к нему скрипт LCCManager через Add Component.

Создание GameObject LCCManager и добавление скрипта LCCManager
Создайте LCCRenderer
Щёлкните правой кнопкой мыши в пустой области окна Hierarchy, выберите Create Empty, чтобы создать пустой GameObject, назовите его LCCRenderer и задайте его Transform значения Rotation.x = -90 и Scale.x = -1.

Создание LCCRenderer и настройка его Transform (Rotation.x = -90, Scale.x = -1)
Примечание:
Настройки Transform GameObject LCCRenderer (Rotation.x = -90, Scale.x = -1) выравнивают его с системой координат данных LCC. Подробнее о выравнивании системы координат см. в разделе «Система координат данных LCC» документа Введение в Unity SDK.
Шаг 2: Напишите скрипт для передачи источников света
Создайте новый скрипт C# с именем Relighting.cs со следующим кодом:
using System.Collections.Generic;
using LCCCore;
using Unity.Mathematics;
using UnityEngine;
public class Relighting : MonoBehaviour
{
public LCCManager m_manager;
public string m_FilePath;
private LCCCore.Renderer m_renderer;
[Header("Настройки точечного источника света")]
public Vector3 pointLightPosition = new Vector3(0, 2, 0);
public Color pointLightColor = Color.red;
public float pointLightIntensity = 2.0f;
public float pointLightRange = 3.0f;
[Header("Настройки прожекторного источника света")]
public Vector3 spotLightPosition = new Vector3(0, 2, -2);
public Vector3 spotLightDirection = new Vector3(0, -1, 0);
public Color spotLightColor = new Color(0.1f, 0.9f, 0.7f);
public float spotLightIntensity = 3.0f;
public float spotLightRange = 20.0f;
public float spotLightAngle = 45.0f;
[Header("Анимация")]
public bool animateLights = true;
public float rotateSpeed = 30.0f;
private List<PointLightData> m_lights = new List<PointLightData>();
private float m_angle;
void Start()
{
m_manager.SetPlatformType(PlatformType.PC);
m_manager.SwitchRenderPass(ActiveRenderMode.SingleRender);
m_manager.SetMainCamera(Camera.main);
m_renderer = m_manager.GetRender(this.transform);
m_renderer.Load(m_FilePath, onProgress, onComplete);
}
private void onProgress(float _progress)
{
Debug.Log($"[Relighting] прогресс загрузки: {_progress:P1}");
}
private void onComplete()
{
Debug.Log("[Relighting] загрузка завершена, настройка источников света");
//m_manager.SetLightIntensity(0.5f);
ApplyLights();
}
void Update()
{
if (!animateLights) return;
m_angle += rotateSpeed * Time.deltaTime;
ApplyLights();
}
private void ApplyLights()
{
m_lights.Clear();
float rad = m_angle * Mathf.Deg2Rad;
float px = pointLightPosition.x + Mathf.Cos(rad) * 3f;
float pz = pointLightPosition.z + Mathf.Sin(rad) * 3f;
// lightType 0 = точечный источник света
m_lights.Add(new PointLightData
{
position = new float3(px, pointLightPosition.y, pz),
lightType = 0,
color = new float3(pointLightColor.r, pointLightColor.g, pointLightColor.b),
intensity = pointLightIntensity,
direction = float3.zero,
range = pointLightRange,
spotAngle = 0f,
pad = float3.zero
});
// lightType 1 = прожекторный источник света
Vector3 dir = spotLightDirection.normalized;
m_lights.Add(new PointLightData
{
position = new float3(spotLightPosition.x, spotLightPosition.y, spotLightPosition.z),
lightType = 1,
color = new float3(spotLightColor.r, spotLightColor.g, spotLightColor.b),
intensity = spotLightIntensity,
direction = new float3(dir.x, dir.y, dir.z),
range = spotLightRange,
spotAngle = spotLightAngle,
pad = float3.zero
});
int result = m_manager.SetLights(m_lights);
if (result != 0)
Debug.LogWarning($"[Relighting] SetLights завершился ошибкой: {result}");
}
void OnDisable()
{
// Передаём null, чтобы отключить пользовательское освещение
m_manager.SetLights(null);
}
}
Примечание:
- Освещение в реальном времени должно передаваться после завершения загрузки LCC-сцены, поэтому первый вызов
ApplyLights()выполняется в обратном вызовеonComplete.- Этот пример каждый кадр в
Updateобновляет положение источника света, чтобы анимировать точечный источник света, движущийся по круговой траектории.- Тип поля источника света —
Unity.Mathematics.float3, что требуетusing Unity.Mathematics;.colorимеет только три компонента RGB и не имеет альфа.
Шаг 3: Прикрепите скрипт и задайте путь к данным
- Прикрепите скрипт
Relighting.csк GameObject LCCManager в окне Hierarchy. - В окне Inspector перетащите GameObject LCCManager на свойство Manager скрипта.
- Заполните путь к файлу LCC в свойстве File Path скрипта.
- Остальные свойства точечного источника света, прожектора и анимации можно настроить свободно.

Прикрепление скрипта Relighting и настройка его свойств в Inspector
В этом примере создаются один точечный источник света и один прожектор, а точечный источник света движется по круговой траектории, демонстрируя эффект освещения в реальном времени.
Шаг 4: Запустите
Нажмите кнопку Play в окне Game, чтобы увидеть эффект освещения в реальном времени в сцене.

Эффект освещения в реальном времени в сцене 3DGS после запуска
Особенности освещения 3DGS
Освещение в 3DGS сильно отличается от традиционного освещения моделей Mesh. Эффект освещения в 3DGS записывается непосредственно в цвет RGB, то есть освещение «запекается» в компоненты отрендеренного цвета. Поэтому если модель 3DGS была захвачена в солнечный день с очень сильными жёсткими тенями, переосвещение не сможет удалить эти уже запечённые тени.
Кроме того, диапазон цвета при рендеринге равен [0, 1]. Если напрямую усилить освещение без какой-либо обработки, возникнет переэкспонирование. Чтобы предотвратить переэкспонирование, обычно сначала затемняют сцену 3DGS, а затем переосвещают её.
В SDK интенсивность освещения можно настроить через LCCManager.SetLightIntensity(float _intensity):
- Входной параметр
_intensityнаходится в диапазоне[0, 1]. - Эта функция влияет на общий эффект освещения: чем сильнее настроенная интенсивность света, тем темнее становится сцена 3DGS.
- Значение по умолчанию —
0.5.
Совет:
Расчёт освещения — относительно дорогостоящая операция. SDK поддерживает максимум 50 динамических источников света (точечных и прожекторных вместе). При превышении лимита
SetLightsвозвращает-1и не даёт эффекта.
Ключевые шаги
Ключевые шаги для добавления освещения в реальном времени в сцену 3DGS:
- Выполните предварительную настройку
SetPlatformType/SwitchRenderPass/SetMainCameraи загрузите LCC-сцену черезGetRender+Load. - После завершения загрузки сцены (в обратном вызове
onComplete) постройте списокPointLightDataи вызовитеSetLightsдля передачи источников света. - При необходимости анимации обновляйте параметры источников света в
Updateи снова вызывайтеSetLights. - Если возникает переэкспонирование, используйте
SetLightIntensity, чтобы сначала затемнить сцену, а затем переосветить её. - Чтобы отключить освещение в реальном времени, передайте
nullили пустой список вSetLights.
API освещения в реальном времени
LCC Unity SDK предоставляет следующие два API освещения в реальном времени через LCCManager. Оба они должны вызываться после завершения загрузки LCC-сцены (то есть в обратном вызове onComplete).
SetLights
// Возвращаемое значение: int → 0 = успех, -1 = превышен максимальный лимит количества
public int SetLights(List<PointLightData> lights)
Задаёт пользовательский список точечных источников света. Передача null или пустого списка отключает пользовательское освещение.
| Параметр | Тип | Описание |
|---|---|---|
lights | List<PointLightData> | Список источников света (до 50 точечных и прожекторных вместе) |
Пример использования:
using Unity.Mathematics; // float3
var lights = new List<PointLightData>();
lights.Add(new PointLightData {
position = new float3(0, 5, 0),
lightType = 0, // 0=точечный источник света, 1=прожекторный источник света
color = new float3(1, 1, 1),
intensity = 2f,
range = 10f
});
m_manager.SetLights(lights);
Примечания:
- Тип поля —
Unity.Mathematics.float3, а неVector4;colorне имеет компонента альфа. lightType:0= точечный источник света (игнорируетdirection/spotAngle),1= прожекторный источник света (требуетdirection/spotAngle).- Максимальное количество — 50 (точечные и прожекторные вместе); при превышении возвращается
-1. - Передача
nullили пустого списка отключает пользовательское освещение. - При включении активируется ключевое слово шейдера
_USERLIGHT. - Структура данных названа PointLightData, потому что UnityEngine уже определяет LightData, во избежание неоднозначности.
SetLightIntensity
// Возвращаемое значение: void
public void SetLightIntensity(float intensity)
Задаёт глобальную интенсивность освещения, используемую для затемнения сцены 3DGS перед переосвещением, чтобы предотвратить переэкспонирование.
| Параметр | Тип | Описание |
|---|---|---|
intensity | float | Интенсивность освещения, в диапазоне [0, 1] |
Пример использования:
m_manager.SetLightIntensity(0.5f);
Примечания:
- Значение по умолчанию —
0.5. - Диапазон
[0, 1]; значения вне диапазона ограничиваются автоматически. - Чем больше значение, тем темнее становится общая сцена 3DGS.
Структура данных PointLightData
public struct PointLightData {
public float3 position; // мировая позиция
public int lightType; // 0=точечный источник света, 1=прожекторный источник света
public float3 color; // цвет RGB (без компонента альфа)
public float intensity; // интенсивность света
public float3 direction; // направление прожектора (игнорируется для точечных источников света)
public float range; // дальность света
public float spotAngle; // угол конуса прожектора (в градусах, игнорируется для точечных источников света)
public float3 pad; // выравнивающее заполнение, назначать не нужно
}
| Поле | Тип | Описание |
|---|---|---|
position | float3 | Мировая позиция источника света |
lightType | int | 0 = точечный источник света, 1 = прожекторный источник света |
color | float3 | Цвет RGB (без компонента альфа) |
intensity | float | Интенсивность света |
direction | float3 | Направление прожектора, игнорируется для точечных источников света |
range | float | Дальность света |
spotAngle | float | Угол конуса прожектора (в градусах), игнорируется для точечных источников света |
pad | float3 | Выравнивающее заполнение, назначать не нужно |