Type: research Status: resolved Labels: wayfinder:research Blocked by: None
已完成:Cesium 1.145.0 上设备状态特效的五项事实全部核实完毕(可用原语的能力边界、批量做法与 10/50/200 的开销量级、与限距雾后处理的同集合共存与执行顺序、色与形的单一来源在引擎侧的可行边界、拾取与层级),产物落在 research/device-status-effect-mechanisms.md,每条结论带随包 d.ts/源码路径与行号或官方文档链接;查不到的项已在产物里显式列出。只读调研:未改 src/、未装依赖、未跑 build/dev/截图。
需求⑤要求「定位到设备时,设备点位周围产生对应的特效(对应设备状态:报警、预警、工单、正常、离线等)」。本票只查事实:Cesium 1.145.0 上这类特效怎么做、代价多大、与既定的雾气后处理是否打架。
Entity + CallbackProperty 驱动的动画 billboard / ellipse / cylinder;CustomDataSource 与 Primitive + GeometryInstance + Appearance;PostProcessStage / PostProcessStageCollection;ParticleSystem,注意它挂在 Scene.primitives 上,是全局而非按实体)。Primitive + Appearance 的 instancing、BillboardCollection 的 scale 动画、shader 里按 attribute 驱动)?给同屏 10 / 50 / 200 个特效点的量级判断(有实测数据最好,没有就写清是推断并说明依据)。.scratch/cockpit-primary-area-guardrails 的 07 已定「自建 Cesium depth 后处理级视距雾(路线 B)」,产物在本地图 research/three-fog-shader-reuse.md。请核对:同一 PostProcessStageCollection 里再挂设备特效级是否可行?PostProcessStage 的 execute 顺序语义是什么?该图 06 已更正「Context.depthTexture 是布尔能力标志而非纹理对象」——设备特效若也要读深度,路径是什么?styles/tokens.css 的语义色(--lv1..--lv4/--neutral)与 domain/pointStatus.js 那张表来(票 06/09 的纪律)。引擎侧有哪些地方读不到 CSS 变量、必须像 markerSvg() 那样由服务层烘焙(列出具体 API)。Scene.pick 与 Scene.drillPick 在多个 primitive 叠加时的行为,以及「特效不该吃点击」有哪些做法。产物写到 research/device-status-effect-mechanisms.md,每条结论带来源(随包 d.ts 路径 + 行号、官方文档 URL、或仓库内文件)。
结论:状态特效走「BillboardCollection 逐点 scale/color 动画」为主、「单个自定义 Primitive(N 个 GeometryInstance + 同一 Appearance + batch table)一次 draw call 画 N 个」为升级路径;Entity + CallbackProperty 只留给 1–3 个聚焦设备;与限距雾同处一个 PostProcessStageCollection 可行,但顺序必须显式定为「先特效、后雾」。 全文与逐条证据:research/device-status-effect-mechanisms.md。
Entity + CallbackProperty 能做「按实体定位、只影响一点、可拾取」,但每帧重算且代价极高——非常量属性让 EllipseGeometryUpdater._isDynamic 判真(EllipseGeometryUpdater.js:222-239),走「每实体一个 updater」的 DynamicGeometryBatch(DynamicGeometryBatch.js:14-22),而 DynamicGeometryUpdater.update 每帧 removeAndDestroy 再 new Primitive({asynchronous:false}) 重建(DynamicGeometryUpdater.js:76-85, 139-153);社区实测 25 个 CallbackProperty 圆柱 ≈8 FPS、200 个 ≈0 FPS。CustomDataSource 只是容器,不产生渲染原语。Primitive + GeometryInstance + Appearance 是「一次 draw call 画 N 个」的正统路径(N 个实例合并成一个几何,draw command 数 = _va.length,逐实例数据走 batch table 纹理按 batchId 查,Primitive.js:538-543, 1868, 887)。PostProcessStage 是全屏后处理,无法只影响一个点(除非用只对 3D Tiles feature 有效的 selected + czm_selected,对点位图标无效)。ParticleSystem 挂在 Scene.primitives 上、内部自建一个 BillboardCollection(ParticleSystem.js:710, 807),靠 modelMatrix/emitterModelMatrix 定位、没有位置参数、没有 pick 路径,N 个点就是 N 份粒子模拟。Primitive(逐实例数据走 batch table 纹理,Primitive.js:817-963);② 1.145 的 BufferPointCollection 显式一次 DrawCommand 画完(renderBufferPointCollection.js:278-294),但它 @experimental(BufferPointCollection.js:56-57)且只能改 size/color,不建议押注。10/50/200 的量级判断:BillboardCollection(整集合一次 drawElements,逐点脏更新 BillboardCollection.js:1466-1507)在 200 个点仍属安全区——官方 10,000 个静态 billboard 266 FPS、动画 138 FPS(Billboard Instancing);CallbackProperty 椭圆路线 200 个不可行。本票未在本机实测,10/50/200 是依据绘制结构 + 上述可引实测的推断,真数需在实现票实测。scene.postProcessStages 可以再挂一个设备特效级(add() 无上限、只有名字唯一约束,PostProcessStageCollection.js:436-466)。execute 顺序 = 加入顺序(无插入/排序 API,_index = stages.length),骨架固定为「AO → Bloom → 色调映射 → 自建 stage 按序链式传色 → FXAA」(:799-834);颜色链式、深度不链式——每级拿到的 depthTexture 都是场景那一张(:801-827),所以两级读同一份深度,但谁后跑谁在最上层。→ 顺序应定为先特效、后雾气,否则侧视时会出现「雾盖住了县城、设备特效却亮在雾上面」,违反该图 07 的门控诉求(07-fog-implementation-spec.md:20-24);两级开关要一次原子对齐(enabled 是逐级独立的,PostProcessStage.js:178-182)。读深度的正确路径 = PostProcessStage 默认提供的 sampler2D depthTexture(PostProcessStage.js:32-33, 526-531)+ czm_readDepth;但点位特效通常不需要读深度,正常深度测试即可。注意能力探测是文本正则(PostProcessStage.js:397-404),着色器里必须写成 uniform sampler2D depthTexture。markerSvg() 一样由服务层烘焙(现成入口 mapService.js:631-651 的 toneColors() → :670-676)。必须烘焙的具体 API:billboard.image(SVG 作为图片加载时读不到页面 CSS,pointStatus.js:218)、Billboard#color、Material 的 uniform(Material.js:1255-1278 要求 number/Color,字符串会被当作图片或 stage 输出名)、ColorGeometryInstanceAttribute、BufferPointMaterial.color/outlineColor、PostProcessStage.uniforms、以及自建 GLSL 里的颜色常量(只能走 uniforms)。形状仍只来自 pointStatus.js 的 SHAPES(:42-59),引擎层不新增第二张业务映射表(syncPointMarkers 只认 shape/color 是同一条纪律,cesiumEngine.js:303-319)。derivedCommands.picking(由 command.pickId 派生,Scene.js:1810-1817)或 depth 时才画(executeIdCommand,Scene.js:2379-2404),没有 pickId 的实体命令被整条跳过。做法:① 首选 Primitive({ allowPicking: false })(Primitive.js:76, 2055-2059)或 BufferPointCollection 默认 allowPicking=false(BufferPointCollection.js:159),ParticleSystem / PostProcessStage 本就无拾取路径;② 特效放独立 collection 且不带 pointCode 属性(现有拾取口径就是「有 pointCode 才算点位」,cesiumEngine.js:417-431);③ 做成空心环(billboard 拾取看非透明像素)。最易踩的坑:不透明特效即使没有 pickId,也有 depthOnly 派生命令(Scene.js:2400-2403),会在拾取通道写深度挡住背后的设备点——特效面片必须走半透明 pass(Appearance.js:152-153)。Scene.pick 只回最靠近相机的一个;Scene.drillPick 是「拾一个藏一个再拾」的多次拾取(Picking.js:895-941),可穿透但代价是 N 次 pick pass,且靠改 show 实现,与特效独立开关会互相干扰,不推荐。