Шаблон содержит готовый код для того, что не относится к самой
растеризации: чтение .obj, чтение и сохранение картинок, создание окна и
вывод в него массива пикселей. Всё остальное (векторы и матрицы, растеризатор,
шейдеры, буферы) пишете вы.
CMakeLists.txt
external/ сторонние библиотеки (header-only)
stb_image.h чтение PNG/JPG/...
stb_image_write.h запись PNG
tinyobj_loader_c.h парсер .obj
resources/ тестовые модели и текстуры (включая скайбокс)
src/
vectors.h типы vec2, vec3 (минимум, нужный утилитам)
image_utils.h/.c load_image_f32_rgb, save_image_f32_png_rgb
mesh_utils.h/.c load_obj, free_mesh
main_cli.c пример без окна: меш + картинка -> PNG
main_app.c пример с окном: вывод массива пикселей в реальном времени
Шаблон написан на C (C11). Нужны компилятор (gcc или clang), CMake не ниже 3.10 и GLFW 3.3+. На Debian/Ubuntu:
sudo apt install build-essential cmake libglfw3-devСборка (из корня шаблона):
cmake -S . -B build
cmake --build build -jПо умолчанию собирается Release (-O3 -march=native). Для отладки
соберите отдельную Debug-версию в другую папку:
cmake -S . -B build_debug -DCMAKE_BUILD_TYPE=Debug
cmake --build build_debug -jИзмерять скорость растеризатора имеет смысл только в Release-сборке.
Сборка CMake(из корня шаблона):
cmake --build build -j --config ReleaseПути к ресурсам по умолчанию заданы относительно корня шаблона, поэтому запускайте программы оттуда.
./build/main_cli [mesh.obj] [texture.png|jpg] [output.png]Загружает меш (по умолчанию resources/Bunny.obj), печатает число вершин и
треугольников, затем загружает картинку (по умолчанию
resources/textures/porcelain.jpg) и сохраняет её с переставленными красным
и синим каналами (по умолчанию в swapped_rb.png).
./build/main_app [width] [height]Открывает окно (по умолчанию 640×480) и каждый кадр заполняет на CPU массив
RGBA8 цветом, который плавно меняется со временем; массив выводится в окно
через glDrawPixels. Скорость смены цвета умножается на длительность кадра,
поэтому не зависит от FPS. Раз в секунду в консоль печатается среднее время
кадра. Выход - Esc или закрытие окна.
Вертикальная синхронизация выключена (glfwSwapInterval(0)), чтобы время
кадра показывало реальную скорость программы, а не частоту монитора.
В шаблоне есть только типы vec2, vec3 и функции make2, make3 - то,
что нужно загрузчику мешей. Операции над векторами, vec4, матрицы и прочую
математику дописывайте сами (в этот же файл или в свой).
- Картинка - массив
floatразмеромw * h * channels, каналы пикселя лежат подряд (RGBRGB...). - Строки хранятся снизу вверх: пиксель
(x, y)лежит по адресуdata[(y * w + x) * channels],y = 0- нижняя строка картинки. Так же устроены буферglDrawPixelsвmain_appи текстурная координатаvв.obj. Если вы выберете другое соглашение, поменяйте его везде. load_image_f32_rgb(filename, &w, &h, gamma)загружает RGB-картинку (3 канала), переводит значения в [0, 1] и возводит в степеньgamma(gamma = 1- без преобразования). Возвращает массив, который нужно освободить черезfree(), илиNULLпри ошибке.save_image_f32_png_rgb(data, filename, w, h, channels, gamma)возводит значения в степень1/gamma, обрезает в [0, 255] и пишет PNG. Принимает 1 (только красный канал), 2 (R, G) или 3 и больше (RGB, остальные каналы игнорируются) каналов, поэтому в PNG можно сохранить и кадровый буфер, и, например, буфер глубины.
- Все атрибуты вершины индексируются одним индексом:
verts[i],normals[i],tcs[i]. Треугольникt- вершиныindices[3*t],indices[3*t+1],indices[3*t+2]. - В
.objу позиций, нормалей и текстурных координат индексы раздельные. При загрузке каждая уникальная тройка (позиция, текстурная координата, нормаль) становится отдельной вершиной, поэтому вершин в меше может оказаться больше, чем строкvв файле (например, на швах развёртки). - Многоугольники разбиваются на треугольники.
- Нормали и текстурные координаты не генерируются: если в файле их нет
(или они заданы не для всех вершин),
normals/tcsравныNULL. - При ошибке
load_objвозвращает пустой меш (num_triangles == 0). Освобождается меш черезfree_mesh. - Файлы материалов (
.mtl) не используются.
| Файл | Нормали | Текст. коорд. | Комментарий |
|---|---|---|---|
Bunny.obj |
есть | есть | ~144 тыс. треугольников, хорош для проверки производительности |
Roman Centurion.obj |
есть | есть | |
Chicken_01.obj |
есть | есть | |
cornell_box.obj |
нет | нет | для проверки пересчёта нормалей |
Текстуры лежат в resources/textures, грани скайбокса - в
resources/textures/skybox.
Новые .c-файлы добавьте в список add_library(raster_utils ...) в
CMakeLists.txt - тогда они будут доступны обеим программам. Можно также
завести свои исполняемые файлы по образцу main_cli и main_app.
OpenMP подключается автоматически, если компилятор его поддерживает
(#pragma omp parallel for).