🧪 Omega Test 文档
核心目标:通过 CityEngine 导出的 OBJ 生成黄金标准 JSON,精确对比 CGA.js 引擎与 CityEngine 的函数解析精度。本文档是 Omega 测试体系的唯一权威来源,配置维度调整将在此同步更新。
1. 概述
Omega Test 是 CGA.js 引擎的黄金标准对比测试框架。它的工作原理是:
- 在 CityEngine 中应用一个 CGA 规则(如
extrude(10))到标准 footprint - 导出最终 3D 模型为 Wavefront OBJ 格式
- 通过 Omega 工具上传 OBJ,填写完整的元数据
- 自动生成包含几何数据、Scope、对比策略的黄金标准 JSON
- 将 JSON 放入测试套件,对比 CGA.js 引擎的输出
1.1 测试基础设施
/api/v1/omega/convert 接收 OBJ + 元数据,调用 obj_to_json.py 解析并组装完整 JSON。
1.2 架构级修补(8 项核心基础设施)
| 模块 | 说明 | 状态 |
|---|---|---|
unit_system | 单位配置(米/英尺/厘米),GlobalUnits 单例 | ✅ 已创建,待接入几何函数 |
crs | 坐标系管理,CRSConfig | ✅ 已创建 |
random | Park-Miller LCG 确定性随机,GlobalRNG | ✅ 已创建 |
scope_matrix | 正交归一化验证与修复 | ✅ 已创建 |
attribute_system | 属性注入与继承,GlobalAttributes | ✅ 已创建 |
comp_labels | 组件面标签系统(top/bottom/left/right/front/back) | ✅ 已创建 |
error_handler | 诊断日志与错误分级 | ✅ 已创建 |
uv_system | UV 投影系统,GlobalUVProjections | ✅ 已创建 |
2. 黄金标准 JSON 结构
Omega 工具生成的 JSON 包含 5 个顶级字段:
{
"_meta": { ... }, // 测试元数据(函数、参数、版本、运行环境、对比策略)
"cga": "Lot --> extrude(10)", // CGA 规则源码
"input": { ... }, // 初始 Shape(vertices + faces + scope + pivot)
"expected": { ... }, // CityEngine 输出的几何数据
"notes": { ... } // 关键检查项、CE 行为说明、边界标签
}
2.1 _meta — 测试元数据
| 字段 | 类型 | 说明 |
|---|---|---|
function | string 必填 | 被测函数名,如 extrude, roofHip, setback |
params | array | 函数参数 JSON 数组,如 [10] 或 [30, "shape=L"] |
input_shape | string 必填 | 输入形状类型:square / rectangle / L_shape / U_shape / concave / with_hole |
description | string | 测试用例目的描述 |
source | string | CityEngine 版本:CityEngine_2021.1 ~ 2025.1 |
exported_by | string | 转换工具标识,固定为 omega-converter |
version | number | JSON 格式版本,当前为 1 |
runtime | object | 运行环境配置,见 §3.3 |
comparison | object | 对比策略配置,见 §3.4 |
2.2 input — 初始 Shape
"input": {
"vertices": [
{"x": 0, "y": 0, "z": 0},
{"x": 10, "y": 0, "z": 0},
{"x": 10, "y": 0, "z": 10},
{"x": 0, "y": 0, "z": 10}
],
"faces": [
{"indices": [0,1,2,3], "normal": {"x":0,"y":1,"z":0}}
],
"scope": {"sx":10, "sy":0, "sz":10,
"tx":0, "ty":0, "tz":0,
"rx":0, "ry":0, "rz":0},
"pivot": {"x":0, "y":0, "z":0}
}
2.3 expected — CityEngine 输出
"expected": {
"vertex_count": 24,
"face_count": 10,
"vertices": [[0,0,0], [10,0,0,] ...],
"faces": [[0,1,2], [0,2,3], ...],
"bbox": {
"min": {"x": 0, "y": 0, "z": 0},
"max": {"x": 10, "y": 10, "z": 10}
},
"scope": {"sx":10, "sy":10, "sz":10}
}
2.4 notes — 测试备注
"notes": {
"critical_checks": [
"顶点数应为8(4底+4顶)",
"面数应为6(4侧+顶+底)",
"顶面法向必须向上(0,1,0)"
],
"obj_precision_warning": "顶点坐标精度受限于OBJ格式(6位小数),对比时使用 epsilon=1e-4",
"cityengine_behavior": {
"overhang": 0.5,
"miter_limit": 0.3,
"known_cityengine_behavior": "CityEngine在L形凹角处会生成内部脊线",
"cgajs_approximation": "当前为简化实现,未处理凹角缝合",
"boundary_tags": ["extreme_ratio"]
}
}
3. 配置维度总览
Omega 工具从几何、运行环境、对比策略、CityEngine 特殊行为四个维度采集 20+ 个配置项。精确填写这些字段是测试可信度的关键。
3.1 基础元数据
| 字段 | Omega 表单位置 | 用途与填写建议 |
|---|---|---|
function |
函数名 * | 被测函数名。必须使用引擎内部注册的函数名(如 roofHip 而非 roof_hip)。 |
params |
参数 (JSON 数组) | 函数参数。屋顶函数的 overhang 参数需单独在 overhang 字段中记录。 |
input_shape |
输入形状 | 从下拉菜单选择。如果使用自定义 footprint(非 6 种预设),选择最接近的类型并在描述中说明。 |
ce_version |
CityEngine 版本 | 精确到 minor 版本(如 2023.1)。不同版本的三角化策略可能存在差异。 |
cga |
CGA 规则 | 完整的 CGA 规则源码。用于复现和文档记录。 |
description |
描述 | 一句话说明此测试用例的目的。例如:"验证 extrude 在 10m 高度下的顶点分布"。 |
critical_checks |
关键检查项 | 每行一个检查点。这是测试失败时最重要的诊断线索。 |
3.2 初始 Scope 配置(⚙️ 高级)
为什么重要? 很多引擎实现只测试了轴对齐、无旋转、原点的 trivial 情况。实际 CityEngine 中 footprint 可能是旋转过的,如果引擎内部错误地使用了世界坐标而非局部 Scope 坐标,结果会完全不同。
| 字段 | 默认值 | 测试意义 |
|---|---|---|
scope.rx / ry / rz |
0° | Scope 旋转角度。roofGable 的脊线方向、split(x) 的轴向判断、comp(f) 的面法向分类对此敏感。 |
scope.tx / ty / tz |
0 | 世界坐标平移。验证函数在非原点输入下是否行为一致。 |
scope.sx / sy / sz |
1.0 | 非均匀缩放。extrude 后 scale(2,1,1) 再 split 是否按新尺寸切分。 |
推荐 Scope 测试矩阵
| 测试场景 | rx | ry | rz | tx | ty | tz | sx | sy | sz |
|---|---|---|---|---|---|---|---|---|---|
| 基准(默认) | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
| Y轴旋转45° | 0 | 0 | 45 | 0 | 0 | 0 | 1 | 1 | 1 |
| 非均匀缩放 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0.5 | 1 |
| 远离原点 | 0 | 0 | 0 | 100 | 50 | -30 | 1 | 1 | 1 |
| 组合变换 | 15 | 0 | 30 | 10 | 0 | 5 | 1.5 | 1 | 2 |
3.3 运行环境(🔧 高级)
| 字段 | 默认值 | 用途 |
|---|---|---|
seedian |
12345 | 随机种子,控制 p() / rand() 的确定性序列。同一个 CGA 规则用不同种子应产生不同但各自确定的结果。 |
max_recursion_depth |
300 | 复杂嵌套规则(如 A --> B --> A --> B...)的终止条件。CityEngine 默认值约为 300。 |
attributes |
{} |
外部注入 attr 值(如 attr height = 20 从 GIS/Shapefile 读取)。JSON 对象格式。 |
unit |
meter | 当前固定为 meter。单位系统已创建但未接入几何函数(默认米制无影响)。 |
3.4 对比策略(📏 高级)
这是避免"假阳性"失败的关键。 如果强制所有函数都用 vertex_exact + epsilon=1e-4,roof 系列几乎不可能通过(CityEngine 的三角化策略和我们不同)。分层对比策略是"精准测试"的核心。
| 字段 | 选项 | 说明 |
|---|---|---|
epsilon |
1e-4 / 1e-3 / 0.01 |
顶点坐标容差(米)。简单几何用 1e-4;roof 系列用 1e-3(OBJ 导出已有精度损失)。 |
mode |
vertex_exact / bbox / topology / bbox+vertex |
vertex_exact:顶点坐标逐点对比(最严格) bbox:只比包围盒(最宽松,用于近似验证) topology:只比面数/顶点数/拓扑连通性 bbox+vertex:先比 BBox 再比顶点(推荐平衡策略) |
ignore |
数组 | 可选项:normals / uvs / colors / scope_rotation。CityEngine 和我们的法线计算策略可能不同。 |
3.5 CityEngine 特殊行为(🏗️ 高级)
| 字段 | 类型 | 说明 |
|---|---|---|
overhang |
number | 屋顶悬挑距离(roofHip(30, 1.0) 中的 1.0)。影响 roof 系列的顶面尺寸。 |
miter_limit |
number | offset / setback 的斜接限制,影响凹角处的面生成策略。 |
known_cityengine_behavior |
string | CityEngine 的特殊行为描述。例如:"CityEngine 在 L 形凹角处会生成内部脊线"。 |
cgajs_approximation |
string | 我们当前实现的已知近似/简化。例如:"当前为简化实现,未处理凹角缝合"。 |
3.6 边界条件标签
| 标签 | 触发条件 | CityEngine 预期行为 |
|---|---|---|
zero_size |
输入尺寸为零(如 extrude(0)) |
退化为二维面或空几何,不崩溃 |
degenerate |
退化多边形(共线顶点、零面积面) | 自动剔除退化面,保留有效部分 |
extreme_ratio |
极端长宽比(>100:1 或 <1:100) | 正常生成,数值稳定 |
negative_param |
负参数(如 extrude(-5)) |
方向反转或报错(视函数而定) |
overflow |
尺寸溢出浮点精度(>1e6 或 <1e-6) | 不生成 NaN/Inf |
setback 在退台距离大于 footprint 尺寸时,CityEngine 会退化为一条线而不是崩溃。记录这些边界行为,才能确保我们的引擎也优雅降级而不是抛异常。
4. CityEngine OBJ 导出设置详细指南
OBJ 是 Omega 测试的唯一输入格式。正确的导出设置直接决定黄金标准 JSON 的质量和对比可信度。
核心原则:一个 OBJ = 一个函数 + 一个输入 Shape 的最终结果。不要在一个 OBJ 中包含多个模型或多个生成阶段的几何。
4.1 导出前准备
- 在 CityEngine 中写好最小 CGA 规则,确保只调用一个目标函数(如
extrude(10)) - 选中场景中的初始 Shape(footprint),应用规则(Generate)
- 在 Scene 窗口中,只选中最终生成的 3D 模型(不要选中初始 footprint)
- 菜单栏 →
File→Export Models...
4.2 基础设置(General)
| 参数 | 推荐设置 | 说明 |
|---|---|---|
| Format | Wavefront OBJ |
我们的解析器专为此格式优化。不支持 FBX/DAE/COLLADA。 |
| File | {函数}_{参数}_{形状}.obj |
命名规范例:extrude_10_square.obj、roofHip_30_Lshape.obj |
| Export selected models only | ✅ 勾选 | 避免导出场景中其他模型导致几何混杂。 |
| Coordinate system | Cartesian(默认) |
保持与引擎一致的直角坐标系。 |
| Up axis | Y |
我们的引擎使用 Y-up。不要选 Z-up,否则屋顶方向会完全相反。 |
4.3 几何设置(Geometry)
| 参数 | 推荐设置 | 说明 |
|---|---|---|
| Triangulate geometry | ⚠️ 视函数而定 | 见 §4.5 三角化策略。 |
| Merge geometry | ✅ 勾选 | 将同一模型的所有 mesh 合并为一个 object。避免多 object 导致面索引混乱。 |
| Precision | 6 或更高 |
默认 6 位小数足够。roof 系列建议 8(斜面顶点对精度敏感)。 |
| Scale | 1.0 |
不要缩放,保持原始单位(米)。 |
4.4 法线与 UV(Normals & Texture Coordinates)
| 参数 | 推荐设置 | 说明 |
|---|---|---|
| Export normals | ✅ 勾选 | 生成 vn 数据。我们的解析器支持,且可在对比时选择忽略法线。 |
| Export texture coordinates | ✅(如涉及 UV 函数) ❌(纯几何函数) |
setupProjection / texture / color 相关测试需要 UV。 |
| Normal type | Vertex normals(默认) |
每顶点法线,与 Three.js 的 BufferGeometry 一致。 |
4.5 材质(Materials)
| 参数 | 推荐设置 | 说明 |
|---|---|---|
| Export materials | ❌ 不勾选 | 黄金标准测试只关注几何。材质会增加文件体积且无意义。解析器会跳过 usemtl。 |
4.6 三角化策略(最关键)
这是最容易导致面数不一致的问题。CityEngine 对某些面保持四边形,对其他面自动三角化。我们的解析器支持多边形(face indices > 3),但对比时的 faceCount 必须严格一致。
| 测试函数 | Triangulate | 原因 |
|---|---|---|
extrude |
❌ 不勾选 | 生成的侧面和顶/底面通常是规整的四边形。保持四边形,面数 = 4 侧面 + 2 端面 = 6。 |
split |
❌ 不勾选 | 切分后的面保持四边形。三角化会导致面数不可预测地翻倍。 |
comp(f) |
❌ 不勾选 | 组件分离后的面保持原始形状。 |
setback |
❌ 不勾选 | 退台后的面保持多边形。 |
offset |
❌ 不勾选 | 偏移后的面保持多边形。 |
roofHip |
✅ 勾选 | 屋顶函数 CityEngine 内部会三角化。如果不勾选,对比时面数可能不一致。 |
roofGable |
✅ 勾选 | 同上。三角面是 roof 系列的内部表示。 |
roofPyramid |
✅ 勾选 | 金字塔屋顶必然三角化。 |
roofShed |
✅ 勾选 | 单坡屋顶通常三角化。 |
primitive 系列 |
✅ 勾选 | 圆柱/球体/圆锥 CityEngine 会参数化三角化。 |
验证方法:导出后打开 OBJ 文件,检查f行。如果每行有 3 个索引(如f 1 2 3),说明是三角化;如果有 4 个(如f 1 2 3 4),是四边形。我们的解析器两者都支持。
4.7 导出后验证清单
导出完成后,在文本编辑器中打开 OBJ 文件,确认以下结构存在:
# 顶点坐标(至少3列,X Y Z)
v 0.000000 0.000000 0.000000
v 10.000000 0.000000 0.000000
v 10.000000 0.000000 10.000000
v 0.000000 0.000000 10.000000
# 法线(如果勾选了导出法线)
vn 0.000000 1.000000 0.000000
# 面索引(1-based,我们的解析器会自动转为 0-based)
# 四边形格式
f 1 2 3 4
# 或三角化格式
f 1 2 3
f 1 3 4
常见问题排查
| 现象 | 原因 | 解决 |
|---|---|---|
OBJ 里只有 v 没有 f |
选中了初始 footprint 而非最终模型 | 重新选中最终生成的 3D 模型再导出 |
| 坐标值特别大(如 10000+) | 坐标系未投影 / 使用了地理坐标 | 确保 Shape 是米制直角坐标,或检查 Scene 的 Coordinate System |
f 行包含负数索引(如 f -1 -2 -3) |
CityEngine 某些版本的特殊导出 | 我们的解析器不支持负数索引,需要手动改为正数 |
多个 o (object) 块 |
未勾选 Merge geometry | 勾选后重新导出,或手动删除多余的 object 块 |
面索引包含 v/vt/vn 但我们不需要 vt/vn |
OBJ 标准格式,不影响 | 我们的解析器完全支持 v/vt/vn、v//vn、v/vt、v 四种格式 |
4.8 与 Omega.html 的字段映射
| CityEngine 设置 | Omega.html 对应字段 |
|---|---|
| 是否 Triangulate | notes.cityengine_behavior.known_cityengine_behavior(如"CityEngine 对 roof 面进行了三角化") |
| Export normals 勾选状态 | ignoreTags → 若未导出法线则勾选"忽略法线对比" |
| 坐标异常大 | boundary_tags → 勾选"尺寸溢出" |
| 实际单位不是米 | runtime.unit → 改为实际单位 |
5. 函数推荐配置速查表
当您为具体函数创建黄金标准时,可直接套用下表的推荐配置:
| 函数 | compareMode | epsilon | Triangulate | 必须测试的边界条件 |
|---|---|---|---|---|
extrude |
vertex_exact |
1e-4 |
❌ | 零高度、负高度、非均匀 footprint |
split |
vertex_exact |
1e-4 |
❌ | 尺寸之和>1、尺寸之和<1、浮动~尺寸、零宽度切分 |
comp(f) |
topology |
1e-4 |
❌ | 所有 6 个面方向(top/bottom/left/right/front/back) |
comp(e) |
vertex_exact |
1e-4 |
❌ | 边界边、共享边、退化边 |
comp(v) |
vertex_exact |
1e-4 |
❌ | 所有顶点位置 |
roofHip |
bbox+vertex |
1e-3 |
✅ | 凹角、带孔洞、极端长宽比、不同 overhang |
roofGable |
bbox+vertex |
1e-3 |
✅ | 脊线方向、非矩形 footprint |
roofPyramid |
bbox+vertex |
1e-3 |
✅ | 非正方形底面、极扁/极高 |
setback |
vertex_exact |
1e-4 |
❌ | 退台>尺寸、凹多边形、零退台、极大退台 |
offset |
vertex_exact |
1e-4 |
❌ | 内缩导致退化、斜接限制、负偏移 |
shapeL / shapeU / shapeO |
vertex_exact |
1e-4 |
❌ | 参数边界(如 L 的退台为 0 或等于边长) |
primitive 系列 |
bbox+vertex |
1e-3 |
✅ | 分段数、半径为 0、高度为 0 |
color / set |
topology |
1e-4 |
❌ | 几何不变,只验证属性传递 |
texture / setupProjection |
vertex_exact |
1e-4 |
❌ | UV 范围、投影方向、重复模式 |
rotate / translate / scale |
vertex_exact |
1e-4 |
❌ | 组合变换、零缩放、负缩放 |
nil |
topology |
1e-4 |
— | 几何为空,验证规则终止 |
6. 完整测试流程
-
编写最小 CGA 规则
只包含一个目标函数,例如:
Lot --> extrude(10)或Lot --> roofHip(30, 0.5) -
选择或创建标准 footprint
在 CityEngine 中选中初始 Shape → Generate。
如果 footprint 不在 6 种预设内,可在 Omega 工具中手动填写 vertices + faces。 -
选中最终模型并导出
Scene 窗口中只选中最终 3D 模型(高亮状态)。
File → Export Models → Wavefront OBJ,按 §4 设置参数。 -
命名文件
{函数}_{参数}_{形状}.obj,例:roofHip_30_Lshape.obj -
快速验证 OBJ 内容
文本编辑器打开,确认有v、f行,且f的索引数量符合三角化策略。 -
上传 Omega 工具并填写元数据
访问 /omega.html,拖拽上传 OBJ。
按 §3 精确填写所有配置维度。 -
生成并下载 JSON
点击"开始转换",验证 JSON 内容完整后下载。
文件名自动为:{函数名}_{OBJ文件名}.json -
放入测试套件
将 JSON 放入/omega-test/cases/tier_s/目录,编写对应的.test.ts用例。 -
运行对比测试
cd /omega-test && npm test。观察是否通过,根据 errors/warnings 修复引擎。 -
记录已知差异
如果 CityEngine 行为与引擎输出有预期内的差异(如三角化策略不同),在notes.cityengine_behavior中记录,并调整comparison.ignore或comparison.mode。
7. 常见问题
Q1: 为什么 vertex_exact 模式下 roof 系列总是失败?
CityEngine 的 roof 函数内部使用参数化曲面 + 自适应三角化,其顶点分布策略(如脊线细分、边缘插值)与我们的简化实现不同。即使几何形状正确,顶点顺序和细分密度也可能不同。
解决:将 compareMode 改为 bbox+vertex,epsilon 放宽到 1e-3,并在 notes 中记录三角化策略差异。
Q2: 面数一致但顶点数不一致,是什么原因?
CityEngine 在导出时可能对共享顶点进行去重或复制,导致同样的几何有不同的顶点数。OBJ 格式本身不强制共享顶点。
排查:
- 检查是否勾选了 Merge geometry(未合并可能导致重复顶点)
- 检查 OBJ 中是否有重复的
v行(CityEngine 有时会复制顶点以支持硬边法线) - 如果顶点数差异在可接受范围(如 ±4 以内),考虑改用
topology模式
Q3: 同一个 CGA 规则,不同 CityEngine 版本导出的 OBJ 不一样?
是的。CityEngine 在 2022.x → 2023.x 之间对 roof 函数的三角化策略有调整。2024.x 引入了新的曲面细分算法。
建议:
- 固定一个主版本作为黄金标准(推荐 2023.1,稳定性好)
- 在
_meta.source中精确记录版本号 - 如果多版本差异大,可为同一函数生成多个 JSON(如
roofHip_2023.json和roofHip_2025.json)
Q4: 我可以不用 CityEngine,用 Blender / Rhino 生成 OBJ 吗?
不推荐。 Omega 测试的核心是"与 CityEngine 行为一致"。Blender/Rhino 的几何生成逻辑与 CityEngine 完全不同(如 roof 的脊线计算、setback 的倒角策略)。
如果您没有 CityEngine,可以:
- 联系我们获取已有的黄金标准 JSON
- 使用预设 footprint + 手动计算 expected 值(仅限简单函数如 extrude)
- 将
_meta.source标记为manual_calculation并在notes中说明
Q5: OBJ 文件太大(>10MB)怎么办?
如果 CityEngine 生成了极高细分的几何(如 primitiveCylinder 的 segments 过多),JSON 会很大。
建议:
- 使用简化的 CGA 规则参数(如减少 cylinder 的 segment 数)
- 在 Omega 工具中,JSON 生成是服务器端处理,10MB 以内通常无问题
- 如果超过 20MB,考虑只保留关键几何特征,或分段导出
8. 变更记录
本文档是 Omega 测试体系的唯一权威来源。所有配置维度的调整将在此同步更新。
| 版本 | 日期 | 变更内容 |
|---|---|---|
v3.1 |
2026-06-03 |
新增:运行环境配置(seedian/maxRecursion/attributes/unit)、对比策略(epsilon/mode/ignore)、CityEngine 特殊行为(overhang/miter_limit/known_behavior/boundary_tags)、初始 Scope 微调(rx/ry/rz/tx/ty/tz/sx/sy/sz)。 新增:6 种标准 footprint 预设(正方形/长方形/L形/U形/极小/极大)。 修复:OBJ 解析器兼容 legacy flat format( {vertices:[]})和 undefined geometry。文档:创建本文档页面 omega-docs.html。
|
v3.0 |
2026-06-02 |
新增:Omega Test 基础设施(geometry_comparator, shape_factory, golden/boundary/regression runners)。 新增:8 项架构级核心修补(unit_system, crs, random, scope_matrix, attribute_system, comp_labels, error_handler, uv_system)。 新增:OBJ → JSON 工具链( obj_to_json.py)。新增:Omega 前端工具(拖拽上传 + 自动转换 + 黄金标准 JSON 生成)。 |
v2.x |
2026-05 | IDE 三维解析修复、terser property mangling 移除、初始 Shape 空值崩溃修复、NL2CGA 预留接口。 |
v1.x |
2026-04 | 引擎基础架构、ANTLR4 CGA 解析器、Three.js 渲染管线、FastAPI 后端、前端 IDE。 |
如何追踪变更:本文档托管于/www/wwwroot/www.cgajs.com/omega-docs.html,源码版本与omega.html的.footer中的版本号保持一致(当前 v3.1)。如有配置维度变更,将在此表格追加记录并提升版本号。