Guía de desarrollo de iluminación en tiempo real
El LCC Unity SDK admite iluminación en tiempo real desde luces puntuales dinámicas y focos. A continuación se usa un ejemplo de una luz puntual que se mueve a lo largo de una trayectoria circular para describir los pasos completos para implementar la iluminación en tiempo real.
Paso 1: Crear la escena y los GameObjects
Crea una escena completamente nueva en Unity. Unity crea Main Camera y Directional Light por defecto.
Configurar Main Camera
Selecciona Main Camera en la ventana Jerarquía y establece sus propiedades en la ventana Inspector como se muestra a continuación.

Establecer las propiedades de Main Camera
Crear LCCManager
Haz clic con el botón derecho en un área vacía de la ventana Jerarquía, selecciona Create Empty en el menú emergente para crear un GameObject vacío, nómbralo LCCManager, normaliza su Transform y añádele el script LCCManager mediante Agregar componente.

Crear el GameObject LCCManager y añadir el script LCCManager
Crear LCCRenderer
Haz clic con el botón derecho en un área vacía de la ventana Jerarquía, selecciona Create Empty para crear un GameObject vacío, nómbralo LCCRenderer y establece su Transform como Rotation.x = -90 y Scale.x = -1.

Crear LCCRenderer y establecer su Transform (Rotation.x = -90, Scale.x = -1)
Nota:
Los ajustes de Transform del GameObject LCCRenderer (Rotation.x = -90, Scale.x = -1) lo alinean con el sistema de coordenadas de los datos LCC. Para más detalles sobre la alineación del sistema de coordenadas, consulta "Sistema de coordenadas de los datos LCC" en Introducción al SDK de Unity.
Paso 2: Escribir un script para enviar las luces
Crea un nuevo script C# llamado Relighting.cs con el siguiente código:
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("Ajustes de la luz puntual")]
public Vector3 pointLightPosition = new Vector3(0, 2, 0);
public Color pointLightColor = Color.red;
public float pointLightIntensity = 2.0f;
public float pointLightRange = 3.0f;
[Header("Ajustes del foco")]
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("Animación")]
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] progreso de carga: {_progress:P1}");
}
private void onComplete()
{
Debug.Log("[Relighting] carga completa, configurando luces");
//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 = luz puntual
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 = foco
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] Error en SetLights: {result}");
}
void OnDisable()
{
// Pasa null para desactivar la iluminación personalizada
m_manager.SetLights(null);
}
}
Nota:
- La iluminación en tiempo real debe enviarse después de que la escena LCC termine de cargarse, por lo que la primera llamada a
ApplyLights()se hace en la devolución de llamadaonComplete.- Este ejemplo actualiza la posición de la luz cada fotograma en
Updatepara animar la luz puntual moviéndose a lo largo de una trayectoria circular.- El tipo del campo de luz es
Unity.Mathematics.float3, que requiereusing Unity.Mathematics;.colorsolo tiene tres componentes RGB y no tiene alfa.
Paso 3: Adjuntar el script y establecer la ruta de datos
- Adjunta el script
Relighting.csal GameObject LCCManager en la ventana Jerarquía. - En la ventana Inspector, arrastra el GameObject LCCManager a la propiedad Manager del script.
- Rellena la ruta del archivo LCC en la propiedad File Path del script.
- Las demás propiedades de luz puntual, foco y animación pueden configurarse libremente.

Adjuntar el script Relighting y establecer sus propiedades en el Inspector
En este ejemplo, se crean una luz puntual y un foco, y la luz puntual se mueve a lo largo de una trayectoria circular para demostrar el efecto de iluminación en tiempo real.
Paso 4: Ejecutar
Haz clic en el botón Play de la ventana Game para ver el efecto de iluminación en tiempo real en la escena.

Efecto de iluminación en tiempo real en la escena 3DGS tras la ejecución
Peculiaridades de la iluminación 3DGS
La iluminación en 3DGS difiere mucho de la iluminación tradicional de modelos de malla. El efecto de iluminación en 3DGS se escribe directamente en el color RGB, lo que significa que la iluminación queda «horneada» en los componentes de color renderizados. Por lo tanto, si un modelo 3DGS se capturó en un día soleado con sombras duras muy marcadas, la re-iluminación no puede eliminar esas sombras ya horneadas.
Además, el rango de color durante el renderizado es [0, 1]. Si refuerzas directamente la iluminación sin ningún procesamiento, se producirá sobreexposición. Para evitar la sobreexposición, normalmente oscureces primero la escena 3DGS antes de re-iluminarla.
En el SDK, la intensidad de iluminación puede ajustarse mediante LCCManager.SetLightIntensity(float _intensity):
- El parámetro de entrada
_intensityva de[0, 1]. - Esta función afecta al efecto de iluminación general: cuanto más intensa sea la luz configurada, más oscura se empuja la escena 3DGS.
- El valor por defecto es
0.5.
Consejo:
El cálculo de iluminación es una operación relativamente costosa. El SDK admite un máximo de 50 luces dinámicas (luces puntuales y focos combinados). Cuando se supera el límite,
SetLightsdevuelve-1y no surte efecto.
Pasos clave
Los pasos clave para añadir iluminación en tiempo real a una escena 3DGS:
- Completa la configuración previa de
SetPlatformType/SwitchRenderPass/SetMainCameray carga la escena LCC medianteGetRender+Load. - Después de que la escena termine de cargarse (en la devolución de llamada
onComplete), construye la listaPointLightDatay llama aSetLightspara enviar las luces. - Cuando se necesite animación, actualiza los parámetros de luz en
Updatey vuelve a llamar aSetLights. - Si se produce sobreexposición, usa
SetLightIntensitypara oscurecer primero la escena antes de re-iluminar. - Para desactivar la iluminación en tiempo real, pasa
nullo una lista vacía aSetLights.
API de iluminación en tiempo real
El LCC Unity SDK proporciona las siguientes dos API de iluminación en tiempo real a través de LCCManager. Ambas deben llamarse después de que la escena LCC termine de cargarse (es decir, en la devolución de llamada onComplete).
SetLights
// Valor de retorno: int → 0 = éxito, -1 = superado el límite máximo de recuento
public int SetLights(List<PointLightData> lights)
Establece la lista personalizada de luces puntuales. Pasar null o una lista vacía desactiva la iluminación personalizada.
| Parámetro | Tipo | Descripción |
|---|---|---|
lights | List<PointLightData> | Lista de luces (hasta 50 luces puntuales y focos combinados) |
Ejemplo de uso:
using Unity.Mathematics; // float3
var lights = new List<PointLightData>();
lights.Add(new PointLightData {
position = new float3(0, 5, 0),
lightType = 0, // 0=luz puntual, 1=foco
color = new float3(1, 1, 1),
intensity = 2f,
range = 10f
});
m_manager.SetLights(lights);
Notas:
- El tipo del campo es
Unity.Mathematics.float3, noVector4;colorno tiene componente alfa. lightType:0= luz puntual (ignoradirection/spotAngle),1= foco (requieredirection/spotAngle).- El recuento máximo es 50 (luces puntuales y focos combinados); devuelve
-1cuando se supera. - Pasar
nullo una lista vacía desactiva la iluminación personalizada. - Cuando está activada, se habilita la keyword de shader
_USERLIGHT. - La estructura de datos se llama PointLightData porque UnityEngine ya define LightData, para evitar ambigüedad.
SetLightIntensity
// Valor de retorno: void
public void SetLightIntensity(float intensity)
Establece la intensidad de iluminación global, utilizada para oscurecer la escena 3DGS antes de re-iluminar y evitar la sobreexposición.
| Parámetro | Tipo | Descripción |
|---|---|---|
intensity | float | Intensidad de iluminación, en el rango [0, 1] |
Ejemplo de uso:
m_manager.SetLightIntensity(0.5f);
Notas:
- El valor por defecto es
0.5. - Rango
[0, 1]; los valores fuera del rango se limitan automáticamente. - Cuanto mayor es el valor, más oscura se empuja la escena 3DGS en general.
Estructura de datos PointLightData
public struct PointLightData {
public float3 position; // posición en el mundo
public int lightType; // 0=luz puntual, 1=foco
public float3 color; // color rgb (sin componente alfa)
public float intensity; // intensidad de la luz
public float3 direction; // dirección del foco (se ignora para luces puntuales)
public float range; // alcance de la luz
public float spotAngle; // ángulo del cono del foco (grados, se ignora para luces puntuales)
public float3 pad; // relleno de alineación, no requiere asignación
}
| Campo | Tipo | Descripción |
|---|---|---|
position | float3 | Posición de la luz en el mundo |
lightType | int | 0 = luz puntual, 1 = foco |
color | float3 | Color RGB (sin componente alfa) |
intensity | float | Intensidad de la luz |
direction | float3 | Dirección del foco, se ignora para luces puntuales |
range | float | Alcance de la luz |
spotAngle | float | Ángulo del cono del foco (grados), se ignora para luces puntuales |
pad | float3 | Relleno de alineación, no requiere asignación |