Голографический верстак из обычной вебки: разбираю турбину руками без шлема и датчиков глубины
- пятница, 30 октября 2026 г. в 00:00:12
Короче, мне всегда хотелось как в «Железном человеке»: протянуть руку, взять деталь прямо из воздуха и вытащить её из двигателя. Шлема у меня нет, перчаток с датчиками тоже. Есть ноутбук, встроенная камера и браузер.
В итоге из этого получилась маленькая лаборатория. Двигатель разбирается на детали, из человека можно достать сердце и покрутить его, молекулу глюкозы собираешь из атомов пальцами. Видео с камеры никуда не уходит, всё считается в браузере на твоём же компьютере.

Кода в статье не будет. Расскажу, во что я упёрся, какие решения сработали, а какие нет. Если вы тоже пробовали делать жесты на обычной камере, многое будет знакомо.
Сервер тут только отдаёт страницу, всё остальное происходит у пользователя. Руки и голову видит MediaPipe от Google, рисует Three.js, за физику отвечает cannon-es. Все три библиотеки открытые.
MediaPipe тут, по сути, только глаза. Он отдаёт 21 точку на каждую руку и больше ничего не знает. Что такое щипок, что значит «взять деталь», как передать её из одной руки в другую, как двигатель разбирается и собирается обратно — всё это пришлось придумывать поверх. Вот это всё и есть сам проект.
Каждый кадр проходит один и тот же путь: камера, точки рук, жест, действие с моделью, картинка. И всё это должно успевать так, чтобы рука на экране не отставала от настоящей.
Первое, во что я упёрся, — у вебки нет глубины. MediaPipe выдаёт что-то похожее на расстояние, но это догадка по форме кисти, а не замер. Вдобавок точки дрожат, даже если держать руку неподвижно. А когда сжимаешь пальцы в щипок или кулак, они закрывают друг друга, и модель начинает угадывать.
Больше всего меня бесила именно неточность. Рука вроде на месте, а деталь уезжает. В какой-то момент я поменял сам алгоритм обработки точек, и стало заметно лучше. Но и до этого, и после пришлось сделать ещё несколько вещей.
Что помогло. Во-первых, калибровка. При запуске ты показываешь открытую ладонь, потом щипок, потом кулак. У всех руки разные, и пороги лучше считать от твоих, а не от какой-то средней руки.

Во-вторых, сглаживание. Сначала я подбирал его на глаз и всё время промахивался: то рука плывёт, то дёргается. Помогло только одно: записать реальные сессии и настроить по ним.
В-третьих, у каждого жеста разные пороги на включение и выключение. Иначе на границе деталь то берётся, то выпадает, и это бесит больше любой задержки.
Была и идея, которая не зашла. Я пытался стабилизировать прицел, привязав его к центру ладони. На тестах точность стала хуже, и я откатил это назад к более простому варианту.
Начиналось всё с простых фигур. Складываешь пальцы треугольником, появляется тетраэдр. Кругом — сфера, рамкой из пальцев — куб. Их можно брать, перекидывать из руки в руку, строить башню. Никаких моделей тогда ещё не было вообще, я просто создавал фигурки и строил из них пирамидки. И именно в этот момент впервые почувствовал: оно работает.

И тут же две проблемы. Круг иногда читался как треугольник. А рука упорно хватала не ту фигуру, в которую я целился, а соседнюю, обычно ту, что крупнее.
Я долго пытался выжать из трекинга больше точности, а потом дошло: у вебки есть потолок, выше него не прыгнешь. Выигрывать надо тем, как устроено взаимодействие.
Поэтому сначала деталь подсвечивается, и только потом щипок её берёт. Ты видишь, что именно схватишь, до того как схватил. Мелкую деталь можно взять двумя руками и развести их — она разворачивается на весь экран, и маленькие движения становятся большими. Свёл руки, и она вернулась на место. А когда подносишь деталь к её гнезду, она сама туда встаёт, попадать с точностью до миллиметра не нужно.

Собирать обратно тоже нужно по-честному, в том порядке, как в жизни: сначала то, на чём держится всё остальное. Если ошибся, приложение подскажет, что ставить раньше.
В первых версиях рука на экране заметно отставала от настоящей. Оказалось, что каждый кадр стоял в очереди и ждал, пока трекинг закончит с предыдущим. Я развёл их, чтобы трекинг и отрисовка работали параллельно, и руки стали обновляться почти вдвое чаще. Модели тоже пришлось ужать, чтобы они быстро грузились и не тормозили на обычных ноутбуках.
Самая неприятная история была с шейдерами. Когда я добавил деталям рельеф и подсветку, на MacBook пошли чёрные пятна и мерцание. Я был уверен, что это блики, и сначала полез крутить освещение. А это были два отдельных бага.
Первый: в редких случаях формула освещения получала число чуть больше единицы и выдавала NaN, который расползался по пикселям. Второй: контур и сама деталь рисуются в два прохода, и на видеокартах Apple их глубина расходилась в последних знаках. Контур то пропадал, то пробивал деталь насквозь. Починилось всё довольно просто: ограничить значения и сравнивать глубину с допуском, а не на точное равенство. Найти было в разы дольше, чем починить.
Баги в жестах выглядят так: «через двадцать секунд стало хуже» или «иногда хватает не то». Повторить такое руками по заказу почти нереально. Пришлось сделать себе два инструмента.
Первый — что-то вроде чёрного ящика. Жмёшь клавишу, и приложение сохраняет последние секунды: координаты рук, маленькие кадры с камеры, все события и скриншот. Дальше спокойно разбираешь запись и видишь, в какой момент жест сломался.
Второй — искусственные руки. Позы описаны в коде: ладонь, щипок, кулак, движение по траектории. Браузер без окна подаёт их в приложение вместо камеры, и перед каждым изменением само проверяется, что захват, отпускание, разборка и сборка не сломались. Записи из чёрного ящика можно прогнать так же и сравнить, как было до правки и после.
Именно записи показали, что сглаживание было настроено неправильно, и откуда брались ложные захваты. На глаз я бы это не нашёл.
После двигателей захотелось чего-то не железного. Так появилась химия: берёшь атомы из таблицы Менделеева, кидаешь в «реактор», и если пропорции правильные, собирается настоящее вещество. Если нет, ничего не соберётся, как и в жизни.

Мне было важно, чтобы молекулы выглядели так, как они устроены на самом деле, а не как схема из учебника. Поэтому форма каждой посчитана заранее по реальной геометрии. Бутан, например, получился изогнутым, потому что он такой и есть.
Сложнее всего оказались изомеры. Из одних и тех же атомов собираются разные вещества: четыре углерода и десять водородов — это и бутан, и изобутан. Пришлось добавить кнопку «другой вариант». И отдельная история, когда атомов в реакторе хватает на две молекулы: их надо правильно разделить, а не лепить одну огромную.
Анатомия сделана похоже. Тело человека с органами и отдельное сердце я взял из открытого набора эталонных органов HuBMAP (лицензия CC BY 4.0) и перевёл в свой формат.

Плоский экран остаётся плоским, сколько голограмму ни свети. Чтобы появился объём, я сделал режим, в котором экран ведёт себя как окно в комнату с моделью.
Камера следит за головой, и картинка перестраивается под точку, откуда ты смотришь. Сам экран при этом стоит на месте, меняется только угол взгляда. Наклоняешься влево и видишь деталь немного сбоку, как через стекло.
На видео этого почти не видно: камера, которая снимает, не двигается вместе с глазами. Но вживую эффект сильный. Включается и выключается одной клавишей.
По точности вебка, конечно, никогда не догонит Leap Motion или шлем. Но если строить всё вокруг её ограничений, а не бороться с ними, ощущение «я держу деталь в руке» появляется и на обычном ноутбуке. А ноутбук с камерой есть почти у всех, в отличие от шлема.
Что пока работает так себе: быстрые движения, руки слишком близко к камере и плохой свет — в полумраке трекинг заметно дрожит. Над этим ещё сижу.
После первых видео мне начали писать преподаватели. Одним из первых был учитель биологии из Нидерландов: ему очень зашло, и он прямо просил взять его поучаствовать в проекте. Так проект и стал учебной лабораторией: анатомия, химия, двигатели. Называется M2 Holo Lab, сейчас идёт закрытое тестирование. Если вы преподаёте и хотите попробовать на занятии, заявку можно оставить на m2holo.com.
Если есть вопросы, пишите в комментах. Особенно интересно услышать тех, кто тоже воевал с MediaPipe и глубиной.