- name
- blockwright-capture
- description
- Этап 1 Blockwright — захват и конвертация. Используй, когда нужно превратить ge-export из Google Earth в .obj, обрезать клип по участку, посчитать clip-box, привести стороннюю 3D-модель к метрам и Y-вверх, отрендерить ортографические виды в Blender, или когда падает ge_convert.py / render_orthos.py.
# Этап 1 — захват и конвертация
Этап нужен, только если вход — Google Earth или модель в чужом формате. Проект
на карте, на чертежах или на одном описании начинается с этапа 2.
На входе: экспорт Google Earth как пакет сценария Microsoft Flight Simulator —
сотни glTF-тайлов, текстуры в подкаталоге, на который сами glTF не ссылаются, и
расстановка в отдельном XML в географических координатах.
На выходе: один OBJ с работающими материалами, `meta.json` в метрах, и десять
ортографических рендеров.
## Конвертировать дважды
```sh
# 1. весь захват — чтобы увидеть окружение и снять clip-box с орто-видов
python tools/ge_convert.py buildings/<name>/input/ge-export \
-o buildings/<name>/out/mesh
blender -b -P tools/render_orthos.py -- \
buildings/<name>/out/mesh/merged.obj \
-o buildings/<name>/out/mesh/orthos
# 2. тот же захват, обрезанный по участку — не по контуру здания
python tools/ge_convert.py buildings/<name>/input/ge-export \
-o buildings/<name>/out/mesh-clip \
--clip-east <a> <b> --clip-north <c> <d> --clip-up <ceiling>
blender -b -P tools/render_orthos.py -- \
buildings/<name>/out/mesh-clip/merged.obj \
-o buildings/<name>/out/mesh-clip/orthos
```
Границы клипа снимаются с вида сверху из шага 1 и записываются в
`out/mesh-clip/meta.json`. Клип нужен не для красоты: после него каждый пробник
работает быстрее и ни одному из них не приходится отфильтровывать соседей.
Клип следует за участком, не за зданием. Нижняя граница по Y не режется никогда:
`--clip-up` принимает только потолок. Клип, который начинается выше земли,
молча снимает с эталона всё низкое — клубный дом в четыре метра, террасы в три,
палубу бассейна — и ниже по цепочке просто нечего мерить. Юбки рельефа снимаются
не клипом, а `MESH_FLOOR` в пробнике: измерение их не видит, файл их держит,
потеря видна.
Если гейт сказал `the clip holds the site` красным — переклипай по напечатанной
строке `--clip-east` / `--clip-north` и перемерь. Это те же оси, что у
`ge_convert`, и та коробка, которой хватило бы на постройку и на эталон сразу;
второй взгляд на орто не нужен.
## Чек-лист первой конвертации
Три проверки **до всякого обмера**. Каждая делается за минуту, каждая стоила
кому-то от получаса до половины сборки.
**1. Куда смотрит захват.** Открой `top_tex.png` и найди улицу. Если уличный
фасад оказался не в том орто — экспорт лежит развёрнутым, лечится
`--heading 180` на конвертации. Гейт разворот проглотит (`Registration.orient`
перебирает четыре укладки), а ревью — нет: оно рендерит эталон через
собственную раму меша, и ракурсы разъедутся.
**Компас захвата не свидетель.** `meta.json` пишет «assumed frame for a
heading=0 export», и это честно. Сторона улицы, сторона моря и вход читаются с
карты или с брифа, никогда с осей захвата.
**2. Где земля.** `Mesh.datum()` печатает квантиль, самую плотную полосу высот и
расхождение между ними; `derive` останавливается, если они разошлись больше чем
на метр. Юбки полигонов под грунтом датум отравляют. Нижнюю границу клипа не
режь — это молча снимет низкие постройки. Юбку из измерения убирает `MESH_FLOOR`;
если под грунтом правда есть цоколь, поднимай `DATUM_AGREEMENT` и скажи почему.
**3. Есть ли тайлинг.** Гистограмма высот вершин по фасаду: если пики стоят
ровно через 4.5 м с огромными счётчиками — это шов экспортёра, а не этажи.
Пайплайн теперь отказывается называть 4.5 м высотой этажа, но знать об этом
стоит заранее.
## Клип по участку, а не по зданию
Клип, обрезанный вокруг контура, правилен для регистрации башни и неправилен
для участка: двор, бассейн, парковка, палуба, клубный дом выпадают из эталона
и больше никем не меряются. Один клип — широкий, по участку. Деревья и юбку
рельефа из измерения убирает `MESH_FLOOR`, не граница.
Одно здание вывело из фразы «благоустройство мешем не проверяется» вывод
«нечем и строить» и поставило прямоугольник; переделка стоила двух часов.
**Расширив клип, подними `REGISTER_FLOOR` и `MESH_FLOOR` в `probes/derive.py`.**
Это вторая половина того же решения, и без неё широкий клип ломает обмер.
`Mesh.frame` вписывает раму по всем вершинам выше `MESH_FLOOR`, регистрация
подгоняется по всем вершинам выше `REGISTER_FLOOR` — а план, с которым она их
сравнивает, это только нарисованное здание. Под клипом по зданию два этажа
значили «оставить за бортом дорогу, машины и изгородь». Под клипом по участку
они значат ещё и **«вот эта из масс на участке — то здание, которое нарисовал
план»**: виллы в четырнадцать метров, пальмы в двадцать и сосед за межой все
выше двух этажей.
Не поднял — получишь одно из двух: либо обе стороны раздуваются вместе и
аффинное преобразование тихо неверно для всех, кто читает `derived.json`, либо
`derive` останавливается на `plan overlap` или на `registration` и говорит про
клип, который ни при чём. Оба отказа теперь называют этот выход третьим.
Поднимают выше вспомогательных объёмов и **ниже самой низкой части
нарисованного здания**. Пол ограничивает подгонку, а не чтение: `skyline` идёт
по всем вершинам, поэтому четырёхметровый клубный дом под полом всё равно
измерен и всё равно приезжает на план сборкой.
## Оси
**X на восток, Y вверх, Z на юг** — та же хиральность, что у Minecraft, поэтому
точка меша ложится прямо в раму, построенную по карте. Ничего нигде не
переворачивается.
## Орто-рендеры
`tools/render_orthos.py` рисует пять ортографических видов, каждый дважды:
- **текстурированный** — читается материал, ритм окон, цвет;
- **плоский с cavity** — читается объём, который зашумлённая фото-текстура прячет.
Скрипт пишет точное число метров на пиксель для каждого вида, поэтому расстояние,
померенное в рендере, переводится в метры без гадания.
Ему же передают `--shot` для перспективных кадров — так этап 5 рендерит меш из
тех же камер, что и постройку.
## Blender
Нужен в PATH. На Windows обычно не там; `review.py` перебирает стандартные пути
установки и, если не нашёл, печатает команду, чтобы человек запустил сам. Если
Blender недоступен, орто-рендеры пропускаются — постройка от этого не страдает,
страдают только листы сравнения, и скрипт об этом говорит.
## Векторный план
Если контур есть в векторе — GeoJSON из OSM или GIS, SVG из чертёжной
программы — клади `input/plan.geojson` и этап с палитрой пропускай целиком.
Полигон это уже контур: ни порогов, ни сглаженной каймы, ни лестницы из клеток.
У SVG нет единиц, поэтому `VECTOR_SCALE` заявляется так же, как `MODEL_SCALE` у
OBJ.
## Плоская карта: сначала палитра
Библиотека читает карту по оттенкам серого, и по умолчанию стоит палитра одной
конкретной карты. Прежде чем удивляться «no building found», прогони
```sh
python -m tools.map_probe buildings/<имя>/input/layout.png
```
— он печатает гистограмму серых и предлагает `MAP_PALETTE` для
`probes/derive.py`.
## Сторонняя 3D-модель
Пайплайн читает OBJ. Модель в GLB, FBX, SKP или чём угодно ещё конвертируется в
OBJ Blender'ом и кладётся в `input/model.obj`.
Две вещи, которые файл о себе не говорит и которые придётся заявить в
`probes/derive.py`:
- **`MODEL_UP`** — `"y"` или `"z"`. Половина экспортёров пишет Z-вверх. Ошибка
видна сразу: здание лежит на боку.
- **`MODEL_SCALE`** — множитель до метров. Если габарит выходит абсурдным,
`model.read` останавливается и требует масштаб, вместо того чтобы домножить на
подходящее число: один угаданный коэффициент проходит через каждый размер, и
поймать его потом нечем.
Никакой чистки модели не нужно — `model.read` сам отбрасывает всё ниже двух
метров над землёй и заливает внутренние дыры.
## Что кладут в `input/`
```
input/
brief.md словесное описание — иногда этого одного хватает
plan.geojson контур вектором (или plan.svg)
layout.png кроп плоской карты, 1 пиксель = 1 метр
drawings/ чертежи с масштабом
sketches/ эскизы и чертежи без масштаба
model.obj полноценная 3D-модель: метры, Y вверх
ge-export/ пакет сценария из Google Earth
photos/ все фотографии, какие есть
```
Ничего из этого не обязательно, и чем больше положено, тем больше проверено.
Что каждый вход решает — в `docs/sources.md`.
Фотографий нужны все, а не отобранные три. Они не сопоставляются ни с одним
ракурсом и не должны — значит, нет причины предпочитать одну другой, а вместе они
покрывают двор, улицу и уровень земли, где захват хуже всего.
View on GitHub