FragmentsManager
Copying and pasting? We've got you covered! You can find the full source code of this tutorial here.
📄 Managing Fragments Models
In this tutorial, you'll learn how to load your BIM models in Fragment format. Fragment is an open source geometry system that we created on top of Three.js to display BIM models fast, while keeping control over the individual items of the model. The idea is simple: a BIM model is a FragmentsGroup, which is (like the name implies) a collection of fragments. A fragment is a set of identical geometries instantiated around the scene.
The IfcLoader component does exactly that! It converts IFC models to Fragments. Check out that tutorial if you are starting out with IFC files. Of course, you can just use the IfcLoader in your app, but loading fragments is more than x10 faster than loading IFC files. Our recommendation is to convert your IFC files to fragments just once, store the fragment somewhere (frontent of backend) and then load the fragments instead of teh IFC models directly.
🖖 Importing our Libraries
First things first, let's install all necessary dependencies to make this example work:
import Stats from "stats.js";
import * as BUI from "@thatopen/ui";
// You have to import * as OBC from "@thatopen/components"
import * as OBC from "../..";
🌎 Setting up a Simple Scene
To get started, let's set up a basic ThreeJS scene. This will serve as the foundation for our application and allow us to visualize the 3D models effectively:
const components = new OBC.Components();
const worlds = components.get(OBC.Worlds);
const world = worlds.create<
OBC.SimpleScene,
OBC.OrthoPerspectiveCamera,
OBC.SimpleRenderer
>();
world.scene = new OBC.SimpleScene(components);
world.scene.setup();
world.scene.three.background = null;
const container = document.getElementById("container")!;
world.renderer = new OBC.SimpleRenderer(components, container);
world.camera = new OBC.OrthoPerspectiveCamera(components);
await world.camera.controls.setLookAt(78, 20, -2.2, 26, -4, 25);
components.init();
components.get(OBC.Grids).create(world);
✨ Utilizing the FragmentsManager Component
Great! With the base viewer setup complete, let's dive into using the FragmentsManager component. This component serves as a convenient wrapper around the core FragmentsModels class from the @thatopen/fragments library. One of the key advantages of using Fragments in That Open Engine is its worker-based architecture, which offloads most operations (data retrieval, visibility management, color adjustments, etc.) to a separate thread. This ensures that the app remains responsive during processing. To get started, the first step is to specify the URL of the Fragments worker:
// One option, if you prefer not to rely on an external worker file,
// is to copy the worker file into your project's public directory.
// This ensures the worker file is bundled with your app during the build process,
// and you can provide the corresponding path to it.
const githubUrl =
"https://thatopen.github.io/engine_fragment/resources/worker.mjs";
const fetchedUrl = await fetch(githubUrl);
const workerBlob = await fetchedUrl.blob();
const workerFile = new File([workerBlob], "worker.mjs", {
type: "text/javascript",
});
const workerUrl = URL.createObjectURL(workerFile);
Once initialization is complete, you can safely retrieve the component instance and proceed with its setup:
const fragments = components.get(OBC.FragmentsManager);
fragments.init(workerUrl);
The initialization should only be performed once for the entire application instance.
Since the manager has already been initialized, we can proceed with its configuration. Fragments utilize culling and LOD (Level of Detail in 3D graphics, not LOD from BIM) to optimize geometry rendering by offloading parts that are not visible to the user. A common approach is to apply culling and LOD based on camera movements. By leveraging the world's camera controls, we can detect when the camera is about to stop moving (rest) and instruct the manager to update the visual state of all models accordingly:
world.camera.controls.addEventListener("rest", () =>
fragments.core.update(true),
);
🗂️ Fragments List
When a model is loaded, it is added to memory and the manager's list. This list serves as a centralized place to manage all loaded fragments. Use it to detect when models are added or removed. Usually, that is used to tell the loaded model which camera to use for culling and LOD updates, and add it to the ThreeJS scene:
fragments.list.onItemSet.add(({ value: model }) => {
model.useCamera(world.camera.three);
world.scene.three.add(model.object);
fragments.core.update(true);
});