27 KiB
设置系统模块文档
本文档基于
iflow-engineSDK 真实代码实现,说明设置系统的架构、API 和第三方预设接入方式。
目录
1. 架构概览
设置系统采用分层架构:
┌─────────────────────────────────────────────────────────┐
│ UI 层: Toolbar Setting Button │
│ -> registry.setting.toggle() │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Manager 层: SettingDialogManager │
│ - 管理设置面板生命周期 │
│ - 维护预设列表 │
│ - 编排设置应用流程 │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 组件层: Engine (src/components/engine/index.ts) │
│ - 封装底层引擎设置能力 │
│ - 提供统一 getSettings/setSettings API │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 底层: iflow-engine-base │
│ - 实际 WebGL/Three.js 渲染设置 │
│ - Setting 模块 (shadow, lighting, env, etc.) │
└─────────────────────────────────────────────────────────┘
关键文件
| 文件 | 职责 |
|---|---|
src/managers/setting-dialog-manager.ts |
设置对话框管理器,UI 和预设管理 |
src/components/engine/index.ts |
引擎组件,设置 API 实现 |
src/components/engine/types.ts |
设置相关类型定义 |
src/types/events.ts |
设置相关事件定义 |
src/locales/zh-CN.ts |
设置面板文案国际化 |
2. 核心类型
2.1 EngineSettings - 完整设置
interface EngineSettings {
render: RenderSettings;
display: DisplaySettings;
environment: EnvironmentSettings;
}
interface RenderSettings {
mode: 'simple' | 'balance' | 'advanced'; // 渲染模式
contrast: number; // 对比度 0-100
saturation: number; // 饱和度 0-100
shadowIntensity: number; // 阴影强度 0-100
lightIntensity: number; // 光照强度 0-100
gtaoIntensity: number; // GTAO 强度 0-100
}
interface DisplaySettings {
showEdge: boolean; // 显示边线
edgeOpacity: number; // 边线透明度 0-100
showGrid: boolean; // 显示轴网
showLevel: boolean; // 显示标高
showGround: boolean; // 显示地面
groundId: string; // 地面类型 ID
groundHeight: number; // 地面高度 (米)
}
interface EnvironmentSettings {
type: 'none' | 'hdr' | 'sky'; // 环境类型
hdrId: string; // HDR 背景 ID
hdrIntensity: number; // HDR 强度 0-100
skyPreset: string; // 天空预设
skyParams: SkyParams; // 天空高级参数
skyIntensity: number; // 天空强度 0-100
}
interface SkyParams {
turbidity?: number;
rayleigh?: number;
mieCoefficient?: number;
mieDirectionalG?: number;
elevation?: number;
azimuth?: number;
exposure?: number;
orthoExposureScale?: number;
cloudCoverage?: number;
cloudDensity?: number;
cloudElevation?: number;
showSunDisc?: boolean;
}
2.2 EngineSettingPreset - 预设定义
interface EngineSettingPreset {
id: string; // 唯一标识
presetName: string; // 预设显示名称
isDefault: boolean; // 是否为默认预设
settings: EngineSettings; // 预设包含的设置
readonly?: boolean; // 是否只读
source?: 'sdk-default' | 'external' | 'user'; // 预设来源
allowModify?: boolean; // 是否允许修改(保存/删除),默认 true
}
字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
id |
string |
预设唯一标识 |
presetName |
string |
预设显示名称 |
isDefault |
boolean |
是否为默认预设,打开面板时自动选中 |
settings |
EngineSettings |
预设包含的完整设置 |
readonly |
boolean |
是否只读,只读预设用户无法修改设置值(但仍可保存为新预设) |
source |
'sdk-default' | 'external' | 'user' |
预设来源 |
allowModify |
boolean |
是否允许修改当前预设,false 时隐藏"保存"和"删除"按钮,默认 true |
source 字段说明:
'sdk-default': SDK 内置的默认预设(allowModify: false)'external': 第三方注入的预设'user': 用户自行保存的预设
allowModify 字段说明:
true(默认): 显示所有操作按钮("保存预设"、"存为新预设"、"删除")false: 隐藏"保存当前预设"和"删除"按钮,但保留"另存为新预设"按钮
注意: "另存为新预设"始终可用,因为创建新预设不是在修改当前预设。下拉框宽度始终保持固定。
2.3 设置补丁 (局部更新)
interface EngineSettingsPatch {
render?: Partial<RenderSettings>;
display?: Partial<DisplaySettings>;
environment?: Partial<EnvironmentSettings>;
}
2.4 预设资源列表
interface SettingPresetLists {
ground: PresetListItem[]; // 地面类型列表
hdr: PresetListItem[]; // HDR 背景列表
sky: PresetListItem[]; // 天空预设列表
}
interface PresetListItem {
id: string;
names: string[]; // [中文名, 繁体名, 英文名]
}
3. 设置面板UI
3.1 面板结构
设置对话框宽度 420px,包含以下区域:
┌───────────────────────────────────────────┐
│ 设置 [×] │ ← 标题栏
├───────────────────────────────────────────┤
│ │
│ ▓▓ 渲染设置 ▓▓ │
│ 渲染模式: [性能] [平衡] [效果] │
│ 阴影强度: [══════════════●══] 75 │
│ 光照强度: [════════●═══════] 50 │
│ 对比度: [════════●═══════] 50 (效果模式可见)
│ 饱和度: [════════●═══════] 50 (效果模式可见)
│ GTAO: [════════●═══════] 50 (效果模式可见)
│ │
│ ▓▓ 显示设置 ▓▓ │
│ 边线 [◉] 透明度 [═══●═══] 50 │
│ 轴网 [◉] │
│ 标高 [◉] │
│ 地面 [◉] 类型 [地面一 ▼] 高度 [0] │
│ │
│ ▓▓ 环境背景 ▓▓ │
│ [无] [HDR背景] [天空盒] │
│ HDR: [hdr-001 ▼] 强度 [══●═══] 40 │
│ 或 │
│ 天空: [晴朗 ▼] 强度 [══●═══] 40 │
│ │
├───────────────────────────────────────────┤
│ [撤销修改] │ ← 修改时显示
│ [预设选择 ▼] [🗑] [保存预设] │ ← 底部操作栏
└───────────────────────────────────────────┘
3.2 UI 交互规则
-
渲染模式条件显示:
contrast,saturation,gtaoIntensity仅在advanced模式下显示- 切换模式时面板不抖动,控件平滑显示/隐藏
-
环境类型互斥:
none: 无环境背景hdr: 显示 HDR 选择器和强度滑块sky: 显示天空预设选择器和强度滑块
-
显示设置联动:
- 边线开启后才显示透明度滑块
- 地面开启后才显示地面类型和高度输入
4. API 参考
4.1 SettingDialogManager
文件: src/managers/setting-dialog-manager.ts
生命周期
// 初始化设置管理器
init(): void
// 销毁设置管理器
destroy(): void
对话框控制
// 显示设置对话框
show(): void
// 隐藏设置对话框
hide(): void
// 切换显示状态
toggle(): void
// 获取对话框是否打开
isOpen(): boolean
预设管理
/**
* 设置/注入预设列表
* @param presets 预设数组,会合并到现有预设列表
*/
setPresetList(presets: EngineSettingPreset[]): void
// 获取当前预设列表
getPresetList(): EngineSettingPreset[]
// 获取当前选中的预设
getSelectedPreset(): EngineSettingPreset | null
// 应用指定 ID 的预设
applyPresetById(id: string): Promise<void>
4.2 Engine 组件设置 API
文件: src/components/engine/index.ts
批量设置
/**
* 获取当前完整设置
* @returns 当前 EngineSettings 的深拷贝
*/
getSettings(): EngineSettings
/**
* 应用设置补丁
* @param patch 部分设置,会合并到当前设置
* @returns Promise,设置应用完成后 resolve
*/
setSettings(patch: EngineSettingsPatch): Promise<void>
/**
* 重置为默认设置
* @returns Promise
*/
resetToDefault(): Promise<void>
预设资源
/**
* 获取预设资源列表(地面/HDR/天空)
* @returns 各类资源的可用选项
*/
getPresetLists(): SettingPresetLists
渲染模式
// 获取当前渲染模式
getRenderMode(): 'simple' | 'balance' | 'advanced'
// 设置渲染模式
setRenderMode(mode: 'simple' | 'balance' | 'advanced'): void
光照与渲染
// 环境光强度
setAmbientLightIntensity(intensity: number): void // 0-100
getAmbientLightIntensity(): number
// 对比度
setSceneContrast(contrast: number): void // 0-100
getSceneContrast(): number
// 饱和度
setSceneSaturation(saturation: number): void // 0-100
getSceneSaturation(): number
// 阴影强度
setShadowIntensity(intensity: number): void // 0-100
边线
// 启用边线
activeModelEdge(): void
// 禁用边线
disActiveModelEdge(): void
// 获取边线是否启用
getModelEdgeActive(): boolean
// 设置边线透明度
setEdgeOpacity(opacity: number): void // 0-100
HDR 背景
// 获取 HDR 列表
getHDRBackgroundList(): { name: string; id: string }[]
// 设置 HDR ID
setHDRBackgroundId(id: string): void
// 获取当前 HDR ID
getHDRBackgroundId(): string
// 设置 HDR 可见性
setHDRBackgroundVisibility(visible: boolean): void
// 设置 HDR 强度
setHDRIntensity(intensity: number): void // 0-100
地面
// 获取地面列表
getGroundList(): { name: string; id: string }[]
// 设置地面 ID
setGroundId(id: string): void
// 获取当前地面 ID
getGroundId(): string
// 设置地面高度
setGroundElevation(elevation: number): void // 米
// 获取地面高度
getGroundElevation(): number
// 设置地面可见性
setGroundVisible(visible: boolean): void
天空
// 获取天空预设列表
getSkyPresetList(): { name: string; id: string }[]
// 设置天空预设
setSkyPreset(presetId: string): void
// 设置天空强度
setSkyIntensity(intensity: number): void // 0-100
// 设置天空参数
setSkyParams(params: Partial<SkyParams>): void
4.3 BimEngine 快捷访问
const bimEngine = new BimEngine(container, options);
// 初始化设置管理器
bimEngine.initSetting();
// 访问设置管理器
bimEngine.setting?.show();
bimEngine.setting?.hide();
bimEngine.setting?.toggle();
// 通过引擎组件访问设置 API
bimEngine.engine?.getSettings();
bimEngine.engine?.setSettings({ render: { mode: 'advanced' } });
5. 第三方预设接入
5.1 注入预设
第三方可通过 setPresetList 方法注入自定义预设:
import { BimEngine } from 'iflow-engine';
// 创建引擎
const bimEngine = new BimEngine(container, {
locale: 'zh-CN',
theme: 'dark'
});
// 初始化必要组件
bimEngine.initToolbar();
bimEngine.initButtonGroup();
bimEngine.initDialog();
bimEngine.initEngine();
bimEngine.initSetting(); // 初始化设置管理器
// 注入第三方预设
const externalPresets = [
{
id: 'vendor-indoor',
presetName: '室内展厅',
isDefault: false,
source: 'external', // 标记为外部来源
settings: {
render: {
mode: 'advanced',
contrast: 55,
saturation: 60,
shadowIntensity: 70,
lightIntensity: 80,
gtaoIntensity: 60,
},
display: {
showEdge: true,
edgeOpacity: 40,
showGrid: false,
showLevel: true,
showGround: true,
groundId: 'marble-01',
groundHeight: 0,
},
environment: {
type: 'hdr',
hdrId: 'interior-01',
hdrIntensity: 30,
skyPreset: 'sunrise_clear',
skyParams: {},
skyIntensity: 20,
},
},
},
{
id: 'vendor-outdoor',
presetName: '室外建筑',
isDefault: true, // 设为默认预设
source: 'external',
settings: {
render: {
mode: 'balance',
contrast: 50,
saturation: 50,
shadowIntensity: 50,
lightIntensity: 50,
gtaoIntensity: 50,
},
display: {
showEdge: false,
edgeOpacity: 30,
showGrid: true,
showLevel: false,
showGround: true,
groundId: 'grass-01',
groundHeight: 0,
},
environment: {
type: 'sky',
hdrId: '0',
hdrIntensity: 20,
skyPreset: 'sunny_clear',
skyParams: {
turbidity: 3,
cloudCoverage: 0.2,
},
skyIntensity: 25,
},
},
},
];
bimEngine.setting?.setPresetList(externalPresets);
5.2 预设合并规则
调用 setPresetList 时的处理逻辑:
- 保留内置预设:
__internal-default-preset__始终保留 - 去重:相同
id的预设会被新传入的替换 - 来源标记:建议第三方预设标记
source: 'external' - 默认预设:
- 若传入的预设中有
isDefault: true,则选中该预设 - 若有多个
isDefault: true,取第一个 - 若没有指定默认,选中内置默认预设
- 若传入的预设中有
5.3 禁止修改预设
使用 allowModify: false 可以禁止用户保存或删除某个预设:
bimEngine.setting?.setPresetList([
{
id: 'vendor-locked',
presetName: '供应商锁定预设',
isDefault: false,
source: 'external',
allowModify: false, // ← 禁止修改
settings: {
render: { mode: 'advanced', contrast: 60, ... },
display: { showEdge: true, ... },
environment: { type: 'hdr', hdrId: 'hdr-01', ... }
}
}
]);
效果:
- ❌ 不显示"保存当前预设"按钮(无法覆盖原预设)
- ❌ 不显示删除按钮
- ✅ 保留"另存为新预设"按钮(可基于此预设创建新预设)
- ✅ 预设选择下拉框宽度固定不变
- ✅ 用户仍可修改设置值(如需禁止修改设置值,使用
readonly: true)
适用场景:
- 供应商提供的标准预设,不希望用户覆盖或删除,但允许基于此创建新预设
- 项目规定的固定展示模式
- 内置默认预设(SDK 默认
allowModify: false)
为什么保留"另存为新预设"?
"另存为新预设"是创建一个新的预设,不是在修改当前预设。即使用户不能修改供应商预设,也应该可以基于它创建自己的版本。> 如果你希望完全禁止用户基于此预设创建新预设,需要额外的前端逻辑控制。
5.4 动态更新预设
// 随时可以更新预设列表
bimEngine.setting?.setPresetList([
{
id: 'dynamic-preset',
presetName: '动态预设',
isDefault: false,
source: 'external',
settings: { /* ... */ },
},
]);
// 获取当前预设列表
const presets = bimEngine.setting?.getPresetList();
5.5 完整示例
import { BimEngine } from 'iflow-engine';
import type { EngineSettingPreset } from 'iflow-engine';
class VendorPresetManager {
private engine: BimEngine;
constructor(engine: BimEngine) {
this.engine = engine;
}
// 注册供应商预设
registerVendorPresets() {
const presets: EngineSettingPreset[] = [
this.createReviewPreset(),
this.createPresentationPreset(),
this.createPerformancePreset(),
];
this.engine.setting?.setPresetList(presets);
}
// 评审模式 - 高对比度,显示边线
private createReviewPreset(): EngineSettingPreset {
return {
id: 'vendor-review',
presetName: '评审模式',
isDefault: false,
source: 'external',
settings: {
render: {
mode: 'advanced',
contrast: 70,
saturation: 55,
shadowIntensity: 65,
lightIntensity: 55,
gtaoIntensity: 50,
},
display: {
showEdge: true,
edgeOpacity: 50,
showGrid: true,
showLevel: true,
showGround: true,
groundId: 'grid-01',
groundHeight: 0,
},
environment: {
type: 'hdr',
hdrId: 'studio-01',
hdrIntensity: 35,
skyPreset: 'sunrise_clear',
skyParams: {},
skyIntensity: 20,
},
},
};
}
// 展示模式 - 高饱和度,HDR环境
private createPresentationPreset(): EngineSettingPreset {
return {
id: 'vendor-presentation',
presetName: '展示模式',
isDefault: true, // 设为默认
source: 'external',
settings: {
render: {
mode: 'advanced',
contrast: 55,
saturation: 75,
shadowIntensity: 80,
lightIntensity: 70,
gtaoIntensity: 60,
},
display: {
showEdge: false,
edgeOpacity: 30,
showGrid: false,
showLevel: false,
showGround: true,
groundId: 'pavement-01',
groundHeight: -0.5,
},
environment: {
type: 'hdr',
hdrId: 'outdoor-afternoon',
hdrIntensity: 45,
skyPreset: 'sunset_glow',
skyParams: {},
skyIntensity: 25,
},
},
};
}
// 性能模式 - 低画质,高帧率
private createPerformancePreset(): EngineSettingPreset {
return {
id: 'vendor-performance',
presetName: '性能模式',
isDefault: false,
source: 'external',
settings: {
render: {
mode: 'simple',
contrast: 50,
saturation: 50,
shadowIntensity: 20,
lightIntensity: 50,
gtaoIntensity: 0,
},
display: {
showEdge: false,
edgeOpacity: 30,
showGrid: false,
showLevel: false,
showGround: false,
groundId: '0',
groundHeight: 0,
},
environment: {
type: 'none',
hdrId: '0',
hdrIntensity: 20,
skyPreset: 'sunrise_clear',
skyParams: {},
skyIntensity: 20,
},
},
};
}
}
// 使用
const bimEngine = new BimEngine(container);
bimEngine.initToolbar();
bimEngine.initButtonGroup();
bimEngine.initDialog();
bimEngine.initEngine();
bimEngine.initSetting();
const presetManager = new VendorPresetManager(bimEngine);
presetManager.registerVendorPresets();
// 监听预设变更
bimEngine.on('setting:preset-changed', ({ preset }) => {
console.log(`已切换到: ${preset.presetName}`);
// 可以在这里做自定义逻辑
if (preset.source === 'external') {
console.log('使用第三方预设');
}
});
6. 事件系统
6.1 设置相关事件
文件: src/types/events.ts
// 预设保存事件
'setting:preset-saved': {
preset: EngineSettingPreset; // 被保存的预设
currentSettings: EngineSettings; // 当前完整设置
timestamp: number;
}
// 预设切换事件
'setting:preset-changed': {
preset: EngineSettingPreset; // 切换后的目标预设
timestamp: number;
}
// 预设删除事件
'setting:preset-deleted': EngineSettingPreset; // 被删除的预设
6.2 事件监听示例
const bimEngine = new BimEngine(container);
// 监听预设保存
const offSaved = bimEngine.on('setting:preset-saved', ({ preset, currentSettings, timestamp }) => {
console.log('用户保存预设:', preset.presetName);
console.log('预设来源:', preset.source);
console.log('保存时间:', new Date(timestamp));
// 可以持久化到本地存储或后端
localStorage.setItem(`preset_${preset.id}`, JSON.stringify(preset));
});
// 监听预设切换
const offChanged = bimEngine.on('setting:preset-changed', ({ preset, timestamp }) => {
console.log('预设已切换:', preset.presetName);
// 根据来源做不同处理
switch (preset.source) {
case 'sdk-default':
console.log('使用 SDK 默认预设');
break;
case 'external':
console.log('使用第三方预设');
break;
case 'user':
console.log('使用用户自定义预设');
break;
}
});
// 监听预设删除
const offDeleted = bimEngine.on('setting:preset-deleted', (preset) => {
console.log('预设已删除:', preset.presetName);
// 清理本地存储
localStorage.removeItem(`preset_${preset.id}`);
});
// 取消监听
// offSaved();
// offChanged();
// offDeleted();
6.3 与第三方系统集成
// 示例:将用户保存的预设同步到后端
class PresetSyncService {
constructor(private engine: BimEngine) {
this.setupListeners();
}
private setupListeners() {
// 保存时同步到后端
this.engine.on('setting:preset-saved', async ({ preset }) => {
if (preset.source === 'user') {
await this.saveToServer(preset);
}
});
// 切换时上报埋点
this.engine.on('setting:preset-changed', ({ preset }) => {
this.trackPresetUsage(preset);
});
}
private async saveToServer(preset: EngineSettingPreset) {
try {
await fetch('/api/presets', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(preset),
});
} catch (error) {
console.error('同步预设失败:', error);
}
}
private trackPresetUsage(preset: EngineSettingPreset) {
// 埋点上报
analytics.track('Preset Changed', {
presetId: preset.id,
presetName: preset.presetName,
source: preset.source,
});
}
}
7. 默认值参考
const DEFAULT_SETTINGS: EngineSettings = {
render: {
mode: 'advanced',
contrast: 50,
saturation: 50,
shadowIntensity: 50,
lightIntensity: 50,
gtaoIntensity: 50,
},
display: {
showEdge: false,
edgeOpacity: 30,
showGrid: false,
showLevel: false,
showGround: false,
groundId: '0',
groundHeight: 0,
},
environment: {
type: 'none',
hdrId: '0',
hdrIntensity: 20,
skyPreset: 'sunrise_clear',
skyParams: {},
skyIntensity: 20,
},
};
8. 常见问题
Q1: 如何获取当前生效的设置?
const currentSettings = bimEngine.engine?.getSettings();
console.log(currentSettings.render.mode);
Q2: 如何只修改部分设置?
// 只修改渲染模式,其他保持不变
await bimEngine.engine?.setSettings({
render: { mode: 'simple' }
});
Q3: 如何禁止用户修改(保存/删除)某个预设?
使用 allowModify: false 可以禁止用户覆盖或删除某个预设:
{
id: 'vendor-locked-preset',
presetName: '供应商锁定预设',
source: 'external',
allowModify: false, // 禁止修改当前预设
settings: { ... }
}
效果:
- ❌ 隐藏"保存当前预设"按钮(无法覆盖原预设)
- ❌ 隐藏"删除"按钮
- ✅ 保留"另存为新预设"按钮(可基于此创建新预设)
- ✅ 下拉框宽度保持不变
注意:
allowModify: false时,用户仍可以切换到这个预设- 用户仍可以修改设置值,只是无法保存到当前预设
- 如需完全禁止修改设置值,需配合
readonly: true
Q4: readonly 和 allowModify 有什么区别?
| 字段 | 作用 | 对用户的影响 |
|---|---|---|
readonly |
禁止修改设置值 | 禁用所有设置控件(滑块、开关等) |
allowModify |
禁止覆盖/删除当前预设 | 隐藏"保存当前预设"和"删除"按钮,但保留"另存为新预设" |
内置默认预设(__internal-default-preset__)的 allowModify: false。
Q5: 第三方预设会被用户删除吗?
如果设置了 allowModify: false,用户无法删除该预设。建议第三方预设设置 allowModify: false:
{
id: 'vendor-preset',
presetName: '供应商预设',
source: 'external',
allowModify: false, // 用户不可删除/保存该预设
settings: { ... }
}
Q6: 如何清空所有第三方预设?
// 获取当前列表
const currentList = bimEngine.setting?.getPresetList() || [];
// 过滤掉外部预设
const filteredList = currentList.filter(p => p.source !== 'external');
// 重新设置
bimEngine.setting?.setPresetList(filteredList);
Q7: 设置修改后立即生效吗?
setSettings 返回 Promise,设置应用完成后 resolve:
await bimEngine.engine?.setSettings({
environment: { type: 'hdr', hdrId: 'hdr-01' }
});
// 到这里设置已生效
文档版本: 1.1.0
更新时间: 2026-03-30
适用 SDK 版本: iflow-engine >= 2.2.1