唯杰地图 logo唯杰地图
VJMAP
EN

fx-quality

vjmapext/references/perf/fx-quality.md 6.6 KB189 行
原文

本文回答:fx.setQuality / getQuality + getMetrics() + 事件 render / empty / overflow / compact。

一、三档画质

fx.setQuality('lite');        // 中低端机
fx.setQuality('standard');    // 默认
fx.setQuality('cinematic');   // 演示机 / 大屏

fx.getQuality();              // 当前档
档 shader 宏 QUALITY 含义
lite 1 简化迭代、降 octave、丢 bloom 抗锯齿
standard 2 默认平衡
cinematic 3 完整迭代、平滑边缘、最大噪声层数

所有 12 点 / 5 线 / Shadertoy 都在 shader 编译期读 #if QUALITY >= 2 这类宏分支(宏名是 QUALITY,不是 FX_QUALITY)→ 预设作者可根据档位写分支。setQuality 对非法值直接 throw(lite|standard|cinematic 之外报错)。

二、切换耗时

首次切档:用到的 program 重编译一次(< 30 ms); 切回旧档:从 programCache 读缓存(≈ 0 ms)。

console.time('lite');
fx.setQuality('lite');
console.timeEnd('lite');          // 8~30 ms 首次

console.time('lite-again');
fx.setQuality('lite');            // 无变化,直接返回
console.timeEnd('lite-again');    // < 1 ms

三、渲染分桶 bucket

fx.addPoint('halo', { cad: [x, y], size: 50, bucket: 'topmost' });
bucket z-order
below 底图 下方;适合地下管线烟雾
above(默认) 底图 + CAD 实体之上
topmost 所有图层之上;告警高亮 / 教学引导

默认只有 above 一个渲染层;第一次用 below / topmost 自动创建子层。批量数组里每个元素的 bucket 独立生效。

四、批量 API

API 用途 性能
addPoint(preset, opts) 单点 / 偶发 只写 CPU 影子缓冲,下一帧 draw 时合并成一次 bufferSubData
addPoints(preset, list) 一次加多点 内部循环 addPoint,按 bucket 分组——与同步循环 addPoint 性能相当,胜在写法简洁
replaceAllPoints(preset, list) 周期整数据替换 清空该预设默认 above 桶后 addPoints;忽略各项 bucket、不处理 triggerOnce/strikeEvery,并使该预设旧句柄(含 bindToEntity)失效
setPointData(handle, patch) 改单点色 / 大小 / 位置 增量写
// 1 万火焰
const handles = fx.addPoints('fire', list);

// 周期刷新
fx.replaceAllPoints('fire', newList);

// 单点改色
fx.setPointData(handles[0], { color: [1, 0, 0, 1] });

五、事件 fx.on

事件 payload 何时 fire
render (activeCount) 每一帧且 ≥ 1 个实例存活
empty () active 从 N 降到 0 时一次
overflow ({ kind, preset, capacity }) GPU 容量自动扩容时
compact ({ preset, result }) 闲置槽位整理完成
fx.on('render', active => hud.active = active);
fx.on('empty', () => console.log('全部清空'));
fx.on('overflow', ({ kind, preset, capacity }) =>
  console.warn(`扩容 ${kind}/${preset} → ${capacity}`));
fx.on('compact', ({ preset, result }) =>
  console.log(`compacted ${preset}, moved=${result?.remap?.size ?? 0}`));
  • render 不在 active=0 的帧 fire → 适合 FPS 采样
  • empty 是边沿事件 → 适合 "清场后" 逻辑
  • overflow / compact 都是良性提示

六、getMetrics() 实时指标

const arr = fx.getMetrics();
// [
//   { bucket: 'above',   active: 5234, points: [...], lines: [...], shadertoys: [...] },
//   { bucket: 'topmost', active:   12, ... }
// ]
字段 说明
bucket 'below' / 'above' / 'topmost'
active 该桶活跃 FX 实例总数
points { preset, live, capacity }[]
lines { preset, live }[]
shadertoys { programKey, live, capacity }[]

调用成本 O(unique presets);随便 setInterval 250ms 也无压力。

七、事件仪表盘工具

function attachDashboard(fx) {
  const s = { fps: 0, frameMs: 0, peakMs: 0, renderFrames: 0, emptyFires: 0, overflowFires: 0, compactFires: 0 };
  let last = 0; const win = [];
  const onRender = () => {
    s.renderFrames++;
    const now = performance.now();
    if (last) {
      const dt = now - last;
      win.push(dt); if (win.length > 60) win.shift();
      s.frameMs = win.reduce((a, b) => a + b, 0) / win.length;
      s.peakMs = Math.max(s.peakMs, dt);
      s.fps = 1000 / s.frameMs;
    }
    last = now;
  };
  fx.on('render', onRender);
  fx.on('empty', () => { s.emptyFires++; last = 0; win.length = 0; });
  fx.on('overflow', () => s.overflowFires++);
  fx.on('compact', () => s.compactFires++);
  return s;
}

const stats = attachDashboard(fx);
setInterval(() => console.log(stats), 1000);

八、调优套餐

卡(< 30 FPS)

  1. fx.setQuality('lite') → 常见 +20% FPS
  2. 查 getMetrics 哪个 preset live 最大 → 瓶颈
  3. 同区域重叠多个 cinematic Shadertoy → 换预设
  4. Symbol 图标:fx.symbolImage.addPreset 时 fps: 24~30

海量点

  1. addPoints 与同步循环 addPoint 都是每帧一次合并上传,差别不大;瓶颈通常在实例数与 shader 档位
  2. 周期刷新走 replaceAllPoints(仅限 above 桶、且该预设没有 bindToEntity 绑定时)
  3. 海量同形点 → fx.symbolImage 性能与点数解耦
  4. 上万点还要 60 FPS → 聚合 (cluster) + symbolImage

偶发卡顿

  1. overflow 频繁 → 反复 add/remove 改为 setPointData({ visible: false }) 重用
  2. compact 触发 → 自动整理,handle 自动 remap,无需手动处理
  3. 切 quality 首次 30ms 编译 → 缓存后 0ms

九、压测参考(中端集成显卡)

预设 / 数量 1k 5k 10k 20k 50k
pulseRing 60 60 58 50 35
fire 60 60 55 45 28
halo 60 60 60 55 40
radarSweep 60 60 55 42 25
meteor 60 60 55 40 22
lightning 60 60 50 35 18

数字仅供参考;实际看 GPU / 分辨率 / size 屏占比。

十、常见坑

  1. setQuality 每帧切:没必要;程序生命周期里通常只切 1~2 次。
  2. cinematic 开全:中低端机撑不住;给次要特效 lite。
  3. bucket topmost 滥用:所有 FX 都 topmost → z-order 混乱,UI 遮挡。
  4. forgot to off fx events:组件卸载时必须 fx.off。
  5. metrics 拿来做 UI 高频刷新:250ms 够了;别 16ms。

相关