调色开发指南
LCC Unity SDK 支持对 3DGS 场景进行高亮、裁剪、调色等编辑操作。本文介绍调色相关操作:通过 2D 投影纹理、3D 几何体或二者混合的方式圈选区域,对选中区域调整亮度、饱和度、对比度,支持正选、反选等操作。
注意:
当前调色功能仅是运行时的显示效果,不会对原始数据文件产生任何修改,也不支持将编辑结果保存导出。如果需要调色、裁剪并保存数据,请使用其域创新(XGrids)LCC Editor 软件工具处理。
如果不希望修改数据,也可以将操作记录下来,下次在数据加载完成后重放操作(执行设置)。
前置条件
通过 SDK 对场景进行调色,需要满足以下条件:
- 在加载数据之前进入编辑状态。 SDK 默认处于浏览状态(View),该状态能提供最佳性能,正常浏览时建议保持。要进行调色等编辑操作,需在
Load数据之前通过SetEditorMode(true)切换到编辑状态。该方法只在加载所有数据之前调用才有效。 - 在数据加载完成后再执行调色操作。 调色接口需要在场景数据完全加载后调用。
步骤 1:搭建场景
在场景中准备好调色所需的游戏对象:
- Main Camera:场景相机,2D 调色会用到它的视图与投影矩阵。
- LCCManager:空游戏对象,Transform 归一,添加
LCCManager脚本。 - LCCRenderer:空游戏对象,Transform 设置为 Rotation.x = -90、Scale.x = -1(与 LCC 数据坐标系对齐),用于挂载后面编写的
Tone脚本。 - 3D 选区几何体(可选):用于 3D 调色的辅助对象,示例中准备了一个 Cube(
Box1),移动、缩放它即可控制 3D 调色选区的位置和大小。
注意:
渲染相机、LCCManager、LCCRenderer 游戏对象(GameObject)相关设置请参照PC 快速开发入门指南、工程设置优化指南 相关章节。
步骤 2:了解数据结构
调色使用 ToneMix 数据结构,可同时描述 2D 纹理选区和 3D 几何体选区,并携带调色参数。用到的枚举和结构体如下。
public enum SelectMode { normal, invert, clip } // 正常选区、反选、实时裁剪
public enum OperationMode { normal, erase } // 正常选区、擦除选区
public enum ShapeType { box, sphere } // 3D Box 选区、3D Sphere 选区
public enum EditType { Edit2D, Edit3D } // 2D 编辑、3D 编辑
// 调色选区
public struct ToneMix
{
public EditType editType; // 编辑类型(必填,决定使用 2D 还是 3D 字段)
public Texture2D texture; // 2D 蒙版纹理(Edit2D 使用)
public Matrix4x4 mv; // 相机视图矩阵(Edit2D 使用)
public Matrix4x4 mvp; // 相机视图投影矩阵(Edit2D 使用)
public ShapeType type; // 几何体类型(Edit3D 使用)
public Matrix4x4 invMat; // 几何体逆变换矩阵(Edit3D 使用)
public OperationMode operation; // 操作类型(Edit3D 使用)
public SelectMode mode; // 选择模式(必填)
public float brightness; // 亮度,范围 [0, 3],默认 1.0
public float saturation; // 饱和度,范围 [0, 3],默认 1.0
public float contrast; // 对比度,范围 [0, 3],默认 1.0
public int lutid; // LUT 表索引(预留),0 表示不使用
}
关于调色列表,有三点需要注意:
- 列表是有序的。 无论 2D 还是 3D,列表中的条目按顺序依次生效,请确保添加顺序符合预期。
- 反选(invert)必须携带调色数据。 这是调色与高亮、裁剪最关键的不同之处——高亮、裁剪的反选是纯指令,可不关联数据;而调色的反选条目除了
mode = SelectMode.invert,还必须设置brightness、saturation、contrast,用于指定选区之外区域的调色效果。 - 单个列表的条目数量上限为 255。 超出会返回错误码。
步骤 3:了解调色 API
调色相关接口都由 LCCManager 提供,包含一个 SetTone 方法和一个退出方法。
SetTone
// 返回值:int
// 0:执行成功
// 1:列表为 null 或元素个数为 0
// 2:列表元素超出最大值 255
public int SetTone(List<ToneMix> _Mix)
对选定区域进行调色处理,支持亮度、饱和度、对比度调整。2D 纹理条目与 3D 几何体条目可在同一个列表中混合使用。
QuitToneMode
// 返回值:void
public void QuitToneMode()
退出调色模式,恢复场景原始色彩。
提示:
切换调色参数或清除当前调色时,先调用
QuitToneMode()再设置新的调色。
步骤 4:2D 蒙版纹理规范
2D 调色通过一张蒙版纹理来描述选区,可支持四边形、三角形、笔刷、套索等各种圈选方式——在纹理上把对应像素标记为选中值即可。使用 2D 操作时应锁定相机,在固定视角下标识纹理。纹理和像素值有如下约定:
- 纹理规格固定为 1024 × 1024,
R8单通道,不生成 Mipmap,使用点滤波(FilterMode.Point),采样夹断(TextureWrapMode.Clamp)。 - 像素值约定:
| 像素值 | 含义 |
|---|---|
128 | 默认(未选中) |
240 | 选中 |
180 | 减选(擦除已选区域) |
0 | 裁剪 |
在调色场景下,通常只用到 128(默认)和 240(选中)两个值。
步骤 5:编写脚本
新建一个 C# 脚本,命名为 Tone.cs。先完成基础框架:在 Start 中进入编辑状态并加载数据,加载完成后置位加载标记,供后续调色方法判断。
using LCCCore;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Tone : MonoBehaviour
{
public LCCManager m_manager;
public string m_FilePath;
public GameObject m_Box1;
public Slider m_brightness;
public Slider m_saturation;
public Slider m_contrast;
private LCCCore.Renderer m_renderer;
private Camera m_camera;
private bool m_isLoaded = false;
void Start()
{
m_camera = Camera.main;
m_manager.SetPlatformType(PlatformType.PC);
// 进入编辑状态,必须在 Load 之前调用
m_manager.SetEditorMode(true);
m_renderer = m_manager.GetRender(this.transform);
if (m_renderer == null)
Debug.LogError("GetRender failed, check if the manager is set correctly and the file path is valid.");
m_renderer.Load(m_FilePath, onLoadProgress, onLoadCallback);
}
private void onLoadProgress(float value)
{
Debug.Log($"loading progress: {value}");
}
private void onLoadCallback()
{
Debug.Log("data loaded !!!");
m_isLoaded = true;
}
// 调色方法见下文
}
注意:
SetEditorMode(true)必须在Load之前调用才有效;而SetTone必须在数据加载完成(onLoadCallback回调触发)之后调用。m_brightness、m_saturation、m_contrast三个 Slider 用于在运行时动态调整调色参数,可按需使用。
步骤 6:挂载脚本并设置属性
- 将
Tone.cs脚本挂载到 LCCRenderer 游戏对象上。 - 在 Inspector 窗口中,将 LCCManager 游戏对象拖动到脚本的 Manager 属性上。
- 在 File Path 属性中填写 LCC 文件的路径地址。
- 将场景中的
Box1拖动到脚本的 Box1 属性上,将三个 Slider 分别拖动到 Brightness、Saturation、Contrast 属性上,用于 3D 调色与运行时参数调整。

在 Inspector 中设置 Tone 脚本的属性
步骤 7:调色操作示例
将下面的方法补充到 Tone 类中,并在运行、数据加载完成后调用对应方法。
正常调色
构造一张 R8 蒙版纹理,把要调色的像素标记为 240、其余标记为 128,再用相机矩阵构造 ToneMix,设置 brightness、saturation、contrast 后加入列表。
public void onTone()
{
// 纹理尺寸固定 1024*1024,其它属性保持与示例一致
Texture2D _texture = new Texture2D(1024, 1024, TextureFormat.R8, false);
_texture.filterMode = FilterMode.Point;
_texture.wrapMode = TextureWrapMode.Clamp;
int _count = 1024 * 1024;
int _half = _count / 2;
byte[] _values = new byte[_count];
for (int i = 0; i < _count; i++)
{
if (i < _half)
_values[i] = 128; // 128 表示默认,240 表示选中,0 表示裁剪
else
_values[i] = 240;
}
_texture.SetPixelData(_values, 0);
List<ToneMix> _tMixs = new List<ToneMix>();
ToneMix _tmix01 = new ToneMix();
_tmix01.editType = EditType.Edit2D;
_tmix01.mv = m_camera.worldToCameraMatrix * this.transform.localToWorldMatrix;
_tmix01.texture = _texture;
_tmix01.mode = SelectMode.normal;
_tmix01.mvp = GL.GetGPUProjectionMatrix(m_camera.projectionMatrix, true) * m_camera.worldToCameraMatrix * this.transform.localToWorldMatrix;
_tmix01.brightness = 2.0f;
_tmix01.saturation = 2.0f;
_tmix01.contrast = 0.4f;
_tMixs.Add(_tmix01);
m_manager.SetTone(_tMixs);
}
代码解释 : 构建了一张纹理蒙板,将屏幕上半区域选中(屏幕以左下角为原点),对选中区域应用亮度 2.0、饱和度 2.0、对比度 0.4 的调色,示例效果如下。
在实际使用时,可使用矩形框、三角形、笔刷、套索等各种圈选工具对蒙板对应位置进行选择,也可通过 Slider 动态传入 brightness、saturation、contrast 的值。

正常调色效果
反选调色
调色的反选与高亮、裁剪不同:反选条目除了设置 mode = SelectMode.invert,还必须携带调色数据(brightness、saturation、contrast),用于指定选区之外区域的调色效果。在上面正常调色的基础上,追加一个反选条目即可。
public void onToneInvert()
{
// 纹理尺寸固定 1024*1024,其它属性保持与示例一致
Texture2D _texture = new Texture2D(1024, 1024, TextureFormat.R8, false);
_texture.filterMode = FilterMode.Point;
_texture.wrapMode = TextureWrapMode.Clamp;
int _count = 1024 * 1024;
int _half = _count / 2;
byte[] _values = new byte[_count];
for (int i = 0; i < _count; i++)
{
if (i < _half)
_values[i] = 128; // 128 表示默认,240 表示选中,0 表示裁剪
else
_values[i] = 240;
}
_texture.SetPixelData(_values, 0);
List<ToneMix> _tMixs = new List<ToneMix>();
// 正常选区调色
ToneMix _tmix01 = new ToneMix();
_tmix01.editType = EditType.Edit2D;
_tmix01.mv = m_camera.worldToCameraMatrix * this.transform.localToWorldMatrix;
_tmix01.texture = _texture;
_tmix01.mode = SelectMode.normal;
_tmix01.mvp = GL.GetGPUProjectionMatrix(m_camera.projectionMatrix, true) * m_camera.worldToCameraMatrix * this.transform.localToWorldMatrix;
_tmix01.brightness = 2.0f;
_tmix01.saturation = 2.0f;
_tmix01.contrast = 0.4f;
_tMixs.Add(_tmix01);
// 反选:必须携带调色数据(brightness/saturation/contrast),不是纯指令
ToneMix _tmix02 = new ToneMix();
_tmix02.editType = EditType.Edit2D;
_tmix02.mode = SelectMode.invert;
_tmix02.brightness = 0.5f;
_tmix02.saturation = 0.5f;
_tmix02.contrast = 2.0f;
_tMixs.Add(_tmix02);
m_manager.SetTone(_tMixs);
}
代码解释 : 在正常调色的基础上追加了一个反选条目,为选区之外的区域应用亮度 0.5、饱和度 0.5、对比度 2.0 的调色。这样选区内外可应用不同的调色参数,示例效果如下。

反选调色效果
注意:
高亮、裁剪的反选是纯指令,追加一个
mode = SelectMode.invert的条目即可,无需其它数据;而调色的反选条目必须同时设置brightness、saturation、contrast,否则反选区域会使用默认值(1.0),达不到预期效果。
步骤 8:退出调色
调用 QuitToneMode() 即可清除当前调色,恢复场景原始色彩。
public void onToneClear()
{
m_manager.QuitToneMode();
}
关键步骤
对 3DGS 场景进行调色的关键步骤:
- 在
Load数据之前调用SetEditorMode(true)进入编辑状态。 - 在数据加载完成后(
onLoadCallback回调触发 或者通过按钮/事件触发)再调用SetTone。 - 通过
ToneMix的brightness、saturation、contrast(范围[0, 3],默认1.0)控制调色效果,并保证调色列表的添加顺序符合预期。 - 2D 蒙版纹理固定为 1024 × 1024、
R8单通道,按约定填充像素值(128默认、240选中)。 - 调色的反选(
SelectMode.invert)必须携带brightness、saturation、contrast数据,这是与高亮、裁剪反选的关键差异。 - 需要清除或切换调色时,先调用
QuitToneMode()。