mcpField
T
threejs-impl-ifc-viewer

threejs-impl-ifc-viewer

github.com/impertio-studio开发23131 次安装30 周前更新
代码仓库

关于 threejs-impl-ifc-viewer

这是使用 Three.js 实现 IFC 解析和 BIM 查看器的参考技能。它对比底层 web-ifc API 与高层 @thatopen/components 工具包,并介绍几何、属性和内存管理模式。

主要功能

  1. 01web-ifc 与 @thatopen/components 方案对比
  2. 02IFC 几何与属性提取参考
  3. 03BIM 查看器组件用法
  4. 04大型 IFC 模型内存管理
  5. 05弃用库与许可证注意事项

适用场景

  1. 01为自定义 Three.js 管线提取 IFC 几何
  2. 02构建含构件选择和剖切面的 BIM 查看器
  3. 03读取 IFC 构件属性而不渲染几何
  4. 04规划大型 IFC 文件的分批加载

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/impertio-studio/three.js-claude-skill-package --skill threejs-impl-ifc-viewer

安装后在 Claude Code 中输入/threejs-impl-ifc-viewer确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

.gitkeep
references/
anti-patterns.md
examples.md
methods.md

详细介绍

threejs-impl-ifc-viewer

快速参考

库对比
库许可证级别状态使用场景
web-ifcMIT底层 WASM 解析器活跃(v0.77+)自定义流水线、完全控制
@thatopen/componentsMIT(v3.x)高层 BIM 工具包活跃(v3.3.2+)完整 BIM 查看器、快速原型开发
@thatopen/components-frontMIT浏览器专用扩展活跃UI、高级可视化
web-ifc-three—已弃用的桥接库已停止维护切勿使用
openbim-components(v1)—已弃用的工具包已停止维护切勿使用
包安装
# Low-level approach (MIT, full control)
npm install web-ifc three

# High-level approach (MIT, batteries-included)
npm install @thatopen/components @thatopen/components-front web-ifc three
重要警告

许可证历史警告:@thatopen 软件包(v3.x)采用 MIT 许可证。不过,较早的 IFC.js 生态系统软件包(openbim-components v1、IFC.js v0.x)采用 AGPL-3.0 许可证。务必核实所安装的确切软件包版本的许可证。如果使用任何采用 AGPL-3.0 许可证的软件包,整个应用程序都必须以 AGPL-3.0 或兼容许可证开源。

切勿使用 web-ifc-three——它已弃用且无人维护。请改用 web-ifc 或 @thatopen/components。

切勿使用 openbim-components(v1)——它已弃用。请改用 @thatopen/components(v3.x)。

切勿一次性加载超过 50MB 文件中的全部 IFC 几何体——务必采用流式处理或按需加载几何体。WASM 内存有限,且无法回收,除非重新加载页面。

切勿在处理完成后忘记调用 ifcApi.CloseModel(modelID)——WASM 内存泄漏将持续存在,直到重新加载页面。

卸载 @thatopen 查看器时,务必调用 components.dispose()——否则会造成 GPU 内存、Three.js 对象和事件侦听器泄漏。

务必异步初始化 IfcAPI——在执行任何模型操作之前,必须先完成 await ifcApi.Init()。


方法 1:web-ifc(底层 WASM 解析器)

适用场景
  • 需要完全控制几何体提取和渲染
  • 正在构建自定义渲染流水线
  • 只想使用 MIT 许可证的代码
  • 需要提取 IFC 属性,但不渲染几何体
WASM 设置
import * as WebIFC from 'web-ifc';

const ifcApi = new WebIFC.IfcAPI();
ifcApi.SetWasmPath('./');  // MUST point to directory containing web-ifc.wasm
await ifcApi.Init();       // ALWAYS await before any operations

WASM 文件要求:web-ifc.wasm 文件必须从浏览器可访问的位置提供。将其从 node_modules/web-ifc/ 复制到 public/static 目录。Vite 等打包工具需要显式配置才能提供 WASM 文件。

IfcAPI 核心方法
方法签名说明
Init()() => Promise<void>初始化 WASM 模块
SetWasmPath(path)(string) => void设置包含 .wasm 文件的目录
OpenModel(data, settings?)(Uint8Array, object?) => number加载 IFC 数据,返回 modelID
CloseModel(modelID)(number) => void释放模型内存
GetGeometry(modelID, expressID)(number, number) => object获取元素的几何体
GetFlatMesh(modelID, expressID)(number, number) => FlatMesh获取扁平化网格数据
GetPlacedGeometry(modelID, pg)(number, PlacedGeometry) => MeshData获取带变换的已定位几何体
GetLine(modelID, expressID, flatten?)(number, number, boolean?) => object按 expressID 读取单个 IFC 实体
GetAllLines(modelID)(number) => number[]获取模型中的所有 express ID
GetLineIDsWithType(modelID, type)(number, number) => number[]按 IFC 类型常量获取 ID
GetAllTypesOfModel(modelID)(number) => TypeInfo[]列出模型中的所有实体类型
几何体提取模式
const modelID = ifcApi.OpenModel(ifcData); // ifcData: Uint8Array

const wallIDs = ifcApi.GetLineIDsWithType(modelID, WebIFC.IFCWALL);
for (const wallID of wallIDs) {
  const flatMesh = ifcApi.GetFlatMesh(modelID, wallID);
  for (const pg of flatMesh.geometries) {
    const meshData = ifcApi.GetPlacedGeometry(modelID, pg);
    // meshData.vertexData: Float32Array (interleaved position + normal, 6 floats per vertex)
    // meshData.indexData: Uint32Array (triangle indices)
    // pg.flatTransformation: Float64Array (4x4 column-major matrix)
    // pg.color: { x: r, y: g, z: b, w: alpha } (0-1 range)
  }
}

ifcApi.CloseModel(modelID); // ALWAYS release when done
将 web-ifc 几何体转换为 Three.js
import * as THREE from 'three';

function ifcMeshToThree(meshData, placedGeometry) {
  const { vertexData, indexData } = meshData;

  // vertexData is interleaved: [px, py, pz, nx, ny, nz, px, py, pz, nx, ny, nz, ...]
  const posFloats = new Float32Array(vertexData.length / 2);
  const normFloats = new Float32Array(vertexData.length / 2);
  for (let i = 0; i < vertexData.length; i += 6) {
    const j = i / 2;
    posFloats[j]     = vertexData[i];
    posFloats[j + 1] = vertexData[i + 1];
    posFloats[j + 2] = vertexData[i + 2];
    normFloats[j]     = vertexData[i + 3];
    normFloats[j + 1] = vertexData[i + 4];
    normFloats[j + 2] = vertexData[i + 5];
  }

  const geometry = new THREE.BufferGeometry();
  geometry.setAttribute('position', new THREE.BufferAttribute(posFloats, 3));
  geometry.setAttribute('normal', new THREE.BufferAttribute(normFloats, 3));
  geometry.setIndex(new THREE.BufferAttribute(indexData, 1));

  const { x: r, y: g, z: b, w: a } = placedGeometry.color;
  const material = new THREE.MeshPhongMaterial({
    color: new THREE.Color(r, g, b),
    opacity: a,
    transparent: a < 1,
    side: THREE.DoubleSide,
  });

  const mesh = new THREE.Mesh(geometry, material);

  // Apply the 4x4 transform matrix (column-major)
  const mat = new THREE.Matrix4();
  mat.fromArray(placedGeometry.flatTransformation);
  mesh.applyMatrix4(mat);

  return mesh;
}
IFC 属性提取
// Read a specific entity
const wall = ifcApi.GetLine(modelID, wallExpressID, true); // flatten=true resolves references
console.log(wall.Name?.value);       // "Basic Wall:Generic - 200mm"
console.log(wall.GlobalId?.value);   // IFC GUID

// Get all property sets for an element
const relDefines = ifcApi.GetLineIDsWithType(modelID, WebIFC.IFCRELDEFINESBYPROPERTIES);
for (const relID of relDefines) {
  const rel = ifcApi.GetLine(modelID, relID, false);
  // Check if this relation references our element
  // rel.RelatedObjects contains expressIDs of related elements
  // rel.RelatingPropertyDefinition points to the property set
}
IFC 类型常量
常量IFC 实体
WebIFC.IFCWALL墙体
WebIFC.IFCWALLSTANDARDCASE标准墙体
WebIFC.IFCSLAB楼板/地板
WebIFC.IFCCOLUMN柱
WebIFC.IFCBEAM梁
WebIFC.IFCDOOR门
WebIFC.IFCWINDOW窗户
WebIFC.IFCROOF屋顶
WebIFC.IFCSTAIR楼梯
WebIFC.IFCSPACE空间/房间
WebIFC.IFCSITE场地
WebIFC.IFCBUILDING建筑
WebIFC.IFCBUILDINGSTOREY楼层
WebIFC.IFCPROJECT项目根节点
WebIFC.IFCRELDEFINESBYPROPERTIES属性集关系
WebIFC.IFCPROPERTYSET属性集
WebIFC.IFCPROPERTYSINGLEVALUE单个属性值

方案 2:@thatopen/components(高级 BIM 工具包)

适用场景
  • 需要快速获得功能齐全的 BIM 查看器
  • 希望内置片段优化,以处理大型模型
  • 需要元素高亮、剖切平面或楼层平面图
  • 项目可以接受 MIT 许可证(v3.x)
架构设置
import * as OBC from '@thatopen/components';

const components = new OBC.Components();
const worlds = components.get(OBC.Worlds);
const world = worlds.create();

// Scene
world.scene = new OBC.SimpleScene(components);
world.scene.setup(); // Adds default lights and grid

// Camera
world.camera = new OBC.SimpleCamera(components);
world.camera.controls.setLookAt(10, 10, 10, 0, 0, 0);

// Renderer (container is an HTMLDivElement)
world.renderer = new OBC.SimpleRenderer(components, container);

// ALWAYS call init after setup
components.init();
加载 IFC 文件
const ifcLoader = components.get(OBC.IfcLoader);
await ifcLoader.setup(); // Downloads and initializes WASM

// Load from file input
const file = event.target.files[0];
const data = new Uint8Array(await file.arrayBuffer());
const model = await ifcLoader.load(data);

// model is added to the active world automatically
// model contains Three.js Group with fragment meshes
主要组件
组件访问方式用途
OBC.Componentsnew OBC.Components()所有子系统的中央管理器
OBC.Worldscomponents.get(OBC.Worlds)多世界环境管理
OBC.SimpleScene构造函数带默认设置的 Three.js 场景封装
OBC.SimpleCamera构造函数内置轨道控制的相机
OBC.SimpleRenderer构造函数绑定到 DOM 元素的 WebGL 渲染器
OBC.IfcLoadercomponents.get(OBC.IfcLoader)IFC 文件加载和片段转换
OBC.FragmentsManagercomponents.get(OBC.FragmentsManager)高效的批量几何体管理
OBC.Highlightercomponents.get(OBC.Highlighter)元素选择和高亮
OBC.Clippercomponents.get(OBC.Clipper)剖切平面工具
OBC.Planscomponents.get(OBC.Plans)楼层平面图生成
片段系统

片段系统会将 IFC 几何体转换为批量绘制调用。这对于大型 BIM 模型(10,000 个以上元素)的性能至关重要。

  • 每种 IFC 类型都会批量处理为单个片段网格
  • 片段尽可能共用材质,从而尽量减少状态更改
  • 仍可通过 expressID 选取、高亮和隐藏单个元素
  • 对于包含 1,000 个以上元素的模型,务必使用片段
清理
// ALWAYS dispose when unmounting the viewer
components.dispose();
// This releases: Three.js scene, renderer, geometries, materials, textures,
// WASM memory, event listeners, and all component state

IFC 空间树

IFC 文件遵循分层空间结构:

IFCPROJECT
  └── IFCSITE
        └── IFCBUILDING
              ├── IFCBUILDINGSTOREY (Level 0)
              │     ├── IFCWALL
              │     ├── IFCSLAB
              │     └── IFCSPACE
              └── IFCBUILDINGSTOREY (Level 1)
                    ├── IFCWALL
                    ├── IFCCOLUMN
                    └── IFCDOOR

空间包含关系由 IFCRELCONTAINEDINSPATIALSTRUCTURE 和 IFCRELAGGREGATES 关系定义。务必遍历这些关系以构建可导航的树结构——不要认为扁平的元素列表能代表建筑结构。


大型 IFC 文件的内存管理

文件大小策略
<10MB完整加载,一次性渲染所有几何体
10-50MB完整加载,使用片段批处理
50-200MB按楼层或类型流式加载几何体,并释放未使用的资源
>200MB在服务端预处理为片段,按需加载
规则
  • 务必监控 WASM 堆使用情况——web-ifc 会在 WASM 线性内存中分配内存,且该内存有硬性上限
  • 务必释放当前不可见的几何体(屏幕外楼层、隐藏类型)
  • 不要在 WASM 堆和 JavaScript 堆中同时保留重复几何体
  • 务必使用 BufferGeometry(不要使用旧版 Geometry)
  • 从场景中移除网格时,务必调用 geometry.dispose() 和 material.dispose()

参考链接

Official Sources

评论

支持 Markdown