Map2Mesh. Как я навайбкодил свой картографический скрипт для 3ds Max
Всем привет! Сегодня хочу поделиться историей одного проекта, который вырос из банального желания сэкономить время, нервы и деньги.
Извечная проблема: Где взять рельеф для сцены?
Если вы занимаетесь архвизом, или моделингом сцен под экстерьер, то знаете эту боль: заказчик присылает координаты в чистом поле, в лучшем случае пару размытых фото и вам нужно каким-то образом сделать окружение. Либо просто поставить на фоне какой-то холм или гору видимые в реальности.
Для этого раньше у меня были следующие варианты получения рельефа:
SketchUp: Там был (и есть) отличный инструмент для вытягивания рельефа и спутниковой съемки, но из года в год он планомерно становился всё дороже, триальные сроки становились слишком нищими, а теперь и в целом все сервисы стали капризным в плане доступов к ним из определенной страны.
Blender: Есть аддоны вытягивающие рельеф и текстуры, но перекидывать всё это в Макс просто неудобно из-за того, что ты скачешь из одного софта в другой буквально ради одной функции. Можно, а зачем, как говорится.
SAS Планета: Классика для мегатекстур в разрешении хоть 32к, но она дает просто плоскую картинку. Рельеф руками по ней не поднимешь.
ESRI CityEngine: Ну это просто монстр и по сути своей отдельный GIS инструмент, в котором реализован очень классный редактор дорог и земельных участков, но как и с Скечапом, из года в года триалы получать стало слишком сложно, а лицензии крайне дорогие для редкого пользования.
Для 3ds Max в открытом доступе нормальных инструментов просто не было. Есть плагин Mapbox за 300 евро в год, в котором куча функций, которые мне (и большинству визуализаторов) в жизни не понадобятся. Платить такие деньги за очередной GIS инструмент, с учетом что мне чаще всего нужна просто подложка рельефа? Ну такое. Я найду куда потратить эти деньги с большей пользой.
Для затравки, напишу сразу что получилось и что в итоге умеет этот скрипт.
Изначально я хотел просто скачивать рельеф + текстуру со спутника, буквально сделать копию функционала этой функции из скечапа которым я пользовался. Но аппетит пришел во время еды, поэтому по итогу финальный список функций стал таким:
- Рельеф в один клик: Вбиваешь адрес или координаты, выбираешь зону динамической рамкой — получаешь 3D-сетку с натянутым спутником в нужном качестве.
- OSM-данные (здания и дороги): Раз уж мы тянем ландшафт, почему бы не закинуть туда «коробки» домов и сплайны дорог? Да, это условная геометрия, но для заполнения фона, стилизованных визуализаций районов или понимания пятна застройки — идеальное подспорье.
- Маски для скаттеров без Фотошопа: Это была моя личная хотелка. Обычно, чтобы рассадить лес или траву, нужно выгружать текстуру, идти в Фотошоп, крутить уровни. А сейчас есть генерация ЧБ-масок прямо в скрипте. Он анализирует текстуру взятую с модели рельефа по цветовому выбору и сам понимает: «тут — будет белое, тут — черное». А может мне нужна маска определенного участка земли, для того, чтоб по ней раскидать камни, или замешать материал? Или мне нравится общий результат но нужно подрисовать немного зону выделения? Теперь это можно получить не выходя из Макса. Да, это не нейросетевая точность в 100%, а базовые алгоритмы, как в том же Фотошопе, но, чтобы быстро накинуть Forest Pack или Chaos Scatter, или сделать смешивание материалов хватает за глаза.
Главные функции скрипта
Редактор масок
Взять кусочек Сочи — не вопрос
Вытащить гору Фудзи — да сколько угодно
Изобразить побережье Санта-Моники на закате — да пожалуйста
Ну а теперь к истории.
Примерно месяц назад, в очередной раз получив задачу сделать проект черт-те где, в месте, где нет ни панорам, ни фотографий с местности, а только шакальные ЯНДЕКС ЗЕРКАЛА, да вид со спутника, я подумал: Может попробовать собрать инструмент под себя? Такой, который делает ровно то, что мне как визеру, нужно часто, ну и желательно чтоб он имел хоть какой-то интерфейс, а не превращался в пердолинг с командной строкой.
Чтобы не нужно было открывать кучу левых программ, париться с триальными версиями и в целом делать что-то за пределами 3ds Max.
Тут нужно сперва сделать уточнение. Ранее я уже пробовал делать простенькие скрипты через нейронки. Каждый раз, когда выходила какая-то новая модель, про которую отовсюду кричали ПРОГРАММИСТЫ – ВСЁ!!! я обычно пробовал прогнать через неё пару запросов на создание скрипта, но чаще всего они пасовали перед задачами чуть сложнее каких-то базовых функций, вроде выделить предметы в сцене. Как я думаю, сказывалось их непонимание логики MaxScript или того, как реализован Python в 3ds Max, поэтому всерьез я не особо рассматривал их. Максимум как вспомогательные истории.
Но всё изменилось, когда во время работы с Nano Banana я узнал про модель Gemini от Google, которая умела выходить в интернет прямо во время подготовки ответа и считывать контекст этих поисковых запросов. Я задумался, а вдруг это именно то, чего не хватало?
Так начался мой путь 💅~вайбкодинга~💅.
Я не программист, но я понимаю что именно мне нужно, плюс представлял как смотреть логи ошибок, как подсказать нейросети исправить конкретные вещи через правильный промпт, такие вещи. Так мы и начали собирать Map2Mesh.
В целом весь процесс разработки был бесконечным диалогом с нейросетью, в попытке заставить её создать ту самую кнопку "Сделать красиво". Я не думал о правильной архитектуре, о чистом коде, об используемых библиотеках. Я думал только о вещах которые влияют на пользовательский опыт, а задача нейронки уже была решить все эти задачи. Например, как сделать так, чтобы текстуры были рассортированы по папкам. Или как собрать максимально быстрый просмотрщик карт, или исправить проблему что главная кнопка «Сгенерировать» намертво вешает Макс, если я забыл указать путь к кэшу. Или то, что интерфейс нужно немного пересобрать для удобства пользователя. Или, что тоже важно, постараться сделать так, чтоб всё работало без установки левых расширений и всё было только в рамках того что уже есть в Максе
Соответственно это был вызов и для нейронок. Прожевать огромный массив данных из моих не всегда разборчивых запросов, интеграции различных провайдеров карт и OSM помноженных на специфику кодинга для 3ds Max в понятные кнопочки в интерфейсе. Были моменты, когда над одной функцией мы совместно бились несколько дней, просто потому что нейросеть пыталась решить специфическую проблему своим способом, который был совершенно тупиковым, но делала это очень убедительно, как они это обычно и делают.
Самое забавное в этой истории то, как первоначальный код вообще появлялся на свет. Как я и писал ранее, основную массу работы вывезла Gemini 3.1 поскольку у неё гигантское окно контекста и доступ в интернет. Но поскольку на тот момент я даже не думал об удобстве, то изначально мой рабочий цикл там выглядел так:
- Говорил что-то типа «добавь вот такую фичу» или «перепиши весь код заново с учётом новых правок» и так далее.
- Нейронка выдавала гигантское полотно кода.
- Я копировал всё в Макс, запускал, ловил ошибки в MaxListener
- GO TO 1
Почему такой неоптимальный метод? Ведь можно было просить просто кидать куски исправленного кода, самому вставлять их в нужные места, и так далее. Да, но в такой ситуации я заметил что, во-первых, я начинаю слишком уходить в технические нюансы, теряя фокус и время, пытаясь разобраться что куда нужно вставить, после какой строки кода, а во-вторых, нейронка начинала иногда забывать контекст общего кода, плодя ошибки, просто из-за того что начинала работать только в рамках этого куска кода, а не всей картины целиком
Так, незаметно, я стал дотошным тестировщиком и тем самым душным заказчиком, который просит сто раз подвинуть унитаз на два сантиметра после полной сдачи проекта. Но в какой-то момент даже Gemini начал задыхаться от объема кода в чате, интерфейс просто переставал адекватно переваривать полотно текста, и я решил, что пора искать другие способы работы с кодом.
Сперва я попробовал уйти на ChatGPT — не зашло. Он просто начинал придумывать новые функции, ломать существующий код, пытаться оптимизировать то, что уже было оптимизировано и так далее. Не дело.
Пошёл по другим известным решениям. Нужно отдать должное модели Grok, на моей памяти он в целом первый начал более-менее понимать контекст и логику работы MaxScript, но очевидно большинство его ресурсов были заняты раздеванием всех в ЭксТвиттере, поэтому в рамках текущей задачи бесплатная версия модели довольно быстро уходила в лимиты обсуждения и это тоже было тупиковым ходом.
Попробовал локальные модели типа Qwen 3.5, но на моем железе это было слишком медленно, хотя для более приземленных задач это любопытное решение, которое я еще наверное пощупаю, особенно живя в современном многополярном мире с 4D гроссмейстерами, где доступность инструментов очень часто зависит не от нас с вами.
Именно поэтому в итоге финальную полировку и сложные связки я доделывал в Cursor AI. Максимально облачную, зарубежную и подписочную тему, которая сейчас, как по мне, просто спасение для таких недо-программистов, как я. Главное отличие в том, что он содержит в себе несколько мощных моделей заточенных именно на кодинг, плюс может работать с файлами на вашем компьютере напрямую, запрашивая к ним доступ, скачивать библиотеки необходимые для решения задачи, и так же делать поиск решений проблемы через интернет.
Я так же писал свои пожелания в чат как и при работе с Гемини, но теперь Курсор уже мог полноценно создавать файлы и работать с ними, вносить изменения, делать новые версии и в целом быть именно что виртуальным программистом, без моей необходимости заниматься копипастой кода туда-сюда.
Технические нюансы и картографические «грабли»
В процессе так же пришлось внезапно стать экспертом в картографии, чего я вообще не планировал. Оказывается, например, у Яндекса отличная от других провайдеров система координат. Если просто брать данные «как есть», точки на карте смещаются, и ваш выбранный участок может внезапно уплыть в соседний двор, а координаты не будут совпадать с другими провайдерами. Пришлось учить скрипт правильно дружить разные проекции, учитывать смещения, делать поправки в координатах. Или моя личная боль дырка задница, которая так и не побеждена до конца, но хотя бы немного улучшена. Это буквально дырки, но в океане.
И это еще более-менее как выглядит результат без фильтрации.
Бесплатные карты высот (SRTM/AWS) — штука капризная. После тестов от знакомых, которым я кинул черновую версию скрипта, пока шел процесс разработки, всплыла неожиданная проблема. Из-за паразитных отражений от воды при спутниковом сканировании в прибрежных зонах оказывается могут возникать артефакты — гигантские «дыры» или пики в воде. Пришлось тратить время на борьбу с фильтрацией этих данных, чтобы береговая линия выглядела как берег, а не как сцена из фильма-катастрофы. Так же вылезли проблемы связанные со сглаживанием карт высот в целом. Какие-то участки мира начинали быть похожи на рисовые поля, настолько на них проявлялось террасирование которого нет в реальной жизни. Всё это нюансы которые нужно было тестировать, ловить, учитывать и формулировать как новую задачу для нейронки.
Стрём
Норм
Много времени и сил так же ушло на интерфейс самой карты. Я не знал существуют ли готовые решения, поэтому мой изначальный запрос был сделать как в скечапе, с выделением зоны рамкой, с вводом координат или локации, с локальным кэшированием тайлов. Чем-то похоже еще и на то, как это работает в SAS Планета. И вот казалось бы, задача простейшая, сделать карту, сделать рамку выбора, но даже тут были десятки нюансов. То рамка не меняла размер, то не отслеживалось её положение, то отслеживалось, но криво. Какие-то провайдеры отображались на карте, а какие-то нет. Сами карты грузились в кэш миллион лет, или не грузились в него вообще. В последствии выяснилось, что готовые решения для карт оказывается есть, но их интерфейс мне показался перегруженным, а мне уже нравился мой вариант, поэтому и я остался на нашем изначальном решении.
Небольшой пункт про полноценные фотограмметрические 3D карты, которые можно видеть в некоторых городах в Гугл Картах и почему я не реализовал их скачивание, потому что меня об этом некоторые спрашивают.
Если в двух словах — это сложно для конечного пользователя.
Если подробнее — для легального скачивания таких карт нужно не только получить гугловское API для доступа к 3D тайлам этих карт, но еще и заплатить за доступ к нему. Вернее оформить триал, но для этого нужна зарубежная карта, зарубежные ВСЯКИЕ НЕХОРОШИЕ МЕТОДЫ ВЫХОДА В СЕТЬ, плюс, как я понял, еще и надо иметь импорт .gltf формата в 3Ds Max, а это или ставить самому (либо через скрипт) дополнительные плагины, а это уже шло вразрез с моей концепцией работы в любом варианте Макса из коробки, либо прям жестко пиратить и выгрызать куски моделей карты через другие библиотеки, но тогда дорога к платному скрипту была бы заказана. Функционал полезный, но как будто слишком много проблем вызывает, чем дает пользы. Давать доступ через отдельное API к картам высот или дополнительному провайдеру спутниковых снимков это одно, все же там есть и бесплатные альтернативы, а вот с 3D тайлами альтернатив таких нет и получится это была бы целая отдельная функция, сделанная только для небольшого числа людей.
Глубокие проблемы разработки (маски и ограничения)
Когда базовый функционал «найти и вытянуть рельеф с текстурами» заработал, я услышал обратную связь от знакомых что инструмент действительно полезный и рабочий, проснулся внутренний перфекционист, ну и желание попробовать монетизировать потраченное время и дать удобный инструмент в народ. Мы с Курсором начали прорабатывать нюансные вещи.
Изначально маски были примитивными: несколько ползунков, которые пытались отделить деревья от травы. Но быстро пришло понимание, что оттенок зелени на картах разных регионов пляшет так, что один алгоритм на всех не натянешь. Решение казалось очевидным: нужна пипетка. Ткнул в нужный цвет на спутнике пипеткой — получил маску именно этого типа растительности или просто зоны. Вот тут и начался настоящий ад разработки. Все нейронки упорно предлагали решать задачи обработки изображений через какие-нибудь сторонние библиотеки. Это значило, что пользователю пришлось бы что-то доустанавливать, прописывать пути или, что хуже всего, наблюдать внезапно всплывающие на миллисекунду окна командной строки при запуске скрипта, а это выглядит так, будто товарищ майор или мошенник уже на связи с вами.
Первая версия интерфейса скрипта. Всё еще минималистично и базово, после уже началось накидывание функций.
Первая версия редактора масок.
Я поставил жесткое условие: скрипт должен работать «из коробки».
- Без сторонних программ.
- Без сторонних библиотек.
- Без пугающих выскакивающих консольных окон, которые параноики примут за вирусы.
- Универсальность для разных версий 3ds Max
Оказалось, что стандартные инструменты 3ds Max для работы с 2D-графикой на лету — это боль. Редактор масок постоянно преподносил сюрпризы и в целом всё работало, но безумно медленно. Ползунки просто висли, или двигались с дикой задержкой. Маски отрисовывались еще медленнее, я заваливал нейронку своими претензиями и предложениями как выйти из ситуации, а она честно пыталась наворотить что-то. А уж когда я предложил добавить еще и функцию дорисовки маски вручную поверх генерируемой. Ууу, сложно сказать сколько времени и токенов было потрачено только на одну эту кисть и реализацию её суперпростого функционала.
В итоге наверное около 40% всего времени разработки просто ушло на оптимизацию того, чтобы пипетка и кисть работали стабильно и не вешали систему, а маску можно было банально сохранить. Да, это не Photoshop по скорости, но похоже это максимум того, что можно выжать из встроенного функционала для моментального результата.
В начале пути была еще одна амбициозная идея: чтобы скрипт сам создавал Forest Pack или Chaos Scatter по этим маскам, плюс с учетом того, что мы можем вытягивать OSM данные областей растительности в виде сплайнов, использовать их для этих скаттеров. Но тесты показали, что это путь в никуда, потому что популярные системы скаттеринга иногда меняют свою логику от версии к версии, и мой скрипт стал бы заложником их обновлений. В итоге я решил: ЧБ-маски вечны. Скаттеры приходят и уходят, не в них счастье. Самым важным на свете всегда будут люди в этой комнате, вот здесь, сейчас, а старая добрая маска в слоте Density будет актуальна и через 10 лет в любом движке. К тому же сама идея быстро превратилась в создание универсальных масок, а не только скаттерных. В итоге я думаю это и надежнее, и дает пользователю больше универсальности использования инструмента.
UX и доводка
Когда интерфейс начал обретать форму, я понял: инструмент не должен быть «черным ящиком». В архвизе время самый дорогой ресурс, и никто не хочет тратить час на чтение мануала, или смотреть ролики на ютубе чтоб понять, что делает та или иная функция. Поэтому были приняты несколько решений, а именно:
- Никакого языкового барьера и загадочных кнопок. Я почти сразу, после мысли о том что это будет инструмент для всех, а не только для меня, решил сделать полную локализацию. Благодаря нейронкам, перевод на английский и русский занял считанные минуты, но это дало огромный буст к удобству. И главное — я (нейронка) внедрил систему живых подсказок, примерно как это сделано в Corona Renderer. На абсолютно каждый элемент интерфейса, будь то кнопка, ползунок или галочка мы повесили всплывающую подсказку. Не понимаете, что делает та или иная функция? Скрипт тут же кратко объяснит на русском или английском языке, что произойдет после нажатия, достаточно навести на неё курсор. Вы никогда не остаетесь один на один с интерфейсом.
- Борьба за точность высот. В процессе тестов вскрылась неожиданная проблема: бесплатные провайдеры рельефа и платные API выдают разную высотность. В некоторых локациях разница в высоте составляла около 7-8 метров. Для проекта это катастрофа. О какой точности может идти речь если ваш овраг в жизни высотой метров 6, а бесплатный провайдер рисует его пригорком в 1-2 метра? Я не мог заставить бесплатные сервисы работать идеально, но предложил нейронке добавить функцию Z-коррекции и зафиксировать её по дефолту на тех самых 7 метрах, но оставить ручное управление этой разницей. Теперь пользователь бесплатного рельефа может ввести поправку, и результат будет максимально близок к дорогостоящим платным API, либо же данным, которые он сам знает на основе доступных ему исходников проекта. Вышла некоторая социальная справедливость: качественный результат может быть доступен всем.
Пример таких контекстных подсказок
Не могу не упомянуть забавный момент, случившийся на финишной прямой. Когда основной скелет скрипта был готов, я закинул рабочую бету в один уютный чатик «для своих» на тест. Мы обсудили функции, мне, как и писал выше, предложили подумать о монетизации, и что-то я даже так воодушевился? что начал думать о системах лицензии, где и как бы это всё хостить, как генерировать ключи для покупателей, какой функционал дать платным, а какой бесплатным пользователям. Через Гемини обсуждал функции, сравнивал варианты, закидывал предложения, а через Курсор реализовал систему лицензий и генератор уникальных кодов с привязкой к ID железа. В общем планов было море, всё шло к релизу, шкура медведя была практически снята, а я уже почти открывал конфигуратор Порше...
И о чудо! — буквально через неделю после того как мы обсудили мой скрипт в чате, а я пыхтя пытаюсь решить головоломку с лицензиями (там тоже было множество подводных камней), на горизонте появляется инструмент-близнец от человека, который до этого скриптов, кажется, не писал вовсе. А потом выясняется что еще один человек делает буквально такой же скрипт. Ну, как говорится, идеи витают в воздухе. Видимо, разработка картографических скриптов для Макса — это наша общая «Римская империя», о которой все думают одновременно. В моменте было конечно немного обидно, ведь хотелось сделать хороший инструмент для пользователей, ну и чего греха таить, подзаработать, а тут буквально перед носом внезапно появляется аналог с 90% схожих функций. Ну бывает, решил я, и подумал что значит надо вычеркнуть все эти истории с лицензиями про и фри версиями и просто допилить свой вариант до хорошего состояния.
Для меня это стало отличным стимулом перестать бесконечно полировать код «в стол» и поскорее выкатить мой инструмент в свет. В конце концов, дьявол всегда в деталях.
Финал: В итоге получился инструмент для тех, кому нужно быстро. Не для высокоточной геодезии, а для обычных работяг-визуализаторов. Набросать контекст, поставить гору на горизонте, раскидать пятна леса, сделать черновую маску материала, сделать основу для обработки нейронкой. Этот проект показал, что если сейчас тебе чего-то не хватает в софте — иди хотя бы попробуй это собрать самостоятельно. Сейчас идеальное время для таких крафтовых инструментов, которые закрывают конкретные боли, не заставляя покупать подписку за сотни евро (только за десятки, если речь идет об инструментах типа Cursor AI). Нейронки возможно оставят нас без работы, но пока это время не настало — нужно учиться делать работу с их помощью.
Ну и напоследок, буду рад обратной связи по работе скрипта который можно найти здесь .
Пользуйтесь, качайте, редактируйте и удачных генераций!














