在我上一篇文章【高性能 Web CAD Viewer:Batched Geometry 助你轻松渲染百万实体】中,我分享了 CAD-Viewer (Gitlab or Github) 如何通过将 CAD 图纸中的 Entity 进行 Geometry 合并在浏览器中实现快速渲染。这篇文章主要关注"如何高效绘制",减少 Draw Call 用并利用 GPU 友好的数据布局。
然而,Batched Geometry 只是故事的一部分。要真正有意义地渲染 CAD 图纸,我们还需要一个结构良好的渲染场景结构来统一管理所有内容。
这就是 CAD-Viewer 中 AcTrScene 类的作用。它充当 CAD 的逻辑数据模型(Layout、Layer、Entity)与渲染引擎的 GPU 友好表示(批处理几何)之间的桥梁。本文将深入介绍 AcTrScene
如何组织 CAD 图纸的可视内容,并通过具体实例进行详细解释。
读完后,你不仅会了解如何快速绘制,还会理解如何保持渲染场景清晰、结构化和可扩展------即使图纸非常复杂。
注意:
- CAD-Viewer 的代码仓库迁移到 https://github.com/mlightcad/cad-viewer 了
1. 场景结构
首先,让我们了解场景的基本结构:
bash
Scene (AcTrScene)
└── Layout (AcTrLayout) # 纸张空间或模型空间
└── Layer (AcTrLayer) # 绘图图层
└── Batched Group (AcTrBatchedGroup)
├── Line Batches # 线条、圆弧、样条、射线...
├── Mesh Batches # 填充、网格字体等
└── Point Batches # 点
Scene (AcTrScene
)
- 整个图纸的根管理器
- 保存所有 Layout 以及 Layer 的信息(存储
isOn
、isFrozen
、颜色等属性)
Layout (AcTrLayout
)
- 表示 CAD 布局(例如 Model Space
Model
或 Paper SpaceLayout1
)
Layer (AcTrLayer
)
- 容纳特定 Layout 中该 Layer 上的 Entity
- 不存储 Layer 属性( Layer 属性保存在场景管理的 Layer 列表中)
Batched Group (AcTrBatchedGroup
)
- 保存该 Layout 中该 Layer 的 Batched Geometry
- 根据类型(Line/Mesh/Point)和材质 ID 进一步分组
2. 一个简洁的 DWG 示例
为了解释如何将 DWG 图纸的结构转化为相应的渲染场景结构,我们使用以下图纸示例:
图层:
0
(CAD 默认图层;在主图纸中为空)L1
(主要几何)L2
(标注)
模型空间中的 Entity:
L1
中的 Polyline(墙轮廓)L1
中的 Hatch(地面图案)L2
中的 Point(测量标记)L1
中的 Insert(块引用):
Insert(块引用)所引用的块包含:
0
图层中的 CircleL2
图层中的 MText
3. 将 AutoCAD Entity 转换为可渲染的 Geometry
渲染引擎(如 Three.js 和 WebGPU)无法直接理解 LINE
、CIRCLE
、HATCH
或 INSERT
等 CAD Entity。cad-viewer
将所有 CAD Entity 转换为三种基本 Geometry,以便 GPU 高效渲染:
- Line:用于线状 Entity ,如 Polyline、Arc、Circle(转换为多段线)、其他 Entity 的边
- Mesh:用于填充类型的 Entity,如 Hatch、使用 TrueType/OpenType 字体的字符
- Point:用于点类型的 Entity
此转换在批处理之前进行,同时解决块和图层继承等复杂问题。
常见 Entity 的处理方式如下表所示:

3.1 Text 和 MText
AutoCAD 支持两种不同的文本技术:

转换流程:
- 从 AutoCAD 读取文本字符串、位置、旋转、样式和字体类型
- 如果字符使用 TrueType/OpenType 字体,获取字符轮廓、三角化并存储为 Mesh 到对应的 Mesh Batch
- 如果字符使用 SHX 字体,解析每个字符的笔画并存储为线段到 Line Batch
详解:
- SHX 笔画字体避免复杂三角化,渲染 CAD 图纸通常更快
- CAD 用户通常在大幅技术图纸中使用 SHX 字体,因为缩放后仍清晰且轻量
单个 MTEXT
对象可以包含多种字体。字体混合使用 TrueType/OpenType 和 SHX 字体时:
- 一个
MTEXT
可以同时为 Line Batches 和 Mesh Batches 贡献几何 - 因此,它可分布到多个批处理
示例:
MTEXT
正文使用 TrueType(如 Arial)→ 存入 Mesh Batch- 工程符号使用 SHX(如 simplex.shx)→ 存入 Line Batch
场景结构示意:
scss
Scene
└── Layout (模型空间)
└── Layer L2
└── Batched Group
├── Line Batches ← MTEXT 的 SHX 部分
├── Mesh Batches ← MTEXT 的 TrueType 部分
3.2 Table Entity
AutoCAD 的 TABLE
Entity 包含了:
- 表格结构:行列网格
- 单元格文本:通常为多行文字且包含字体样式
- 边框与单元格线
转换流程:
-
解析表格:计算每个单元格角的位置,提取边框线
-
转换:
- 所有边框线 → 存入 Line Primitives
- 单元格文字 → TrueType 转 Mesh Geometry,SHX 转 Line Geometry
-
应用每个单元格的格式(字体大小、对齐)
详解:
- 与单个 Polyline 或 Hatch 不同,
TABLE
可扩展为数百到上千个 Geometry - 通过按材质和 Geometry 类型创建相应的 Batched Geometry 来处理表格的边框和单元格文字,即使大表格也能高效渲染
3.3 Insert Entity
块参照类似可重用子图纸的实例。它引入图层继承和可见性规则,影响内容的转换。
AutoCAD 行为规则:
- 块 Entity 在
0
图层 → 继承块参照图层 - 块 Entity 在其他图层 → 保持原图层
- 关闭块参照图层 → 整个块隐藏
- 关闭块内使用的图层 → 仅隐藏对应 Entity
转换流程:
-
解析块定义,根据插入的缩放、旋转、位置转换 Entity
-
对块内每个 Entity:
- 根据继承规则确定有效图层
- 转换为 Line、Mesh 或 Point Geometry
-
将所有转换后的 Geometry 加入该 Layout 中有效图层的 Batched Groups
示意图:
scss
Layout (模型空间)
└── Layer L1
└── Batched Group
├── Line Batches ← 块内 SHX 字体、边界线
├── Mesh Batches ← 块内 TrueType 字体、填充
└── Point Batches ← 块内标记点
这确保了即使块跨多个图层或包含混合字体,最终渲染也能保持准确。
3.4 总结
根据这些规则,在 AutoCAD 中看起来"在一起"的 Entity,可能会在场景中被拆分多个图层、多个 Batched Geometry中:
- 一个单独的 INSERT 可能会生成多个 Line Geometry 、Mesh Geometry 、Point Geometry ,分散在 多个图层 的 Batched Geometry 中。
- 一个 TABLE 会展开成许多 Line Geometry 和 Mesh Geometry ,分散在 单个图层 的多个 Batched Geometry 中。
- 一个 TEXT 对象可能会变成多个 Line Geometry (如果是 SHX 字体)或 Mesh Geometry (如果是 TrueType 字体),分散在 单个图层 的多个 Batched Geometry 中。
正是这种精细化的组织,使 cad-viewer 能够利用 GPU 实例化技术,并在复杂注释和可重用内容丰富的图纸中保持高帧率。
4. 示例图纸的场景结构
以下是示例图纸的场景结构:
bash
Scene (AcTrScene)
├── Layout: Model Space (AcTrLayout)
│ ├── Layer "0" (AcTrLayer)
│ │ └── Batched Group
│ │ ├── Line Batches # (空)
│ │ ├── Mesh Batches # (空)
│ │ └── Point Batches # (空)
│ │
│ ├── Layer "L1" (AcTrLayer)
│ │ └── Batched Group
│ │ ├── Line Batches
│ │ │ └── [Polyline geometry] # 墙体轮廓
│ │ │ └── [Polyline geometry] # 来自块的圆
│ │ ├── Mesh Batches
│ │ │ └── [Hatch geometry] # 地面图案
│ │ └── Point Batches # (空)
│ │
│ └── Layer "L2" (AcTrLayer)
│ └── Batched Group
│ ├── Line Batches # (空)
│ ├── Mesh Batches
│ │ └── [Text geometry] # 来自块
│ └── Point Batches
│ └── [Point entity] # 测量标记
│
└── Layout: Paper Space (AcTrLayout) # 此示例为空
├── Layer "0" (AcTrLayer) # 存在但为空
├── Layer "L1" (AcTrLayer) # 存在但为空
└── Layer "L2" (AcTrLayer) # 存在但为空
理解转换后的场景
- 每个布局(Layout)都有自己的一组
AcTrLayer
对象。 - 每个
AcTrLayer
包含一个AcTrBatchedGroup
,只包含渲染所需的图元类型。 - 块引用中的圆进入 L1 的 Line Batches 中。
- 块中的文本进入 L2 的 Mesh Batches。
- Point 保持在 L2 的 Point Batches 中。
- Hatch 和 Polyline 保留在 L1 的 Batches 中。
此结构反映了 CAD 的图层语义,同时经过优化以提升渲染性能:使用相同图层、图元类型和材质的实体可以合并为单个批次绘制,从而最小化绘制调用(draw calls)。
5. 场景中的图层 vs. DWG 文件中的图层
在 DWG 文件中:
- 图层是全局的:只有一组图层,每个图层都有属性,如
isOn
、isFrozen
、颜色等。
在场景中:
- 每个布局为每个 DWG 图层创建自己的
AcTrLayer
实例。 - 因此,两个布局(Model, Paper)和三个图层(0, L1, L2)会生成 6 个
AcTrLayer
对象。 - 实际的图层属性存储在
AcTrScene
中,而不是每个AcTrLayer
,确保切换可见性或冻结图层时,对所有布局都一致生效。 - 每个
AcTrLayer
只是特定布局中批次的容器。
这种分离方式让我们可以保持渲染数据的布局友好性,同时维护 CAD 一致的全局图层行为。
6. 处理块引用(INSERT)------棘手部分
块引用(INSERT 实体)是 CAD 渲染中最微妙的部分之一。AutoCAD 的行为说明了原因:
假设块包含:
- E1 在层 0
- E2 在层 L1
- E3 在层 L2
你将该块插入到层 L1(块引用所在的层)。
情况 1:关闭图层 L1
- 块引用本身在 L1。
- 关闭 L1 后,整个块引用消失,无论其内容在哪个图层。
结果:整个块隐藏。
情况 2:关闭图层 L2
- 块引用仍在 L1(L1 保持开启)。
- 块内:
- E1(在 0)→ 继承块的图层 L1,可见
- E2(在 L1)→ 可见
- E3(在 L2)→ 隐藏
结果:块引用可见,但内容中在 L2 的部分消失。
cad-viewer 的处理方式
渲染块引用时,
- 插入对象自身的图层影响整个块的可见性。
- 内部实体根据继承规则确定的有效图层贡献几何到相应的批次中。
这确保渲染遵循 CAD 的可见性语义,同时将几何放置在 GPU 批处理的合适位置。
7. 为什么这种场景结构可行
- 性能:按布局 → 图层 → 批次类型 → 材质分组,最小化绘制调用和 GPU 状态切换。
- 可扩展性:场景结构在图纸变大、变复杂时仍能很好地扩展,同时与 CAD 概念紧密对应。
- 一致性:图层属性统一存储在场景级别,应用一致。
- 可维护性:开发者可以轻松从 CAD 概念(Layout、Layer、Entity)导航到渲染数据。
8. 结束语
在上一篇文章中,我们重点讨论了如何使用 Batched Geometry 以提升性能。本篇文章探讨了如何将 CAD Entity 转换为可渲染图元,并在场景中组织它们。
- 转换步骤是 CAD 语义与 GPU 效率之间的桥梁。
- 理解它后,带有布局、图层和批次的场景结构图会更直观。
- 转换 + 场景组织 + Batched Geometry 让 cad-viewer 既忠实于 AutoCAD 数据模型,又高度优化用于 Web CAD 浏览。
如果想深入实现,或亲自尝试,可查看我的开源项目源代码:
- 👉 Github:github.com/mlightcad/c...
- 👉 Gitlab:gitlab.com/mlightcad/c...