11 KiB
STEP-068 MapLibreParticleLab V3-04 DIRECTION 粒子推进 — Codex 任务 v1
执行状态(2026-09-11):IMPLEMENTED / WAITING_VALIDATION。C++/shader scoped 实现与 shader generator 已完成;本沙箱对最终含新增 source test 的精确编译连续在单次 30 秒终端上限前中止,未将其或全量 Ninja 写为 PASS。详见同编号 Step 记录与完成报告。
0. 任务定位
本任务承接已关闭的 STEP-065/066/067,在 MapLibreParticleLab V3 Core/GPU 中实现第二种通用 VectorSemantics:DIRECTION。
目标不是 Wave 业务实现,而是让任意 canonical direction-only vector field 可以驱动 RasterParticleLayer。Core/renderer 仍不得理解 WIND/WAVE/RAIN/TIDE、WeatherV2、NSFT 或 provider。
本任务只做到 C++/shader/Linux OpenGL 可验证闭环;不得进入 Android/JNI/RN v2 ingress,不执行 Android Gradle/AAR/APK/ADB,不加入或执行 Jest。
1. 仓库与基线
仓库:/mnt/sda1/MapLibreParticleLab
分支:particle/main
任务书编写时 HEAD:89c72554c5fb5cd469bdd8ba06ff4b03a1a67ff9
该 HEAD 已等于 origin/particle/main,STEP-067 为 CLOSED / PASS。
开工时必须重新确认 branch / HEAD / origin / git status --short。若远端已合法推进,先阅读新增提交,不得 reset。
当前工作区仍有 STEP-062 两处用户修改和历史 untracked/build/cache/tgz。全部保留;禁止 git add . / git add -A,禁止恢复、删除、覆盖或提交无关内容。
2. 必须阅读
至少阅读:
AGENTS.mdPARTICLE_BASELINE.mddocs/00_项目规范/*.mddocs/30_设计/MapLibreParticleLab_V3通用ScalarVectorField运行时架构设计_v1.mddocs/50_Step记录/STEP-065_MapLibreParticleLab_V3通用ScalarVectorField架构冻结_v1.mddocs/50_Step记录/STEP-066_MapLibreParticleLab_V3-02_CoreContract与ScalarSnapshotAdapter_v1.mddocs/50_Step记录/STEP-067_MapLibreParticleLab_V3-03_ScalarGPU与GenericFieldRenderer_v1.mdinclude/mbgl/particle/field/field_data_adapter.hppsrc/mbgl/particle/field/field_data_adapter.cppsrc/mbgl/renderer/layers/render_particle_validation_layer.cppinclude/mbgl/style/layers/raster_particle_layer.hppsrc/mbgl/style/layers/raster_particle_layer.cppsrc/mbgl/style/layers/raster_particle_layer_impl.hppsrc/mbgl/style/layers/particle_render_layer_properties.hppshaders/particle_gpu_validation.vertex.glslshaders/particle_gpu_validation.fragment.glslinclude/mbgl/shaders/particle_gpu_validation_ubo.hpp- 对应 generated OpenGL shader header 与现有 layer/source tests。
实现必须以实际源码为准,不得按任务书示例猜接口。
3. 冻结语义
V3 vector semantics 只有:
VELOCITY:canonical U east / V north,物理速度,保持现有 m/s Web Mercator 推进路径。DIRECTION:canonical U east / V north,只表达方向;输入通常为单位向量,但 GPU 不可假设时间插值后仍为单位长度。
DIRECTION 的 GPU 规则必须是:
- 分别解码 T0/T1 vector;
- 按当前
timeMix对 U/V component-wise 插值; - 检查 finite;
- 对插值结果求长度;
- 长度 <= epsilon 时 fail-closed;
- 否则 normalize;
- 乘独立的 renderer
advectionScale; - 再进入现有 Web Mercator displacement 计算。
严禁:
- 先分别 normalize T0/T1 再做最终不归一化 mix;
- 使用 scalar height、period 或 vector 原 magnitude 决定推进速度;
- 将 DIRECTION 当 m/s;
- 在 Core 中出现 Wave 分支。
反向方向示例:T0=(1,0)、T1=(-1,0)、MIX=0.5,插值向量长度近零,必须 invalid/fail-closed,不得任意选择东或西。
4. VELOCITY 回归保护
VELOCITY 是已通过 Android 的旧正式路径。本任务必须保持默认行为:
- 不 normalize VELOCITY;
- T0/T1 仍 component-wise mix;
- 默认参数下 displacement 公式不变;
- U east / V north 与 world-y southward 的符号不变;
- latitude/cos(latitude)/Earth circumference 计算不变;
- lifecycle、respawn、Trail、T0/T1/MIX、pause、cadence、window rollover 不重写。
允许为共享 helper 重构 shader,但必须证明 VELOCITY 结果等价。
5. advectionScale
为 DIRECTION 增加 business-neutral renderer 控制 advectionScale。
优先以 RasterParticleLayer 的 C++ Core style/control property 实现,建议属性名:raster-particle-advection-scale,C++ API 为 getAdvectionScale()/setAdvectionScale();最终命名需与现有 property 体系一致。
冻结要求:
- 默认值
1.0,确保不隐式引入产品级速度偏好; - 必须 finite 且 > 0;需要上限时根据现有数值安全给出保守、文档化的界限,不得随意设为天气业务值;
- V3-04 中
advectionScale只改变 DIRECTION 的推进 magnitude;VELOCITY 默认/现有运动数学不因该属性变化而改变; - 不从 scalar、fieldId、fieldType、displayDomain 推导该值;
- RN 公共 API 暂不增加,留给 V3-05 一并接线。
如果当前 CoreOnly layer property 机制不适合新增 serialize property,Codex 可采用最小等价 C++ renderer config,但必须在报告解释原因;不得因此提前改 Android/JNI/RN。
6. Shader/UBO 一致性
当前 State fragment shader 和正式 particle line vertex shader都会独立读取 u_field_texture/u_next_field_texture。
两者必须使用相同 semantics:
decode T0/T1 -> mix -> resolve VELOCITY or DIRECTION -> validity
不得出现 State 按 Direction 推进、但 line vertex 仍把 raw mixed direction 当 velocity 的不一致。
建议增加明确的 UBO advection/semantics 参数,例如独立 vec4,避免挤占已有字段导致语义混乱。若修改 UBO:
- 同步 vertex GLSL;
- 同步 fragment GLSL;
- 同步 C++ UBO struct/static_assert;
- 运行官方 shader generator 更新 generated OpenGL header;
- 不手工只改 generated header。
helper 命名应从 fieldVelocityAt 收敛为 generic advection/vector 语义;不得继续用 velocity 名称表达 DIRECTION 分支。
7. Renderer acceptance
STEP-067 当前主动拒绝 VectorSemantics::Direction。本任务需改为:
- scalar-only:Particle unavailable/fail-closed;
- vector VELOCITY:允许;
- vector DIRECTION:允许;
- T0/T1 semantics 不一致:继续 fail-closed(正常应已被 Timeline compatibility 拦截,但 renderer 仍防御);
- invalid/NaN/near-zero mixed direction:该 sample invalid,按既有 lifecycle/respawn 安全处理;不得产生 NaN position。
切换 semantics/window 时不得错误复用与新 semantics 不兼容的 GPU resource。既有 sameFieldGpuContent/Timeline compatibility 的 semantics 保护必须保留。
8. Trail 与粒子线段
正式 particle line 必须与 State 实际位移一致:
- line segment 继续连接 previousState -> currentState;
- vertex shader 用于
v_particle_velocity/颜色判断的向量必须使用与 State 相同的 resolved advection vector; - DIRECTION 下可把
length(resolvedAdvection)作为纯视觉强度输入,但不得声称它是原始物理 speed; - 不允许用 scalar 驱动 particle color;
- 本任务不重新设计 speedColorEnabled 公共能力,若命名仍带历史 speed,可记录技术债,避免扩大范围。
9. Timeline / GPU reuse 硬保护
不得破坏:
- Source-owned Timeline;
- T0/T1/MIX;
- PAUSE;
- 连续 MIX 时零 field upload;
- OLD_T1 -> NEW_T0 reuse;
- 正常 rollover 只上传 NEW_T1;
- window overlap 时
simulationRebuild=false、trailCleared=false; - style/context loss 的既有重建规则;
- invalid/gap fail-closed。
改变 advectionScale 不应重新上传 field texture。是否清 trail/simulation 必须依据当前生命周期设计最小化,默认不允许为了纯 renderer 参数变化重新提交 field。
10. 必须补的验证
本任务需新增/调整最小测试,至少覆盖:
- RasterParticleLayer advectionScale 默认值与 set/get/非法值策略;
- VELOCITY 与 DIRECTION renderer eligibility;
- scalar-only 仍 fail-closed;
- T0/T1 semantics mismatch fail-closed/不绘制;
- shader/UBO semantics 参数正确传递;
- DIRECTION 数学:east、north、斜向;
- T0 east + T1 north + MIX=0.5 -> normalize 后 northeast;
- T0 east + T1 west + MIX=0.5 -> near-zero invalid;
- advectionScale 改变 magnitude、不改变 direction;
- VELOCITY 路径不 normalize,默认结果保持现状。
优先使用当前已有 C++ test/fixture 体系;不要为了测试引入新的大型 framework。
11. Linux 验证
必须执行:
node shaders/generate_shader_code.mjs;- 受影响 C++ 精确对象编译;
- 相关现有/新增过滤测试;
- 在可行时
ninja -C build-linux-opengl -j3 mbgl-test mbgl-test-runner; git diff --check。
构建日志遵循项目全局 build-output-throttle。
如果全量 Ninja 再受单次终端时间限制,不得伪造 PASS;但应先确保受影响精确对象与过滤测试通过,并在报告明确缺口。不得要求用户现在编 Android。
12. 明确禁止
本任务不得:
- 修改 Android Java/Kotlin/JNI bridge;
- 修改 RN package API/version;
- 实现 v2 multi-plane file ingress;
- 修改 WeatherV2/NavSea;
- 解析 NSFT/PMTiles;
- 添加 Wind/Wave/Rain/Tide enum 或业务分支;
- 使用 scalar height/period 控制 DIRECTION 速度;
- 增加第二 scalar/N-channel;
- 重写 Timeline/Playback/Runtime Window;
- JSI/zero-copy 重构;
- 执行 Android Gradle/AAR/APK/ADB;
- 加入或执行 Jest。
13. 文档与状态
新增/更新:
- 本任务书
docs/40_任务/STEP-068_MapLibreParticleLab_V3-04_DIRECTION粒子推进_Codex任务_v1.md docs/50_Step记录/STEP-068_MapLibreParticleLab_V3-04_DIRECTION粒子推进_v1.mddocs/报告/STEP-068_MapLibreParticleLab_V3-04_DIRECTION粒子推进_Codex完成报告_v1.md- 追加
粒子开发记录.md
全部文档中文。完成报告逐项写“已完成 / 未完成 / 无法验证”,明确生产代码范围、验证结果、Android/Jest 未执行、风险和下一步。
若代码与 Linux 验证满足本任务门槛,可标记 CLOSED / PASS;若只有实现而关键精确编译/过滤测试未通过,则只能 IMPLEMENTED / WAITING_VALIDATION。
14. Git 收尾
本任务有生产代码修改,完成后必须 scoped commit + push 到 origin/particle/main。
提交前再次 git status --short。只暂存本任务实际修改文件与上述 STEP-068 文档;禁止纳入 STEP-062 两处用户修改和所有历史 untracked/build/cache/tgz。
允许按“实现代码”与“文档收尾”做 1-2 个 scoped commit。禁止 git add .、git add -A。
push 后必须确认:
- commit hash/message;
- push 成功;
HEAD == origin/particle/main;- 最终工作区剩余 dirty 仍只属于原有用户/历史内容。
push 失败则任务不得声称完全完成。
15. 下一阶段边界
本任务完成后下一阶段应为 V3-05:Android/JNI/RN generic v2 multi-plane ingress。
V3-05 之前不要求 Android build。最终仍按 V3 总规划,将 Android 编译/安装/设备综合验收集中到后续大阶段,避免每个小 Step 重复一次 Android 周期。