ThatOpen/engine_components を調べる
IFC.js
が ThatOpen/engine_components
になっていたので、ドキュメントとかソースコード見ていろいろと調べます。
ドキュメントとか見ると半分以上が、HTML, CSS と Three.jsの内容だけどそこはスルーします。
IFC周辺について見ていくことにする。
そうするとドキュメントで言えば、チュートリアルパスの 「LOADING AND EDITING BIM DATA(BIMデータの読み込みと編集)」かな
なんか fragment
というものを使うことによって、モデルの表示速度やメモリ効率を良くしているっぽい?
よくわからないので一旦スルー
ドキュメント見ても最小構成すらわからないので、GitHubのリポジトリ見てたらテンプレートがあった。
git clone https://github.com/ThatOpen/engine_templates.git
cd engine_templates/templates/vanilla
npm install
npm run dev
たぶん最小構成
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OpenBIM App</title>
<style>
* {
margin: 0;
padding: 0;
}
#app {
width: 100vw;
height: 100vh;
overflow: hidden;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
import * as OBC from "openbim-components"
const viewer = new OBC.Components()
const sceneComponent = new OBC.SimpleScene(viewer)
sceneComponent.setup()
viewer.scene = sceneComponent
const viewerContainer = document.getElementById("app") as HTMLDivElement
const rendererComponent = new OBC.PostproductionRenderer(viewer, viewerContainer)
viewer.renderer = rendererComponent
const cameraComponent = new OBC.OrthoPerspectiveCamera(viewer)
viewer.camera = cameraComponent
await viewer.init()
const ifcLoader = new OBC.FragmentIfcLoader(viewer)
await ifcLoader.setup()
const mainToolbar = new OBC.Toolbar(viewer)
mainToolbar.addChild(
ifcLoader.uiElement.get("main"),
)
viewer.ui.addToolbar(mainToolbar)
テンプレートには、
- グリッドの表示(OBC.SimpleGrid)
- モデルクリックでハイライト(OBC.SimpleRaycaster)
- カメラから見えていないオブジェクトの非表示(OBC.ScreenCuller)
- プロパティ表示処理(OBC.IfcPropertiesProcessor)
があったけど、IFCファイルを読み込んでモデル表示するだけなら不要なので、最小限にするとこうなる構成
IFCの読み込みというか表示速度が速いというか軽いのなんでか知りたい。
とりあえず、ファイル指定での読み込み最小構成。
import * as OBC from "openbim-components"
const container = document.getElementById("app") as HTMLDivElement
// Three.jsの準備
const viewer = new OBC.Components();
viewer.scene = new OBC.SimpleScene(viewer);
viewer.scene.setup();
viewer.renderer = new OBC.SimpleRenderer(viewer, container);
viewer.camera = new OBC.SimpleCamera(viewer);
viewer.raycaster = new OBC.SimpleRaycaster(viewer);
await viewer.init();
const scene = viewer.scene.get();
// IFC読み込み準備
const fragmentIfcLoader = new OBC.FragmentIfcLoader(viewer);
await fragmentIfcLoader.setup()
// IFCファイル読み込み処理
async function loadIfcAsFragments() {
const file = await fetch('../assets/small.ifc');
const data = await file.arrayBuffer();
const buffer = new Uint8Array(data);
const model = await fragmentIfcLoader.load(buffer);
scene.add(model);
}
loadIfcAsFragments()
ドキュメント
fragmentIfcLoader.load(buffer)
を詳しく見る。
いろいろやって入るけど、読み込みしてメッシュ作成自体はこれだけ。
// const model = await fragmentIfcLoader.load(buffer);
// scene.add(model);
await fragmentIfcLoader.readIfcFile(buffer);
const group = await fragmentIfcLoader.getAllGeometries();
scene.add(group);
getAllGeometries
が実際のThree.jsのメッシュ作成処理。
FRAGS.FragmentsGroup
になんかトリックがありそうなのはわかったけど...
実際の処理は getMesh
でやっているっぽいからこれを見るか。
違うエンティティでも同じ形状の場合があるから、それをまとめることで、多重にメッシュを作成しないようにしているっていうことはわかった。
IfcOpenShell
だと形状取得処理ifcopenshell.geom.create_shape
でそのあたりを判断できる要素が多分ないので、そういうことはできない。
なんでこんなメモリ効率いいんだ?
試しにBabylon.jsで同じ処理させようとするとメモリ使用量ぜんぜん違うんだけど?
いや、WebGLのパフォーマンスのこと全然詳しくないってのもあって、なにかしら実装に問題があるんだろうけど。