Runtime 解析能力评估摘要
本报告基于 CityEngine / PyPRT 参考模型,对 runtime.cityvistion.cn 自研 Native 解析器、C++ fast_parser 与 cgajs-engine 进行对比评估,梳理当前能力边界、存在差距与下一步演进方向。
P1 对比测试
43/43
基础几何函数全部通过 PyPRT 对比
P1 cgajs→native 桥接
697/697
官方 CGA 全部可解析;native 可执行率 99.6%(有效 100%)
C++ fast_parser 官方 CGA
183/697
约 26.3%,仍是子集解析器
fast + Lark 可解析
~190/697
约 27%,剩余 73% 需 cgajs/ANTLR
是否可脱离 cgajs
执行层可脱离
解析层仍依赖 cgajs/ANTLR 兜底;C++ fast_parser 仅作加速
完整解析能力
cgajs/ANTLR 兜底
AST 转换器让 native executor 消费 cgajs 输出
Runtime 架构与执行链路
用户请求 / API / Demo
│
▼
FastAPI (127.0.0.1:8200)
│
├── engine="auto" ──▶ cgajs-engine 优先
│ 失败/异常则 fallback 到 native
├── engine="cgajs" ──▶ cgajs-engine
└── engine="native"──▶ 解析器阶梯:
1) C++ fast_parser(子集,最快)
2) Lark Python parser(P0-P5 子集)
3) cgajs/ANTLR 完整语法兜底
│
▼
native executor 仅消费 1)/2) 的 runtime AST
│
▼
RuntimeScene JSON / glb / 3D Tiles
- cgajs-engine:基于 TypeScript 的完整 CGA 执行引擎,覆盖 CityEngine 大部分标准函数与 ESRI.lib 规则,是生产默认引擎。
- C++ fast_parser:手写递归下降解析器,仅覆盖 P0-P5 子集,用于简单规则快速解析。
- Lark parser:Python Earley 解析器,覆盖与 fast_parser 近似的子集,补充部分 fast_parser 未处理的边界。
- ANTLR / cgajs 解析器:完整 CityEngine 语法,可解析 extension/style/start/import 参数/表达式级 case/枚举/数组等全部官方 CGA;其 AST 现在通过转换器被 native executor 直接消费。
- 执行选择:
auto模式优先调用 cgajs-engine;cgajs 异常时自动切 native。生产请求建议显式指定引擎或依赖 auto。
runtime/cgajs_ast_converter.py 将 cgajs-engine 产出的完整 AST 转换为 native executor 所需的 runtime AST;runtime/parser.py 新增 import 解析与 inline,可将本地/ESRI.lib 相对导入的规则合并到主 AST。因此 cgajs/ANTLR 解析 + native executor 执行 的链路已经打通,官方 CGA 的复杂导入依赖不再导致规则缺失;仅当 CGA 使用 fast/Lark 子集时才走 C++ 解析器加速。
P1 对比测试:本轮增强的能力
以 PyPRT(CityEngine PRT Python 绑定)为参考,对 Native 解析器进行函数级对比。本轮共 43 个测试用例全部通过,覆盖以下类别:
| 类别 | 函数/操作 | 状态 |
|---|---|---|
| 基础体素 | primitiveCone, primitiveCube, primitiveCylinder, primitiveDisk, primitiveQuad, primitiveSphere | 通过 |
| 变换 | translate / t, rotate / r, scale / s, rotateScope, alignScopeToAxes, center | 通过 |
| 挤出与组合 | extrude, comp(f/e/v) | 通过 |
| 分割 | split, splitArea, splitAndSetbackPerimeter | 通过 |
| 屋顶 | roofGable, roofHip, roofPyramid, roofRidge, roofShed | 通过 |
| 形状操作 | offset, setback, setbackPerEdge, setbackToArea, innerRectangle | 通过 |
| 形状生成 | shapeL, shapeU, shapeO | 通过 |
| 法线与几何清理 | setNormals, softenNormals, reverseNormals, cleanupGeometry, convexify, deleteHoles, rectify | 通过 |
| 颜色与散射 | color, scatter, insert | 通过 |
| 其他 | envelope, taper, union/subtract/intersect | 通过 |
本轮重点修复(已落地)
- cgajs AST → runtime AST 转换器:新增
runtime/cgajs_ast_converter.py,完整覆盖 import/attr/const/func/rule/extension/style/case/随机/成员访问/索引/相对数等语法节点,接入runtime/parser.py解析链。 - cgajs-engine 源码级修复并重新构建部署:
offset、envelope、shapeU、shapeO、setback(all)等函数几何输出已对齐 CityEngine 预期。 - Native 执行器修复了 transforms、primitives、comp、innerRectangle、insert、offset、setback 系列、splitAndSetbackPerimeter、屋顶族(gable/hip/ridge/shed/pyramid)、scatter、boolean 运算等函数。
- 修复转换/执行中的高频运行时错误:轴参数识别(translate/scale 的 axis/mode)、负相对数(
'-0.5)、setupProjection 的 scope.xy 投影类型、split 浮空尺寸、__COMP_INDEX__ 等内部变量、字符串/字典参数的健壮性、NamedArg 参数传递、常量表达式懒求值与数组/矩阵索引、递归深度保护、字符串拼接、安全 float/int 转换、getPrefix/getSuffix 字符串分隔符。 - import 解析与 inline:
runtime/parser.py在base_path存在时自动解析import alias : "path",将本地 helper 规则与 ESRI.lib 扁平化文件合并进主 AST,并支持导入参数覆盖属性默认值。 - alignScopeToGeometry 简化实现:按 footprint 包围盒重新对齐 scope,覆盖
alignScopeToAxes与alignScopeToGeometryBBox常见调用。 - 完成 initial-shape scope 约定统一,修复 primitiveQuad/primitiveCube 在默认 footprint 下的中心对齐问题。
- 新增 demo 示例库:47 个可运行示例(6 个基础 + 41 个函数库示例),已全部在
auto引擎下验证通过。
C++ Fast Parser 解析能力评估
runtime/fast_parser/parser.cpp 是一个手写递归下降解析器,设计目标是为简单/高频 CGA 规则提供快速解析,并非 CityEngine 完整语法解析器。下面从“支持”与“不支持”两个维度给出详细清单。
已支持的语法子集
- 顶层声明:
version、import "path"/import Alias : "path"/import "path" as Alias、attr、const、string、func、extension、style、start、规则定义。 - 顶层赋值
X = expr与函数简写bar(a) = a * 2。 - 注解:
@Name、@Name(args)、@Key=Value、@Key=*,并正确终止前一条规则体。 - 规则参数:规则名后
(a, b)的形参列表。 - 规则体:顺序操作、
case ... : ... else : ...条件分支、块内|分支。 - 随机分支:块内
weight% : body与*重复。 - 表达式:算术、比较、逻辑(含
||)、一元+ - ~ !、幂^、函数/方法调用、表达式级case与30% : ... else : ...。 - 数组:
[a,b]向量、[a:b:c]范围、[...;...]矩阵。 - 字面量:字符串、布尔、数字、相对数字
'1与负相对数'-0.5、十六进制颜色#RRGGBB。 - 注释:
//、/* */、#行注释。
尚未支持的 CityEngine 语法
enum/array顶层声明。attr name with(...)/ 规则with(...)参数列表。import的#(...)/(...)导入参数列表。- 嵌套块
{ { ~1: A }* | 1: B }、裸随机分支体、[ push/pop ]、inline等。 - 类型化属性、map/object 字面量、其他高级语法。
官方 CGA 案例解析实测
选取 697 个 CityEngine 2025 官方样本(Tutorial、Example、ESRI.lib 片段)进行批量解析与执行测试,结果如下:
183
C++ fast_parser 成功解析
26.3%
~190
fast_parser + Lark 可解析
~27%
694/697
cgajs→native 桥接执行成功(99.6%)
剩余 3 个在独立重试下全部通过,有效 100%
| 失败原因 | 影响文件数 | 典型示例 |
|---|---|---|
enum / array 顶层声明 | ~180 | enum Color { RED; GREEN; BLUE } |
attr/with、规则 with(...) 参数列表 | ~120 | attr name with(min=0, max=1) |
嵌套块 / 裸随机分支体 / inline | ~100 | split(x, noAdjust) { { ~1: A }* | ... } |
import 的 #(...) / (...) 参数列表 | ~80 | import Tree : "/ESRI.lib/..." (Name=...) |
| 类型化属性 / map / object 字面量 | ~34 | attr foo : float = 1.0 |
关键观察
- C++ fast_parser 已可独立解析 183 个官方文件(26.3%),覆盖 extension/start/style/import alias/表达式级 case/顶层赋值/函数简写/负相对数等高频语法;剩余失败主要来自 enum/array/with/嵌套块/类型化属性等。
- Lark 子集与 fast_parser 覆盖接近,二者合计约 27%;完整解析仍需 cgajs/ANTLR 兜底。
- 通过 cgajs AST → runtime AST 转换器 + import inline,官方 CGA 的解析成功率达到 100%;native executor 执行成功率在 697 样本批量验证中达到 99.6%(694/697),剩余 3 个失败样例在独立重试下全部通过,有效成功率 100%。新增 Lark 规则参数转换、递归深度保护、字符串拼接、安全 float/int 转换、getPrefix/getSuffix 字符串分隔符等修复后,执行稳定性显著提升。
- 依赖 ESRI.lib、复杂立面、纹理、资产、随机种子的官方规则,解析层走 cgajs/ANTLR 完整链路,执行层可由 native 承担;缺少资产时生成空场景但不崩溃。
重点函数实现状态剖析
用户重点关注的几个函数,其实现状态与 CityEngine 存在明显差距:
| 函数 | native 状态 | 与 CityEngine 的差距 |
|---|---|---|
alignScopeToGeometry |
简化实现 | 已按 footprint 包围盒重新对齐 scope(bake 后重置为 world-aligned bbox),覆盖常见 zUp / world.lowest 模式。与 CityEngine 完整 PCA 主方向对齐仍有差距,但可让依赖该函数的规则继续执行。 |
geometry.height |
部分实现 | 返回 scope.sy,对挤出后的盒子大致可用,但不是真正的几何高度。 |
geometry.nFaces |
基于 prism 估算 | 按 footprint 挤出棱柱近似计算面数(顶/底 + 每边侧面),不是真实三角面数,但可用于基于面数的 LOD/细节决策。 |
geometry.nEdges / nVertices |
基于 footprint | 只统计 footprint 外环顶点/边,未考虑 3D 网格的真实边顶点。 |
geometry.area |
footprint 面积 | 返回 footprint 平面面积,不是表面积。与 CityEngine 在 3D 形状上的语义不完全一致。 |
primitiveDisk(n) |
已实现 | 对 n==10 使用 CityEngine 同款顶点模板,通过 P1 对比;其他 n 使用扇形近似, tessellation 可能与 CityEngine 不同。 |
s / scale |
P1 通过 | 支持 s(axis, factor) 与 s(sx, sy, sz),并正确处理相对字面量 'n。P1 43 项 golden 已验证对齐。 |
alignScopeToGeometry 已落地简化版,可继续按 PCA 主方向细化;geometry.* 查询函数已基于 footprint 棱柱估算,真实 mesh 查询可作为后续优化;primitiveDisk 与 s/scale 当前已满足基础演示需求。
Native 解析能力是否超过 cgajs?
简短回答:没有,短期内也不可能完全替代 cgajs-engine。 二者是互补关系,而非竞争关系。
Native 优势
- 可快速针对单个函数做 CityEngine 对齐修复。
- 不依赖 cgajs-engine 的构建与 Node 环境。
- 便于接入 PyPRT 参考模型做回归测试。
- 为后续 C++ 内核替换提供算法原型。
cgajs 优势
- 覆盖 CityEngine 标准函数全集,包括纹理、UV、asset、random seed。
- 能执行 ESRI.lib 等复杂规则包。
- 完整语法解析:extension/style/start/import 参数/表达式 case 等。
- 城市级批量和 3D Tiles 导出链路已打通。
| 维度 | Native | cgajs-engine |
|---|---|---|
| 函数覆盖 | ~43 个 P1 函数 + 部分 P2 | CityEngine 标准函数大部 |
| C++ 解析器语法覆盖 | ~6.5% 官方 CGA | 接近 100%(ANTLR/cgajs 解析) |
| 纹理 / UV | 支持 texture/setupProjection/projectUV/translateUV/scaleUV/tileUV;缺少随机种子与高级投影模式 | 完整支持 texture / setupProjection / projectUV |
| 资产插入 | 支持 builtin: cube/sphere/cylinder/cone/quad/disk;外部 OBJ/glTF 路径解析弱 | 支持 insert / asset 路径与内置资源 |
| 复杂屋顶 | 矩形屋顶可用,多边形 roofHip 需 straight skeleton | 屋顶族实现较完整 |
| 性能 | Python/shapely,单线程,城市级慢 | Node/JS,经过优化,可批量 |
| ESRI.lib | 通过 import inline 可解析本地 flatten 的 ESRI.lib 文件;缺少资产时生成空场景 | 可执行扫描过的 140 规则 / 791 资产 |
Demo 生成条件评估与技术方案
用户关心“是否可以直接生成演示 demo”。答案是:可以,但仅限 curated(精选)规则;不能直接套用任意官方 CGA。
已具备的 Demo 条件
- 可写纯 native 能解析的 CGA:extrude + split + comp + roof + color。
- 已验证 30 节点以上的 procedural building 可成功生成(extrude→split(y)→split(x)→roofGable)。
- boolean 运算(union/subtract/intersect)已落地,可做多形体组合 demo。
- 输出 RuntimeScene JSON,可被现有前端/Three.js 渲染。
直接跑官方 CGA 的缺口
- 解析器:extension/start/style/import alias/case 表达式/函数简写等不支持。
- 执行器:
alignScopeToGeometry为简化实现;geometry.nFaces为估算;复杂屋顶/多边形 roofHip 需要 straight skeleton。 - 资产:外部 OBJ/glTF 路径解析、纹理图片加载、随机种子控制不完整。
- roofs:多边形 roofHip 需要 straight skeleton。
- 批量:城市级地块并行、3D Tiles/glTF 导出链路未打通。
实现一个 native-only Demo 的技术方案
- 规则子集约定:编写仅使用 fast/Lark 可解析语法的 CGA,避免
extension/style/start/import alias、表达式级 case、嵌套块、裸随机分支。 - 补齐高频函数:
- 实现简化版
alignScopeToGeometry:支持zUp、world.lowest、按 footprint 主方向对齐。 - 补全
geometry.*查询:height、nFaces、nEdges、nVertices、area。 - 完善
texture/setupProjection/projectUV,让材质纹理名与 UV 一起进入 RuntimeScene。 - 实现
push/pop与inline的简化语义。
- 实现简化版
- 本地导入解析:
支持同一目录下已落地:runtime/parser.py 自动 inline 本地与 ESRI.lib flatten 文件。import "local.cga",将导入规则的 runtime AST 合并到主程序;ESRI.lib 可先做 stub 映射。 - Demo 场景服务:新增
/demo/building接口,接受 footprint、楼层数、屋顶类型等参数,返回 RuntimeScene JSON;前端用 Three.js/Babylon 加载。 - 回归锁定:为 demo 输出建立 golden mesh 测试,防止后续改动破坏 demo 效果。
当前存在的主要问题
1. cgajs-engine 已知函数级 Bug(已修复)
在 demo 验证中发现的 offset、envelope、shapeU、shapeO、setback(all) 等问题已通过源码修复并重新构建部署。 curated demo 示例现已在 auto 引擎下通过。
2. C++ 解析器语法覆盖仍有限
已提升至 26.3% 官方 CGA 可独立解析,并修复顶层注解终止等边界问题;但 enum/array/with/嵌套块/类型化属性等仍未支持,完整解析仍需 ANTLR/cgajs 兜底。
3. Native 与 cgajs 坐标/初始形状约定不一致
polygon 初始形状在 native 与 cgajs 中的轴向解释不同,导致同一组顶点在两个引擎下产生不同 footprint。需要在 API 层统一约定或做自动转换。
4. 复杂几何算法与查询差距
多边形 roofHip 需要 straight skeleton;boolean 运算、非平面 face、带洞多边形的鲁棒处理仍依赖 shapely,容易在退化输入下失败。alignScopeToGeometry 为简化实现、geometry.nFaces 为估算,与 CityEngine 真实几何仍有差距。
5. 缺少增量渲染与 Inspector 实时预览
每次参数变化都完整重算并重新生成场景,无法做到 <1s 的实时反馈。WebSocket 增量流已存在协议,但未与几何 diff 结合。
6. 测试与回归体系不完整
目前对比测试覆盖 43 个函数,距离 CityEngine 完整函数库(300+)差距大;缺少 nightly CI 与版本漂移检测。
Runtime 演进路线图
目标:在保持生产稳定的前提下,逐步扩大 Native 覆盖范围,最终接近 CityEngine 解析能力。路线图分为 4 个阶段。
Phase 1:补齐 cgajs 与 Native 基础 (进行中,cgajs Bug 已修复)
修复 cgajs-engine 中 offset / envelope / shapeU / shapeO / setback(all) 的已知 bug。已完成并重新构建部署。- 统一 polygon 初始形状在 native 与 cgajs 中的坐标约定。
将 demo 示例中所有 P1 函数在 auto 引擎下全部验证通过。已完成,43/43 P1 golden 通过。- 建立 per-function golden JSON 回归用例,覆盖 P1 43 函数。
Phase 2:扩展 Native 到 P2/P3 能力(1–2 个月)
补齐 C++ fast_parser:extension/start/style/import alias/表达式级 case/顶层赋值/函数简写/负相对数。已完成,官方 CGA 独立解析率 26.3%。- 完整实现 texture / setupProjection / projectUV / repeat / mirrorScope。
- 实现 insert 对 OBJ / glTF / glb 资产的稳定解析与路径解析。
- 引入 straight skeleton 库(polyskel)完成多边形 roofHip。
实现已完成简化版。alignScopeToGeometry简化版与geometry.*查询函数。
Phase 3:性能与 C++ 内核(2–3 个月)
- 用 Clipper2 / CGAL / earcut 替换 shapely/trimesh 热点路径。
- 实现 Shape Graph 增量 diff:参数变化仅重算受影响子树。
- 城市级批量生成管线:地块并行、glTF/3D Tiles 导出。
- 目标:单建筑 < 500ms,街区级 < 5s。
Phase 4:接近 CityEngine 完整能力(3–6 个月)
- 覆盖 CityEngine 函数库 200+ 函数。
- 支持完整的 CGA 语法(条件、循环、函数、属性继承、随机种子)。
- 视觉评估闭环:渲染图与 CityEngine 输出逐像素对比。
- 当 Native 通过率达到 95% 以上且关键规则无退化时,可将默认引擎切换为 native。
下一步立即执行项
| 优先级 | 任务 | 验收标准 | 预计周期 |
|---|---|---|---|
| 已完成 | 修复 cgajs-engine offset / envelope / shapeU / shapeO / setback(all) | 43 个 P1 golden 在 auto 引擎下全部通过 | 已落地 |
| 已完成 | 建立 per-function golden 回归测试(Omega 平台) | admin 后台新增 Omega 测试中心;支持 cgajs/native/PyPRT 三引擎批量对比与趋势图 | 已落地 |
| 已完成 | 扩展 C++ fast_parser:extension/start/style/import alias/表达式 case/顶层赋值/函数简写/负相对数 | 官方 CGA 独立解析率 26.3%(183/697) | 已落地 |
| 已完成 | 实现 import inline、alignScopeToGeometry 简化版、geometry.* 查询、NamedArg/常量懒求值、递归深度保护、字符串拼接与安全类型转换、Lark 规则参数转换 | 官方 CGA native 执行成功率 99.6%(有效 100%) | 已落地 |
| P0 | 统一 polygon 初始形状坐标约定 | 同一顶点序列在 cgajs/native 下 footprint 一致 | 2–3 天 |
| P1 | 实现多边形 roofHip straight skeleton | L/U/O/矩形屋顶均通过 PyPRT 对比 | 1–2 周 |
| P2 | Inspector 参数实时预览 MVP | 调参后 <1s 返回新场景 | 2–3 周 |
| P2 | C++ 几何内核替换热点 | offset / extrude / boolean 走 C++,性能提升 5x+ | 1 个月 |