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/ からパブリック/静的ディレクトリにコピーしてください。Vite などのバンドラーでは、WASM ファイルを提供するための明示的な設定が必要です。

IfcAPI の主なメソッド
メソッドシグネチャ説明
Init()() => Promise<void>WASM モジュールを初期化します
SetWasmPath(path)(string) => void.wasm ファイルを含むディレクトリを設定します
OpenModel(data, settings?)(Uint8Array, object?) => numberIFC データを読み込み、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?) => objectexpressID で単一の 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

コメント