Создаём с нуля своё BIM-приложение для просмотра моделей IFC формата в браузере на основе open-source библиотеки IFC.js
Введение
Приложение, о котором пойдёт речь, применимо в архитектурно-строительной области. С развитием информационных технологий, технологий строительства и производства, а также экономической составляющей, появилась необходимость в более эффективном и комплексном подходах в управлении инвестиционно-строительными проектами, что поспособствовало появлению и формированию ТИМ BIM-технологии.
- BIM (англ. Building Information Model или Информационное моделирование строительных объектов) — это объектно-ориентированная модель строительного объекта, как правило, в трёхмерном представлении, элементы которой содержат данные геометрических, физических и функциональных характеристик будущего здания или сооружения.
- BIM-технология — организованный процесс, в результате которого формируется BIM-модель, отвечающая задачам и потребностям конкретной стадии жизненного цикла здания или сооружения.
Основным популяризатором и разработчиком программ в области BIM, принято считать компанию Autodesk с их приложениями для AEC (Architecture, Engineering, and Construction) индустрии — Revit, Navisworks, ACC (Autodesk Construction Cloud, ex-BIM360) и др., но в последнее время, активно набирает обороты недовольство пользователей продуктов Autodesk, аргументируя это стагнацией в части разработки нового полезного функционала и недоработки существующего, при этом явным повышением цен на программное обеспечение. Ещё одной проблемой, является замкнутая экосистема Autodesk и их закрытый формат данных (Closed BIM), работая с которым, ты ограничен в действиях и вынужден оставаться в контуре Autodesk. На примере Revit и Autodesk Platform Services, ex-Forge.
По мере развития BIM-технологии и нежеланием быть зависимым от больших корпораций, свою популярность приобрела концепция OpenBIM и сопутствующий ей IFC формат.
- Open BIM — подход к объединению проектов зданий и сооружений в согласованную модель. Методология, позволяющая участникам проектирования коммуницировать, невзирая на используемое программное обеспечение.
- IFC (Industry Foundation Classes) — открытый стандарт для формата представления данных BIM. Формат файлов разработан buildingSMART (International Alliance for Interoperability, IAI) для упрощения взаимодействия в строительной сфере и приведению к общему знаменателю.
С тенденцией перехода сервисов в облачные решения, начали появляться open-source библиотеки или бесплатные программы по работе с BIM-моделями в web, такие, как xeokit, IFC++, IfcOpenShell и др., а соответственно и BIM-стартапы, преследующие цели OpenBIM или закрывающие конкретные задачи. Одну из таких библиотек мы и рассмотрим, развернув на её основе простое BIM-решение для просмотра модели IFC формата.
Библиотека IFC.js
IFC.js — это библиотека JavaScript для работы с моделями IFC в браузере. Она полностью бесплатная и распространяется по свободной лицензии MIT.
Идейным создателем и одним из разработчиков библиотеки IFC.js, является Antonio González Viegas — BIM software developer. И в качестве предпосылки для создания этого open-source решения и его описания, приведу вольный перевод с его слов:
Сектор AEC традиционно был рынком нескольких богатых ресурсами игроков. Крупные компании годами создавали свои собственные продукты: миллионы строк кода, решающие проблемы и в конечном итоге составляют приложения для реализации BIM и которые мы знаем из повседневной жизни.
Проблема в этой ситуации заключается в том, что новым разработчикам и компаниям очень трудно предлагать свои идеи и конкурировать на равных условиях на этом рынке. И получается, что доступ к "высшей лиге" имеют те, кто может себе это позволить.
Это не относится к таким секторам, как видеоигры, где существует множество инструментов и технологий (видеоигровых движков), которые позволяют любому создать продукт высокого уровня с минимальными затратами времени и ресурсов. Было бы здорово иметь то же самое в секторе AEC?
Вот почему мы запустили IFC.js. Вместо того чтобы создавать решение для реализации технологии BIM и продавать его как продукт, мы делаем его свободно доступным, чтобы каждый мог создавать свои собственные BIM-продукты высокого уровня. Таким образом, мы все можем конкурировать на рынке программного обеспечения с одним и тем же инструментом, где каждый может предложить свои идеи по улучшению.
IFC.js — молодой проект, который развивается и растет с каждым днем. Наша цель — позволить каждому разрабатывать программное обеспечение BIM с такой же легкостью, с какой разрабатываются видеоигры. IFC.js бесплатен, у него нет владельца, и любой может использовать его или участвовать в проекте.
Как вы уже возможно поняли, преследуется концепция Open BIM, противопоставляя решение тяжеловесным и закрытым проприетарным программам. IFC.js даёт возможность BIM-специалистам или разработчикам из других сфер создавать свои собственные BIM-решения, решающие их бизнес-задачи внутри компаний или же создавать свои коммерческие BIM-стартапы. В этом плане, лицензия IFC.js даёт полную свободу действий. Библиотека предназначена для всех, кто хочет разрабатывать BIM-приложения, будь то разработчики, создающие сервисы для строительной отрасли, так и архитекторы совместно с другими специалистами.
Структура IFC.js
В связи с тем, что IFC.js большая, мульти-язычная библиотека (C++, TypeScript JavaScript и т.д.) и держать её в одном репозитории было бы сложно и громоздко, её разбили на три основные части:
- web-ifc — ядро библиотеки: IFC парсер, написанный с нуля на языке C и скомпилирован через Emscripten в WebAssembly. Этот репозиторий инкапсулирует сложность чтения файлов IFC и загрузки их данных в память. Demo
- web-ifc-three — эта библиотека адаптирует web-ifc к Three.js, создавая оптимизированную 3D-сцену, в которой пользователи могут напрямую взаимодействовать с IFC. Эта библиотека является официальным IFC загрузчиком в Three.js. Благодаря этому, приложения BIM можно создавать с помощью Three.js всего за пару строк кода. Demo
- web-ifc-viewer — это решение для просмотра IFC в браузере со множеством примеров того, что можно сделать с помощью IFC.js. Навигация по сценам, изменение материалов, выбор элементов по нажатию на них, планы разрезов и т. д. В этом репозитории есть пример всех этих функций, поэтому его можно повторно использовать в открытых приложениях BIM из коробки. Demo
Каждая последующая часть зависит от предыдущей, в такой последовательности: web-ifc — web-ifc-three — web-ifc-viewer
Обучение
На данный момент, проводятся два курса IFC.js crash course и Advanced BIM frontend course по работе с их библиотекой в web. Курс IFC.js crach cource, как заявляет создатель, подходит для начального уровня и обучение ведётся с нуля, но под конец, как по мне, без хорошей базы в программировании будет тяжеловато.
Программа поддержки
В целях ускорения разработки проекта, а так же его улучшения — команда IFC.js реализовала программу поддержки, где даёт возможность заработать сообществу, принося свой вклад в проект. Если вкратце, то формируются карточки с разного рода заданиями, например исправление бага или реализации инструментов, таких как проверка на коллизии, формирование планов, разрезов и т.д.
Разработка BIM-сервиса для просмотра IFC формата
Создание BIM-приложения с IFC.js довольно простое, как указано на сайте с документацией. Последующий урок взят оттуда в качестве вольного перевода, с некоторыми сокращениями, отклонениями и комментариями. Развёрнутое демо-приложение находиться тут. Для выполнения следующих шагов необходим Node.js и любая IDE, но в статье я буду использовать VS Code в качестве среды разработки и расширение Live Preview в части локального сервера, не разворачивая Node.js. И если у вас нет файлов IFC, вы можете их скачать отсюда.
Для работы с IFC.js требуются базовые знания веб-разработки (HTML, CSS, JavaScript) и библиотеки Three.js
Установка библиотек
Вначале, создаём пустую папку и запускаем менеджер пакетов npm с помощью команды npm init
. Будет создан файл package.json
, содержащий некоторые данные, такие как имя проекта, версия, описание, команды и зависимости.
Все вышеперечисленные свойства можно сразу заполнить, либо прожав Enter
и использовать значения по умолчанию.
Кроме того, при помощи npm необходимо установить следующие зависимости: модуль web-ifc-three (с ним ставится и Three.js), входящий в IFC.js и rollup.js в качестве сборщика проекта для JavaScript.
//Install IFC.js npm i web-ifc-three // Install a bundler: we will use rollup.js for this guide npm i rollup --save-dev npm i @rollup/plugin-node-resolve --save-dev
Сразу можно проверить наличие в package.json
файле свойство "type": "module"
и добавить его, если оно отсутствует.
Следующим шагом, будет создание HTML файла с именемindex.html
в качестве основного документа приложения. HTML будет иметь:
- canvas элемент, используемый для рендеринга сцены Three.js;
- input элемент, который будет открывать файлы IFC с нашего компьютера в приложении.
- Тэг script, ссылающийся на файл
bundle.js
, представляющий собой сборку приложения, которую мы создадим дальше с помощью rollup.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <meta http-equiv="X-UA-Compatible" content="IE=edge"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <link rel="stylesheet" href="styles.css"/> <title>Document</title> </head> <body> <input type="file" name="load" id="file-input"/> <canvas id="three-canvas"></canvas> <script src="bundle.js"></script> </body> </html>
Для удобства импорта нашей будущей IFC-модели для тэга <input>
можно добавить атрибут accept=".ifc"
и видеть только файлы с расширением .ifc
в директории, откуда загружаем модель.
Добавление стилей
Создаём CSS файл styles.css
, где произведём сброс стилей, сделаем наш canvas на весь экран и зададим свойства нашей будущей кнопки для загрузки IFC-модели:
* { margin: 0; padding: 0; box-sizing: border-box; } html, body { overflow: hidden; } #three-canvas { position: fixed; top: 0; left: 0; outline: none; } #file-input { z-index: 1; position: absolute; }
Сборка проекта
Далее, создадим файл конфигурации с именем rollup.config.js
, который будет включать в себя ссылки на ранее установленные дополнения.
Rollup — популярная библиотека пакетов. К примеру, это сборщик, используемый Three.js. Чтобы узнать больше, ознакомьтесь с документацией.
import resolve from "@rollup/plugin-node-resolve"; export default { input: "app.js", output: [ { format: "esm", file: "bundle.js", }, ], plugins: [resolve()], };
Также, в файле package.json
изменим команды в области scripts
для удобного управления объединением/сборки проекта. В каждой команде необходимо указать относительный путь к файлу конфигурации rollup.
npm run build
объединит проект и создаст файл с именемbundle.js
в корневом каталоге проекта.npm run watch
активирует режим просмотра, автоматически обновляя этот файл каждый раз, когда мы вносим и сохраняем изменения в код.
{ "name": "example", "version": "1.0.0", "description": "-", "main": "app.js", "scripts": { "build": "rollup -c ./rollup.config.js", "watch": "rollup -w -c ./rollup.config.js" }, "author": "", "license": "ISC", "devDependencies": { "@rollup/plugin-node-resolve": "^11.2.1", "rollup": "^2.45.2" }, "dependencies": { "three": "^0.128.0", "web-ifc-three": "0.0.102" } }
WebAssembly
Далее, необходимо скопировать файл web-ifc.wasm
в директорию проекта. Найти его можно по пути node_modules\web-ifc и скопировать куда угодно, впоследствии указав на него путь, но в примере он будет размещен в корне проекта.
Этот файл необходим, так как содержит скомпилированную C++ логику модуля web-ifc, являющемся ядром парсинга для чтения и записи IFC файлов.
Создание и настройка 3D сцены
Наконец, мы создадим JavaScript файл для нашего приложения. Разместить его можно где-угодно и задать произвольно имя, главное отразить это в файле rollup.config.js
. В примере это будет app.js
в корне проекта.
import { AmbientLight, AxesHelper, DirectionalLight, GridHelper, PerspectiveCamera, Scene, WebGLRenderer } from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; //Creates the Three.js scene const scene = new Scene(); //Object to store the size of the viewport const size = { width: window.innerWidth, height: window.innerHeight, }; //Creates the camera (point of view of the user) const aspect = size.width / size.height; const camera = new PerspectiveCamera(75, aspect); camera.position.z = 15; camera.position.y = 13; camera.position.x = 8; //Creates the lights of the scene const lightColor = 0xffffff; const ambientLight = new AmbientLight(lightColor, 0.5); scene.add(ambientLight); const directionalLight = new DirectionalLight(lightColor, 1); directionalLight.position.set(0, 10, 0); directionalLight.target.position.set(-5, 0, 0); scene.add(directionalLight); scene.add(directionalLight.target); //Sets up the renderer, fetching the canvas of the HTML const threeCanvas = document.getElementById("three-canvas"); const renderer = new WebGLRenderer({ canvas: threeCanvas, alpha: true, }); renderer.setSize(size.width, size.height); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); //Creates grids and axes in the scene const grid = new GridHelper(50, 30); scene.add(grid); const axes = new AxesHelper(); axes.material.depthTest = false; axes.renderOrder = 1; scene.add(axes); //Creates the orbit controls (to navigate the scene) const controls = new OrbitControls(camera, threeCanvas); controls.enableDamping = true; controls.target.set(-2, 0, 0); //Animation loop const animate = () => { controls.update(); renderer.render(scene, camera); requestAnimationFrame(animate); }; animate(); //Adjust the viewport to the size of the browser window.addEventListener("resize", () => { size.width = window.innerWidth; size.height = window.innerHeight; camera.aspect = size.width / size.height; camera.updateProjectionMatrix(); renderer.setSize(size.width, size.height); });
Загрузка IFC файлов
В завершении мы будем использовать IFC.js для загрузки IFC файлов. Создадим экземпляр загрузчика и событие, когда пользователь загружает IFC файл с помощью элемента ввода <input>
import { IFCLoader } from "web-ifc-three/IFCLoader"; // Sets up the IFC loading const ifcLoader = new IFCLoader(); const input = document.getElementById("file-input"); input.addEventListener( "change", (changed) => { const file = changed.target.files[0]; var ifcURL = URL.createObjectURL(file); ifcLoader.load(ifcURL, (ifcModel) => scene.add(ifcModel)); }, false );
Готовый app.js файл будет так:
import { AmbientLight, AxesHelper, DirectionalLight, GridHelper, PerspectiveCamera, Scene, WebGLRenderer, } from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; import { IFCLoader } from "web-ifc-three/IFCLoader"; //Creates the Three.js scene const scene = new Scene(); //Object to store the size of the viewport const size = { width: window.innerWidth, height: window.innerHeight, }; //Creates the camera (point of view of the user) const aspect = size.width / size.height; const camera = new PerspectiveCamera(75, aspect); camera.position.z = 15; camera.position.y = 13; camera.position.x = 8; //Creates the lights of the scene const lightColor = 0xffffff; const ambientLight = new AmbientLight(lightColor, 0.5); scene.add(ambientLight); const directionalLight = new DirectionalLight(lightColor, 1); directionalLight.position.set(0, 10, 0); directionalLight.target.position.set(-5, 0, 0); scene.add(directionalLight); scene.add(directionalLight.target); //Sets up the renderer, fetching the canvas of the HTML const threeCanvas = document.getElementById("three-canvas"); const renderer = new WebGLRenderer({ canvas: threeCanvas, alpha: true, }); renderer.setSize(size.width, size.height); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); //Creates grids and axes in the scene const grid = new GridHelper(50, 30); scene.add(grid); const axes = new AxesHelper(); axes.material.depthTest = false; axes.renderOrder = 1; scene.add(axes); //Creates the orbit controls (to navigate the scene) const controls = new OrbitControls(camera, threeCanvas); controls.enableDamping = true; controls.target.set(-2, 0, 0); //Animation loop const animate = () => { controls.update(); renderer.render(scene, camera); requestAnimationFrame(animate); }; animate(); //Adjust the viewport to the size of the browser window.addEventListener("resize", () => { size.width = window.innerWidth; size.height = window.innerHeight; camera.aspect = size.width / size.height; camera.updateProjectionMatrix(); renderer.setSize(size.width, size.height); }); // Sets up the IFC loading const ifcLoader = new IFCLoader(); const input = document.getElementById("file-input"); input.addEventListener( "change", (changed) => { const file = changed.target.files[0]; var ifcURL = URL.createObjectURL(file); ifcLoader.load(ifcURL, (ifcModel) => scene.add(ifcModel)); }, false );tURL(file); ifcLoader.load(ifcURL, (ifcModel) => scene.add(ifcModel)); }, false );
И если всё настроенное корректно, то после вызова команды npm run build
мы можем собрать и запустить наше приложение, запустив расширение Live Preview, которое мы устанавливали ранее, с адресом http://127.0.0.1:3000 в браузере или открыть index.html
в папке проекта.
Заключение
Библиотека IFC.js действительно молодой проект и развивается довольно быстро, но уже сейчас даёт возможность реализовывать полноценные BIM-приложения. В связи с последними тенденциями и активным интересом в сторону подхода Open BIM — IFC.js прокладывает отличный путь для развития сервисов в строительной индустрии. Вокруг проекта уже сформировалось значительное комьюнити к которому можно присоединиться в Discord.
20-ого сентября состоится масштабное мероприятие проекта IFC.js с множеством новостей, улучшением и заменой некоторых компонентов библиотеки, а также многое другое.
P.S.
Я старался максимально сократить и упростить вводную часть, в том числе с определениями и понятиями, на сколько смог. Возможно, некоторые моменты могут быть не до конца понятными или раскрытыми. В свою очередь, я старался сделать акцент больше на технической части, но при этом добавив контекста для читателей не из архитектурно-строительной сферы.