Skip to content
whiteragePublic

About

Wireframe 3D model viewer in C++20 and Qt — STL and OBJ parsing, affine transforms, GIF recording, drag & drop, persisted settings. GoogleTest coverage.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

Repository files navigation

3DViewer v2.0

C++20 Qt Widgets CMake Tests

Настольный просмотрщик каркасных 3D-моделей с поддержкой STL и OBJ, написанный на современном C++ с юнит-тестами, drag&drop, записью GIF, авто-поворотом и сохранением пользовательских настроек.

Содержание

Ключевые возможности

Возможность Что даёт
Двойной загрузчик Поддержка OBJ (включая квады, текстурные и нормалевые индексы) и ASCII/бинарных STL с дедупликацией вершин.
Точные трансформации Перемещение, вращение и масштабирование со спинбоксами, автоцентрированием и стеком undo/redo.
Управление рендерингом Переключение между параллельной и перспективной проекцией, настройка стиля рёбер, вершин, цветов и толщины линий.
Экспорт изображений и GIF Снимки экрана в PNG/BMP/JPEG и запись 5-секундных 640x480 GIF-анимаций (при наличии giflib).
Сохранение настроек QSettings запоминает геометрию окна, палитру, параметры линий и последний выбранный пример.
Телеметрия В статус-баре отображаются количество вершин/рёбер, число отрисованных сегментов и время кадра.

Пользовательский опыт

  • Перетащите .obj или .stl прямо на сцену или выберите модель из встроенного набора.
  • Все ключевые действия (загрузка, сохранение, запись GIF, авто-ротация, автоподгонка) доступны с тулбара.
  • Авто-поворот с регулируемой скоростью идеально подходит для презентаций и записи GIF.
  • Боковая панель сгруппирована по сценариям: проекция, стиль, трансформации – минимальный порог входа.
  • Undo/redo фиксируют целые сессии взаимодействия, поэтому можно смело экспериментировать.
  • Статус-бар отображает предупреждения (например, когда в файле нет граней) и подтверждает действия.

Производительность и масштабируемость

  • Граф сцены кеширует список рёбер и может отдавать пониженное количество сегментов для предпросмотра.
  • STL-импорт использует 64-битный хеш для дедупликации вершин и спокойно работает с миллионом треугольников.
  • CLI meshgen генерирует сетки от 100k до 1M вершин для стресс-тестов (make gen_1m).
  • Статистика кадра в статусе показывает время отрисовки в миллисекундах — узкие места сразу видны.

Как запустить

Требования

  • CMake 3.16+
  • Компилятор с поддержкой C++20 (проверено на Clang и GCC)
  • Qt 5 или Qt 6 Widgets (dev-пакеты)
  • giflib (опционально, для записи GIF)

Сборка и запуск через Makefile

cd src
make run                   # конфигурация CMake, сборка и запуск GUI
make build CONFIG=Debug    # только сборка (по умолчанию Release)
make install PREFIX=$HOME/.local
make uninstall             # удалить установленный бинарник и ресурсы
make clean                 # удалить каталог src/build

Чистый CMake-поток

cd src
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
./build/3dviewer

Запуск тестов

cd src
make tests                 # или: ctest --test-dir build --output-on-failure

Отчёт по покрытию (lcov обязателен)

cd src
make gcov_report
# HTML-отчёт появится в src/build/coverage/html/index.html

Структура проекта

src/
  app/             # Точка входа, запуск QApplication
  controller/      # Контроллер-фасад и стек команд (undo/redo)
  model/           # Меш, загрузчики, трансформации, стратегии проекций
  view/            # Qt-виджеты: канвас, главное окно, рекордер GIF
  tools/           # meshgen — генератор больших OBJ
  tests/           # Наборы GoogleTest для загрузчиков, меша и трансформаций
  models/          # Встроенные примеры моделей
  dvi/             # Документация (опционально)
  pic/             # Папка для GIF-анимаций и скриншотов, используемых в README
  Makefile         # Обёртка над CMake со вспомогательными целями
  CMakeLists.txt   # Основной сценарий сборки

Архитектура

  • MVC: view/ содержит UI на Qt, controller/ управляет взаимодействиями, model/ хранит данные и математику.
  • Паттерны: стратегия для выбора проекции (model/projection.h), команда для undo/redo (controller/command.h), контроллер выступает фасадом для слоя представления.
  • Библиотека ядра: статическая viewer_core подключается к GUI и юнит-тестам, чтобы бизнес-логика оставалась независимой от UI.
  • Пайплайн рендеринга: view/render_widget.cpp собирает матрицы MVP, рисует линии через QPainter и умеет выводить сцену в offscreen для GIF-рекордера.
  • Безопасность: загрузчики кидают информативные std::runtime_error, которые транслируются в статус-бар; настройки валидируются и ограничиваются при загрузке.

Примеры кода

Импорт STL с дедупликацией вершин

auto getIndex = [&](float x, float y, float z) -> int {
  Key k = Quantize(x, y, z);
  auto it = map.find(k);
  if (it != map.end()) return it->second;
  int idx = static_cast<int>(out.vertices.size());
  out.vertices.push_back(Vec3{x, y, z});
  map.emplace(k, idx);
  return idx;
};
int i0 = getIndex(v[0], v[1], v[2]);
int i1 = getIndex(v[3], v[4], v[5]);
int i2 = getIndex(v[6], v[7], v[8]);
out.faces.push_back({i0, i1, i2});

Undo/Redo через паттерн Command

void Controller::BeginInteraction() {
  if (interacting_) return;
  interacting_ = true;
  before_ = TransformCmd::Capture(model_.transform());
}

void Controller::EndInteraction() {
  if (!interacting_) return;
  interacting_ = false;

  auto after = TransformCmd::Capture(model_.transform());
  if (std::memcmp(&before_, &after, sizeof(before_)) == 0) return;

  auto cmd = std::make_unique<TransformCmd>();
  cmd->before = before_;
  cmd->after = after;
  undo_.push_back(std::move(cmd));
  redo_.clear();
}

Адаптивный стиль рёбер в рендере

AdaptLineStyle(edge_count, base_color, settings.line_width, adapted_color,
               adapted_width);

QPen pen(adapted_color);
pen.setWidthF(adapted_width);
pen.setStyle(settings.line_type == LineType::kDashed ? Qt::DashLine
                                                     : Qt::SolidLine);
pen.setCosmetic(true);
p->setPen(pen);

Инструменты и автоматизация

  • meshgen grid <nx> <ny> <out.obj> [tri] строит регулярные сетки; опция tri разбивает квады на треугольники.
  • make gen_100k и make gen_1m создают модели напрямую в src/build/models.
  • Цели make format и make check_format применяют единый стиль из materials/linters/.clang-format.

Примеры данных

  • Базовые OBJ-файлы лежат в models/ и копируются в build/models/ при конфигурации.
  • Приложение автоматически подхватывает содержимое build/models/, чтобы новые сетки появлялись в выпадающем списке Samples.
  • Дополнительные тестовые или демонстрационные модели можно размещать рядом с существующими.

Документация

  • Основная документация располагается в dvi/.
  • Ключевой артефакт — dvi/documentation.html: лёгкая, полностью гипертекстовая версия, которую удобно читать прямо в браузере. На фоне типичных PDF-файлов она выделяется интерактивным TOC, поиском и живыми ссылками на разделы.
  • При необходимости можно дополнить HTML версией в других форматах (PDF/DVI), но базовый канал доставки знаний — именно HTML.

Идеи для развития

  • Просчет нормалей и предпросмотр затенения вместе с каркасом.
  • Импорт glTF 2.0 с упрощением материалов.
  • Headless-режим, позволяющий использовать движок для пакетного рендеринга.
  • Плагинная система для пользовательских камер и скриптовых трансформаций.

С любовью Whiterage :3

About

Wireframe 3D model viewer in C++20 and Qt — STL and OBJ parsing, affine transforms, GIF recording, drag & drop, persisted settings. GoogleTest coverage.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages