Skip to content

Latest commit

 

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

CpuStaticViewer — OBJ 3D Viewer (Qt + OpenGL 3.3 Core)

1. Назначение и краткое описание

CpuStaticViewer — настольное приложение для визуализации трёхмерных моделей формата Wavefront OBJ с интерактивным управлением сценой и параметрами отображения. Графический вывод реализован через OpenGL 3.3 Core в контексте QOpenGLWidget, при этом матричные преобразования (аффинные преобразования и проекции) вычисляются на CPU с использованием собственного матричного класса.

Ключевая идея проекта: детерминированный и контролируемый конвейер преобразований (CPU) + минимальный набор данных на GPU (VBO/EBO) + настраиваемые режимы отрисовки (грани/рёбра/вершины).


2. Функциональность

2.1. Загрузка и представление модели

  • Загрузка .obj (вершины v, грани f).
  • Формирование:
    • массива вершин vertices_xyz (XYZ),
    • списка уникальных рёбер edge_indices (каждое ребро — пара индексов),
    • списка треугольников tri_indices (после триангуляции граней).
  • Информационная строка (главный интерфейс) отображает:
    • имя текущего файла,
    • количество вершин,
    • количество рёбер.

2.2. Режимы отображения

  • Грани (заливка)
    • включение/выключение,
    • цвет заливки,
    • режим прозрачности (в текущей конфигурации UI — дискретно 0/1).
  • Рёбра
    • включение/выключение,
    • цвет,
    • толщина (с учётом ограничений платформы, см. §7.2),
    • пунктир: параметры «шаг» и «заполнение».
  • Вершины
    • режим: отсутствуют / круг / квадрат,
    • размер,
    • цвет.
  • Фон
    • выбор цвета фона.
  • Снимок экрана
    • сохранение текущего кадра в BMP/JPEG через grabFramebuffer().

2.3. Управление сценой

  • Повороты модели вокруг осей X/Y/Z.
  • Перемещение «камеры» (через матрицу вида).
  • Два режима проекции: перспективный и ортографический.
  • (Опционально, при подключении UI) масштабирование модели (увеличение/уменьшение) через кнопки и поле ввода.

3. Управление (клавиатура)

Ниже приведены бинды, соответствующие текущей логике GlWidget.

3.1. Поворот модели

  • I / K — вращение вокруг X (±)
  • J / L — вращение вокруг Y (±)
  • U / O — вращение вокруг Z (±)

3.2. Перемещение/zoom

  • W / S
    • в перспективной проекции: движение по оси Z (приближение/удаление),
    • в ортографической проекции: изменение масштаба видимости (zoom).
  • A / D — смещение по X
  • Q / E — смещение по Y

3.3. Переключатели

  • P — переключение типа проекции (ортографическая / перспективная)
  • Z — переключение заливки граней (on/off)

4. Интерфейс

4.1. Верхняя панель вкладок

  • Проекция — тип проекции, точные углы поворота (spinbox), (при включении) масштаб модели.
  • Рёбра — пунктир, толщина, параметры пунктира, цвет рёбер.
  • Вершины — режим, размер, цвет вершин.
  • Фон — цвет фона и параметры заливки (если размещены в этой вкладке).
  • Файл — загрузка модели и сохранение изображения.

4.2. Информационная строка (главный интерфейс)

В главной части окна (вне панели настроек) отображаются:

  • имя открытого файла,
  • количество вершин,
  • количество рёбер.

Поведение:

  • при открытии панели настроек (любой вкладкой) строка скрывается,
  • при закрытии панели строка отображается вновь.

5. Аффинные преобразования (CPU) и матричный конвейер

5.1. Однородные координаты и единая матрица 4×4

Все преобразования выполняются в однородных координатах: вершина (\mathbf{p}=(x,y,z,1)^\mathsf{T}). Это позволяет описывать поворот, перенос и масштаб одной матрицей (4\times4):

[ \mathbf{p}' = \mathbf{M},\mathbf{p}. ]

Итоговая матрица передаётся в OpenGL как uniform uMVP.

5.2. Повороты вокруг осей (модуль AffineTransformation)

Повороты реализованы стандартными матрицами:

  • Вокруг X: [ \mathbf{R}_x(\alpha)= \begin{pmatrix} 1&0&0&0\ 0&\cos\alpha&-\sin\alpha&0\ 0&\sin\alpha&\cos\alpha&0\ 0&0&0&1 \end{pmatrix} ]

  • Вокруг Y: [ \mathbf{R}_y(\beta)= \begin{pmatrix} \cos\beta&0&\sin\beta&0\ 0&1&0&0\ -\sin\beta&0&\cos\beta&0\ 0&0&0&1 \end{pmatrix} ]

  • Вокруг Z: [ \mathbf{R}_z(\gamma)= \begin{pmatrix} \cos\gamma&-\sin\gamma&0&0\ \sin\gamma&\cos\gamma&0&0\ 0&0&1&0\ 0&0&0&1 \end{pmatrix} ]

Композиция поворотов соответствует следующей форме (как в коде Rz*(Ry*Rx)):

[ \mathbf{R} = \mathbf{R}_z , (\mathbf{R}_y , \mathbf{R}_x). ]

5.3. Масштабирование модели

Равномерный масштаб задаётся диагональной матрицей:

[ \mathbf{S}(s)= \begin{pmatrix} s&0&0&0\ 0&s&0&0\ 0&0&s&0\ 0&0&0&1 \end{pmatrix}. ]

При добавлении масштаба матрица модели может быть записана как: [ \mathbf{M} = \mathbf{R},\mathbf{S}. ]

5.4. Матрица вида (камера) как перенос сцены

Положение камеры реализовано переносом мира на (-\mathbf{c}): [ \mathbf{V}=\mathbf{T}(-c_x,-c_y,-c_z), \quad \mathbf{T}(t_x,t_y,t_z)= \begin{pmatrix} 1&0&0&t_x\ 0&1&0&t_y\ 0&0&1&t_z\ 0&0&0&1 \end{pmatrix}. ]

Это соответствует концепции: «двигаем не камеру, а сцену в противоположную сторону».

5.5. Передача матрицы в OpenGL (column-major)

OpenGL ожидает матрицу в column-major виде. Поэтому перед отправкой в glUniformMatrix4fv формируется массив float[16] в нужном порядке (например, через GetColMajor(MVP)), а GL_FALSE означает отсутствие транспонирования на стороне драйвера.


6. Проекции (модуль Projection) и формирование MVP

6.1. Общая формула

Финальная матрица строится по классической схеме: [ \mathbf{MVP} = \mathbf{P},(\mathbf{V},\mathbf{M}), \quad \mathbf{p}_{clip} = \mathbf{MVP},\mathbf{p}. ]

6.2. Перспективная проекция (центральная)

Перспективная матрица строится по параметрам:

  • вертикальный угол обзора (fov_y),
  • аспект (a=\frac{width}{height}),
  • near/far плоскости (n, f).

Обозначим: [ t=\tan\left(\frac{fov_y}{2}\right), \quad s=\frac{1}{t}. ]

Типичная матрица перспективы для OpenGL (NDC (z\in[-1,1])):

[ \mathbf{P}_{persp}= \begin{pmatrix} \frac{s}{a}&0&0&0\ 0&s&0&0\ 0&0&\frac{f+n}{n-f}&\frac{2fn}{n-f}\ 0&0&-1&0 \end{pmatrix}. ]

Практическая особенность: при слишком малом расстоянии до камеры возможны артефакты; поэтому вводится нижняя граница для cam_z_, чтобы не «пролетать» через near-plane.

6.3. Ортографическая проекция (параллельная)

Ортографическая проекция задаётся симметричным объёмом: [ x\in[-w,w],\quad y\in[-h,h],\quad z\in[n,f], ] где (w=\text{half_w}), (h=\text{half_h}).

Для OpenGL (NDC (z\in[-1,1])) матрица симметричной ортографической проекции:

[ \mathbf{P}_{ortho}= \begin{pmatrix} \frac{1}{w}&0&0&0\ 0&\frac{1}{h}&0&0\ 0&0&\frac{2}{n-f}&\frac{f+n}{n-f}\ 0&0&0&1 \end{pmatrix}. ]

Отдельная особенность управления: в ортографическом режиме W/S изменяют half_w, то есть масштабируют видимый объём без перспективных искажений.


7. Реализация рендера (OpenGL)

7.1. Данные на GPU

  • Грани: VAO + VBO + EBO (индексы треугольников), отрисовка glDrawElements(GL_TRIANGLES, ...).
  • Рёбра: отдельный VAO/VBO (либо индексы, либо предразвёрнутые вершины линий), отрисовка glDrawArrays(GL_LINES, ...).
  • Вершины: отрисовка GL_POINTS с GL_PROGRAM_POINT_SIZE.

7.2. Особенности glLineWidth и платформенные ограничения

На системах с Core Profile (особенно macOS) ширина линий > 1 может:

  • игнорироваться драйвером,
  • давать нестабильный результат.

Если требуется гарантированно «толстый каркас», корректным универсальным решением является отрисовка рёбер как геометрии (ленты из треугольников).

7.3. Пунктир

Текущая модель пунктира, построенная в метрике модели, закономерно зависит от масштаба/перспективы: визуальная длина штриха на экране меняется при зуме/поворотах. Для строго стабильного пунктира рекомендуется screen-space подход (период в пикселях).


8. Парсинг OBJ и построение рёбер/треугольников

  • v-строки формируют массив вершин.
  • f-строки формируют грани, из которых извлекаются:
    • рёбра (последовательные пары индексов, замыкание последнего с первым),
    • треугольники (триангуляция многоугольников).

9. Сборка и запуск

9.1. Зависимости

  • Qt 6 (предпочтительно) или Qt 5 (fallback в CMake)
  • Компилятор с поддержкой C++20
  • OpenGL 3.3 Core

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages