Назад

Невозможные тела природы

Одноэкранный интерактивный архив шестнадцати реальных животных с невозможной анатомией: шестнадцать моделей Tripo можно вращать перетаскиванием и изучать. Материалы систематизированы по самой аномалии, а не по таксономии: семь категорий плюс независимый глубоководный срез. Интерфейс дополняют лайтбокс пластины с контровой подсветкой и загрузка в стиле чертежа.

Автор: Theodore
Попробовать онлайн
Невозможные тела природыПопробовать онлайн

О проекте

ANOMALY — архив шестнадцати реальных животных, каждое из которых представлено через одну структуру, словно противоречащую законам природы: прозрачный наполненный жидкостью купол над черепом рыбы-бочкоглаза, удар кавитационным пузырьком у креветки-богомола, отсутствие хвостового плавника у рыбы-луны. Каждая запись из диапазона A-001–A-016 содержит отдельную модель Tripo, которую можно вращать перетаскиванием, масштабировать и возвращать в исходное положение.

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

Ключевые моменты

  1. При выборе любой из шестнадцати записей, 01–16, на нижней ленте сцена и обе боковые панели заменяются на месте. Перетаскивание вращает модель, прокрутка изменяет масштаб, а при каждом переключении камера сбрасывается, чтобы все шестнадцать образцов отображались в сопоставимом размере.
  2. По щелчку архивная пластина трансформируется из собственной миниатюры в смотровой бокс с контровой подсветкой. Световой ореол образует свет, выходящий за края пластины. Изображение можно увеличить до 3.2× и перемещать перетаскиванием.
  3. Фильтры работают по самой аномалии — прозрачности, зрению, биолюминесценции, маскировке, хищничеству, гигантизму и плану строения тела; отдельно доступен независимый срез по глубоководной среде, основанный на месте обитания. Один образец может одновременно относиться к нескольким категориям, а поиск охватывает названия видов, латинские названия, структуры и идентификаторы образцов.
  4. Пока загружается модель, GSAP штрих за штрихом рисует обмерный линейный чертёж образца, а штангенциркуль движется вдоль линейки. Чертёж появляется раньше тела, затем плавно сменяется 3D-моделью; даже для модели из кэша он остаётся на экране 1.5 секунды, чтобы не промелькнуть слишком быстро для чтения.

Технический разбор

  • 3D-ассеты · Подготовка высокополигональных моделей Tripo для веба

    Шестнадцать моделей образцов созданы в Tripo. Каждый исходник занимает ~60 MB и содержит ~1.9M треугольников — это скульптурная плотность, непригодная для поставки. Пайплайн gltf-transform с meshopt сокращает геометрию до 2.4–11 MB: вершины свариваются, геометрия упрощается с допуском ошибки 0.0002, неиспользуемые данные удаляются, затем применяется сжатие meshopt. Текстуры намеренно остаются в 4K, а не понижаются в разрешении: это давало мало экономии и было главной причиной размытия. Всё, что поставляется в 8K, уменьшается до 4K; расход VRAM на одну карту базового цвета снижается примерно с 358 MB до 89 MB без видимых потерь при экранном размере.

    Каждый образец независимо переходит по цепочке GLB → статичное изображение → вырезка → вручную подготовленный линейный чертёж. Даже при отсутствии чертежа на фоне остаётся чертёжная сетка, поэтому отсутствие любого файла не может оставить сцену пустой.

  • Сцена образца · Автоматическое кадрирование и защита контекста

    Шестнадцать моделей созданы без единого общего стандарта, и ни для одной трансформация не подгоняется вручную. Каждая модель при загрузке измеряется относительно собственной корневой матрицы. Измерение в мировом пространстве повторно учитывает уже применённый масштаб, поэтому при каждом новом измерении модель уменьшается. Вместо необработанного Box3 для измерения используются границы по процентилям. У некоторых животных усики и нити содержат лишь ничтожную долю вершин, но при этом определили бы границы бокса и уменьшили тело. Обрезка крайних значений заключает в бокс основную массу животного, благодаря чему все шестнадцать образцов имеют сопоставимый визуальный вес. Автоматическое вписывание разворачивает модель так, чтобы её самая длинная горизонтальная ось шла поперёк экрана, центрирует её и заполняет canvas. Новый образец достаточно добавить в каталог, и он сам впишется в кадр; максимум потребуется небольшая индивидуальная поправка (двустворчатый моллюск похож на крышку, а не на профиль).

    Canvas не получает key по образцу: при каждом переключении это уничтожало бы и заново создавало контекст WebGL, а браузеры отбрасывают самый старый активный контекст. Key назначается только внутренней Scene. Для primitive также требуется dispose={null}: кэш GLTF в drei разделяет геометрию между клонами, и если разрешить R3F выполнять dispose при размонтировании, будут уничтожены всё ещё используемые буферы.

  • Освещение · Как в витрине, а не на копировальном стенде

    Один рисующий источник, два скользящих контровых сзади и никакого отражённого от пола света — большинство этих животных тёмные, и именно край отделяет тёмное тело от тёмного фона; в этом вся задача контровых источников. Карта окружения запекается на месте из площадных источников внутри Scene (Environment находится за пределами Scene с key, поэтому при переключении образцов карта не запекается заново), без загрузки HDRI и внешних запросов.

    Одной перенастройки света оказалось недостаточно, чтобы отделить самые тёмные образцы: тёмный красно-коричневый кальмар и тёплый коричневый фон действительно близки по светлоте. Поэтому образец помещён в мягкое световое пятно, а контактная тень врезается в него — именно это раскрывает силуэт. Для тонального отображения используется Khronos PBR Neutral с экспозицией 1.34, а не ACES по умолчанию, который резко затемняет средние тона — именно поэтому эти образцы терялись.

    Lightformer · PBR
  • Загрузка · Индикатор прогресса без ложных обещаний

    useProgress из drei считает файлы, а не байты: самодостаточный GLB — это один элемент, поэтому индикатор остаётся на нуле в течение всей загрузки и в конце скачком достигает ста — эта цифра лжёт. Поэтому загрузчик не показывает проценты: DrawSVGPlugin штрих за штрихом рисует обмерный линейный чертёж образца, пока штангенциркуль движется вдоль линейки. Он сообщает лишь о том, что работа продолжается, не делая вид, будто знает, сколько осталось.

    Когда модель готова, чертёж плавно сменяется 3D-моделью. Даже для модели из кэша он остаётся на экране как минимум 1.5 секунды, иначе промелькнул бы слишком быстро, чтобы его успели прочитать. При prefers-reduced-motion декоративная анимация останавливается, а минимальная выдержка отменяется: уменьшение движения должно убирать движение, а не функцию, и никогда не добавлять ожидание.