Вадим Утяшев, инженер-программист, АСКОН-Бизнес-решения, делится опытом применения инструмента для визуализации и просмотра 3D-моделей в веб-браузере C3D Web Vision, сравнивает прежнюю и нынешнюю архитектуру веб-решения и описывает направления развития.
Поделюсь взглядом веб-разработчика, работающего в команде ЛОЦМАН:PLM. Что такое ЛОЦМАН:PLM? Это система управления инженерными данными и жизненным циклом изделия. Она имеет широкий спектр возможностей для решения разных инженерных задач. Одной из главных задач является управление структурой и конфигурацией изделия.
Иллюстрация демонстрирует, что структура изделия отображена в левой части окна пользователя. У пользователя есть узлы, в которые добавлены C3D-файлы. К ним, в свою очередь, прикрепляются различные файлы. Есть состав изделия, включающий дочерние узлы, дочерние элементы — детали или сборочные единицы. К ним могут прикрепляться как C3D-файлы, так и документы, например чертежи в формате PDF. Первостепенная задача, которая стоит перед нами, — это визуализация моделей. Когда пользователь кликает, он хочет видеть, как выглядит модель, вращать ее.
Вторая наша задача — предоставить пользователю инструменты контроля. Когда один пользователь формирует документацию, составляет дерево изделия, прикрепляет документы, а второй пользователь хочет проконтролировать, насколько это соответствует поставленной задаче, возникает необходимость в таких инструментах контроля, как измерения и сечения. Они также у нас применяются. После того как контроль осуществлен, второй пользователь собирает замечания и может оставлять их в виде аннотаций. Такой инструмент мы тоже используем. Исторически сложилось, что он представлен в виде приложения, которое написано под ОС Windows как серверная часть и как десктопная (клиентская) часть.
В 2020 году АСКОН запустил проект по переводу своего программного обеспечения на мультиплатформенные рельсы, чтобы все приложения работали как минимум на ОС Linux. На иллюстрации изображена дорожная карта, в соответствии с которой в 2022 году планировалось переписать серверную часть, точнее адаптировать ее под запуск на ОС Linux, и начать разработку веб-версии ЛОЦМАН:PLM в качестве отдельного клиента.
Почему веб-клиент, а не другой десктопный клиент? Думаю, ответ очевиден. Если мы разрабатываем веб-клиент, это значит, что задействована одна команда разработки и не нужно тратить ресурсы на другие команды. Кроме того, это означает, что единожды написанный клиент будет запускаться в браузерах во всех операционных системах, а в перспективе — даже на мобильных устройствах. Также для нас важно упрощение развертывания и поставки новых версий приложения. В систему легко добавлять новых пользователей, рабочие места и новые версии. Пользователю не нужно устанавливать новую версию, он получает ее сразу же, просто открывая браузер.
Эти планы мы начали реализовывать. На иллюстрациях можно наблюдать, что получилось в итоге. Для визуализации моделей нам нужно было применить компонент, которым и стал C3D Web Vision.
Рассмотрим наш опыт с точки зрения внутренних технических аспектов. Архитектура состоит из клиента и сервера. На веб-клиенте — Angular. Здесь добавлен npm-пакет C3D Web Vision. В серверной части находятся сервер приложений и некоторая «обертка», которую мы называем backend или web-API. С ее помощью мы общаемся с нашим веб-клиентом. Вместе с ними запущен C3D-сервис как серверная часть C3D Web Vision.
Как происходит взаимодействие? Когда пользователь кликает на определенный узел и приложение определяет, что там есть модель, которую нужно отобразить, клиент посылает запрос на сервер с идентификатором рабочего пространства и именем файла этой модели. Сервер определяет, что это за файл, и выгружает этот файл на диск из базы данных в определенную папку, известную C3D-сервису. Оттуда он может взять эту модель, и, после того как файл выгружен, backend, обращаясь к C3D-сервису посредством web-API, по HTTP-запросу просит начать загрузку этой модели, то есть добавить эту модель в рабочее пространство. После этого серверная часть C3D-сервиса производит некоторые манипуляции над файлом, и в какой-то момент он начинает отдавать геометрию. Пользователь видит, как модель прорисовывается.
На иллюстрации показано, как работала одна из прошлых, первых, версий нашего веб-клиента. Мы видим, как пользователь кликает на какой-то узел, изделие начинает отображаться достаточно быстро. Потом он кликает на дочерний узел, загружается дочерняя модель в виде отдельного C3D-файла.
Все работало весьма неплохо до тех пор, пока мы не начали тестировать более тяжелые модели. Нам в руки попал C3D-файл размером около 500 Мб. Допустим, это был троллейбус, как на иллюстрации. Этот файл загружался в течение двух-пяти минут, что порождало ряд проблем.
Первая проблема заключалась в том, что пользователь не мог понять, что происходит. Перед ним оказывался синий экран, и он начинал кликать по разным узлам дерева, пытаясь разобраться, работает система или нет. В результате модели вообще переставали отображаться. Мы осознали, что необходимо решать эту проблему. В консоли браузера мы обнаружили «висящий» запрос с C3D-сервиса, причем он продолжал «висеть» даже после того, как мы кликали по тем узлам дерева, которые не содержали в себе какие-либо модели C3D-файла.
Мы анализировали, почему так происходит, почему запрос не закрывается, а модели перестают работать и не отображаются. Предположили, что ответы на эти вопросы находятся в области правильного освобождения ресурсов, иными словами, нужно закрывать все это правильно. Но так как это соединение создаем не мы, а клиентская часть C3D Web Vision, то как с ней работать? Мы попытались найти соответствующий API, а на тот момент такой документации в C3D Web Vision еще не существовало. В связи с этим мы непосредственно в среде разработки исследовали интерфейсы и методы в поисках решения. К счастью, мы нашли такой интерфейс. C3DModelView — это именно тот интерфейс, который отвечает за отображение, за то пространство, где должна быть прорисована модель. В этом интерфейсе мы обнаружили метод unload. К счастью, разработчики C3D Labs заботливо оставили комментарий, который указывал на то, что этот метод выгружает ресурсы и соединение. Мы воспользовались этим методом, и все задачи решились мгновенно. Когда пользователь «перекликивал» разные узлы дерева, соединение закрывалось, открывалось, и все отлично прорисовывалось.
Но оставалась вторая проблема. При загрузке файла большого объема пользователю нужно было продемонстрировать динамику долгой загрузки. Это было необходимо для того, чтобы он понимал, что процесс запущен и ничего не сломалось. Мы намеревались понять, что происходит во время этой долгой загрузки, можем ли мы каким-либо образом отследить этот процесс, показать его пользователю. Более того, нам хотелось показать не просто некую условную динамику, а реальный progress-bar, чтобы пользователь точно знал, когда завершится этот процесс, когда он увидит итоговую модель.
Для этого мы обратились к логу консоли C3D-сервиса, запустили C3D-сервис как консольное приложение с параметром log-level=trace и там увидели следующее сообщение: «Building cache in process»/«Progress=0.4381404 completed=false».
Так мы узнали, что процесс построения кэша существует и что именно он занимает столь продолжительное время. Этот прогресс отображался в цифрах, в процентах, и мы поняли, что можем эту информацию получить. Следующим шагом стал поиск рационального способа получать подобную информацию.
Мы задавались вопросом, сможем ли мы вообще управлять процессом кэширования модели или для начала хотя бы отслеживать этот процесс. В поисках ответа мы изучили архив поставки серверной части C3D-сервиса. Там мы нашли файл swagger.yaml — описание web-api. Мы загрузили его в визуальный редактор и увидели методы, обозначенные как GET и POST. На самом деле методов работы с кэшем больше, но для примера на иллюстрации приведены два метода, которые для нас важны. Это метод получения информации о кэше модели и метод запуска генерации модели.
Теперь мы могли отобразить progress-bar и точно указать в процентах, сколько времени пользователю остается ждать. Стало очевидно, что у нас есть два процесса. Сначала мы выгружаем файл из базы данных в папку. Если даже это большой файл, то мы можем это отследить, выгружая фрагментами. Мы иллюстрируем первый этап, в ходе которого идет процесс копирования файла, а после — второй этап, подразумевающий процесс кэширования модели C3D-сервисом. Потом progress-bar исчезает, и пользователь видит всю эту геометрию в своем веб-клиенте.
Проследим, как изменилась архитектура, что в нее добавилось. Теперь взаимодействие между клиентом и сервером стало теснее. Сначала клиент посылает команду на сервер о том, что нужно начать загрузку определенной модели. Вместе с тем он запускает цикл опроса, постоянно спрашивая у сервера, каков прогресс. Тем временем сервер выгружает этот файл в папку, но при этом после каждого выгруженного фрагмента он фиксирует прогресс, то есть записывает его себе в память.
После того как этот процесс завершен, он отправляет запросы C3D-сервису через web-API, обращаясь к методу построения кэша. И C3D-сервис начинает строить кэш, а параллельно backend начинает опрашивать C3D-сервис о том, каков прогресс построения кэша.
Таким образом клиент отрисовывает свой progress-bar, и, как только к нему поступает информация о том, что операция полностью завершена, он может отправить запрос на добавление модели к области отображения. Backend проксирует запросы к C3D-сервису, то есть напрямую запросов к серверной части C3D из приложения нет. Когда C3D-сервис получает этот запрос, у него уже есть модели, построенный кэш. Он начинает выдавать геометрию, и все работает оптимально.
Иллюстрация демонстрирует, как это работает в настоящее время. Пользователь кликает на какой-то узел, идет процесс кэширования. Здесь не отображено копирование, потому что файл небольшой. Показательно, что даже работа с небольшим файлом занимает время, когда идет процесс кэширования. После этого progress-bar «прячется», показывается геометрия, и пользователь может работать с этой моделью, может ее вращать. Если пользователь кликает на какие-то другие модели, копирование-кэшрование происходит таким же образом.
Важно, что, когда пользователь во второй раз кликает по этим узлам, копирование-кэширование не происходит, потому что все уже скопировано и закэшировано. Как итог, модель выдается очень быстро, буквально сразу же.
Теперь немного о наших планах. Разрабатывая веб-клиент, мы пытаемся догонять десктопное приложение. Несмотря на то что не все планы, представленные в списке, в нем реализованы, мы остаемся в позиции догоняющей стороны.
Первое направление — это работа с аннотациями. Второе — показ исполнений, так как в одном C3D-файле могут быть разные исполнения одной модели, а нам нужно переключаться между этими исполнениями, чтобы пользователь мог видеть возможные варианты. Еще ряд направлений — измерения, проставление размеров, управление подсветкой компонентов, то есть более интересный функционал, такой как взаимное селектирование или синхронный показ. Отдельного внимания заслуживают динамические сборки, то есть загрузка разных моделей в одну сцену, когда разные C3D-файлы, разные модели загружаются в одну сцену. Другой пункт — пользовательские виды, когда пользователь вращает камеру. Один пользователь строит модель под определенным углом, ставит какие-то сечения, может добавлять комментарии, аннотации и сохраняет этот вид так, чтобы потом показать другому пользователю. Другой пользователь, соответственно, открывая эту модель, может применить этот вид, и в результате они могут взаимодействовать более эффективно и оперативно.
Наконец, сравнение геометрии версий. Это последнее направление из данного списка планов, которое означает показ различий. Пользовательские виды пока отсутствуют даже в десктопном клиенте, а вот сравнение геометрии версий уже в разработке, и что-то можно посмотреть в десктопном клиенте.
На иллюстрации продемонстрированы управление подсветкой и синхронный показ. Мы можем наблюдать некоторую родительскую модель и дочерний узел, соответственно, дочерняя модель — это отдельный C3D-файл. Что же такое синхронный показ? Это процесс, когда у пользователя, кликающего по дочерним узлам, не загружается дочерняя модель, а происходит подсветка этой дочерней модели в рамках родительской.
Данная иллюстрация посвящена динамическим сборкам. Режим отображения динамических сборок подразумевает, что появляются некоторые чекбоксы в узлах дерева и, кликая по ним, пользователь выбирает, какие из этих C3D-файлов загрузить в общую сцену. Примечательно, что эти модели загружаются в нужном месте и в нужном расположении, как в родительской модели. Так работает режим просмотра.

Вадим Утяшев,
инженер-программист,
АСКОН-Бизнес-решения