Разработка и реализация программного 3D-движка для микроконтроллеров семейства ESP32
Автор: И. А. Тимофеев, К. А. Ковалева
Журнал: Современные инновации, системы и технологии.
Рубрика: Управление, вычислительная техника и информатика
Статья в выпуске: 5 (4), 2025 года.
Бесплатный доступ
В статье представлена разработка и практическая реализация программного 3D-движка для микроконтроллеров семейства ESP32, ориентированного на использование во встраиваемых системах, устройствах интернета вещей и портативной электронике, лишённых аппаратной поддержки графики. Актуальность работы обусловлена ростом требований к визуализации и интерактивности в недорогих и энергоэффективных устройствах при отсутствии готовых решений, обеспечивающих полноценную трехмерную графику в жёстко ограниченной аппаратной среде. Цель исследования заключается в создании расширяемой, модульной и производительной архитектуры программного 3D-движка, способной эффективно использовать двухъядерный процессор ESP32 и ограниченные ресурсы оперативной памяти. Архитектура движка базируется на объектно-ориентированном подходе и применении паттернов проектирования «Состояние» и «Стратегия», обеспечивающих низкую связанность компонентов, удобство сопровождения и возможность замены алгоритмов рендеринга без изменения ядра системы. Для организации параллельной обработки используется FreeRTOS, в рамках которой задачи физики, геометрических преобразований и растеризации распределяются по ядрам микроконтроллера и выполняются по конвейерной схеме. Особое внимание уделено оптимизации использования памяти за счёт индексированного хранения геометрии, применения целочисленных типов данных и разделения кадрового буфера между быстрой внутренней SRAM и внешней PSRAM. Экспериментальные испытания на ESP32-S3 показали возможность стабильного рендеринга сцен с 1385 треугольниками на частоте 17 кадров в секунду с поддержкой текстурирования и динамического освещения, что подтверждает практическую реализуемость предложенного подхода.
ESP32, 3D-движок, ПО, FreeRTOS, архитектура ПО, паттерн Стратегия, паттерн Состояние, двухъядерная обработка
Короткий адрес: https://sciup.org/14135235
IDR: 14135235 | DOI: 10.47813/2782-2818-2025-5-4-2091-2100
Текст статьи Разработка и реализация программного 3D-движка для микроконтроллеров семейства ESP32
DOI:
Актуальность темы исследования обусловлена стремительным развитием встраиваемых систем, в частности микроконтроллеров семейства ESP32, которые благодаря двухъядерной архитектуре и поддержке внешней памяти открывают новые возможности для реализации задач интерактивной трехмерной графики в устройствах интернета вещей (IoT) и портативной электроники. В таких системах требования к энергоэффективности и стоимости сочетаются с необходимостью визуализации сложных данных, что создаёт потребность в специализированных программных решениях [1].
Анализ литературы показывает, что существующие 3D-движки в основном ориентированы на платформы с графическими ускорителями (GPU) и не учитывают жёсткие аппаратные ограничения микроконтроллеров, лишённых аппаратной поддержки графики. Движки же, реализующие трехмерную графику на микроконтроллерах, часто ориентируются на математически верные системы, способные отображать только каркасные модели (без текстур) [2,3].
Проблема исследования заключается в отсутствии готовых, расширяемых и поддерживаемых архитектурных решений для создания 3D-систем на ресурсоограниченных микроконтроллерах.
Целью работы является разработка модульной архитектуры программного 3D-движка для микроконтроллеров ESP32, обеспечивающей эффективное распараллеливание вычислений на двухъядерном процессоре и оптимальное управление памятью.
Для достижения поставленной цели решаются следующие задачи:
-
• проектирование модульной структуры движка на основе паттернов проектирования «Состояние» и «Стратегия»;
-
• организация многозадачности и
- распределения вычислений между ядрами с использованием ОС реального времени FreeRTOS;
-
• реализация и экспериментальная проверка работоспособности системы, оценка её производительности.
Основная научная новизна заключается в адаптации и комбинации указанных паттернов проектирования для специфических условий
ESP32, включая организацию многозадачности на базе FreeRTOS и описание полного процесса рендеринга – от ввода геометрических данных до вывода изображения на дисплей [4].
МАТЕРИАЛЫ И МЕТОДЫ
Архитектура программного 3D-движка спроектирована с учетом принципов модульности, низкой связанности компонентов и эффективного использования ограниченных ресурсов микроконтроллера. Данный подход стал ответом на ключевые вызовы, с которыми сталкивается разработчик при создании графической системы для платформы без аппаратной поддержки GPU. Принятые архитектурные решения являются прямым следствием глубокого анализа возможностей и, что более важно, ограничений целевой аппаратной платформы.
Исследуя микроконтроллеры ESP32, можно отметить их мощный двухъядерный процессор, однако отсутствие блока FPU делает операции с плавающей запятой чрезвычайно затратными. Память представляет собой еще более жесткое ограничение: необходимый для вывода изображения кадровый буфер может занимать более трети всей доступной быстрой SRAM, которая к тому же сильно фрагментирована системными процессами [5,6]. Это делает классические подходы к организации графического конвейера неприменимыми.
Таким образом, проектирование началось не с абстрактных идеальных моделей, а с жестких рамок, заданных железом. Архитектура формировалась как набор компромиссов и оптимизаций, призванных превратить недостатки платформы в управляемые параметры [7,8]. Ключевыми аспектами, вытекающими из этого анализа, стали:
-
• применение паттернов проектирования («Стратегия» и «Состояние») для обеспечения расширяемости и изоляции кода, что позволяет гибко адаптировать логику под разные сценарии рендеринга без
переписывания ядра системы;
-
• четкое разделение ответственности между модулями, что минимизирует
взаимозависимости и упрощает отладку в условиях ограниченных ресурсов;
-
• организация многозадачной обработки данных, которая является не просто желательной опцией, а необходимым условием для раскрытия потенциала
двухъядерной архитектуры и обеспечения плавного рендеринга.
Этот прагматичный, «снизу-вверх» подход к проектированию лег в основу всех последующих решений, от модели данных до системы многозадачности, визуальное представление которых приведено на диаграммах далее.
Общая структурная схема компонентов
Фундаментом системы является объектноориентированная модель, построенная вокруг нескольких ключевых классов. Центральным управляющим элементом выступает класс SceneManager, реализующий паттерн «Состояние» (State Pattern). Он инкапсулирует логику переключения между различными режимами работы приложения (например, главное меню, игровая сцена, экран паузы). Каждое состояние представлено объектом класса
Scene, который содержит собственную логику обновления и набор сущностей (Entity), что обеспечивает изоляцию и переиспользование кода.
Класс Entity является абстрактным представлением любого объекта в трехмерном пространстве сцены. Он выступает в роли контейнера для геометрических данных: массивов вершин, нормалей, текстурных координат и полигонов (Polygon). Все трансформации объекта (перемещение, вращение, масштабирование) применяются к его вершинам в локальной системе координат, а результат кэшируется для последующего использования в рендеринге, что минимизирует повторные вычисления.
Рисунок 1. Диаграмма компонентов.
Figure 1. Components Diagram.
Подсистема визуализации построена на основе
Абстрактный интерфейс IRendererStrategy паттерна «Стратегия» (Strategy Pattern).
определяет контракт для всех алгоритмов рендеринга. Конкретные реализации, такие как BasicRendererStrategy, инкапсулируют специфическую логику растеризации (например, Z-буферизацию, интерполяцию освещения, текстурирование). Это позволяет гибко выбирать и подменять методы отрисовки без изменения ядра движка.
Координатором процесса визуализации выступает класс GraphicsRenderer. Его основная задача – управление списком активных сущностей, полученных от текущей сцены, и делегирование процесса их отрисовки выбранной стратегии рендеринга. Этот класс также отвечает за подготовку буферов холста и организацию вывода конечного изображения на дисплей через DMA-контроллер.
Для наглядного представления описанной структуры использована Диаграмма компонентов (Component Diagram) на Рисунке 1. Она отображает ключевые классы (SceneManager, Scene, Entity, GraphicsRenderer, IRendererStrategy), их атрибуты, основные методы и связи между ними (агрегация, композиция, зависимость), демонстрируя модульность и слабую связанность системы.
РЕЗУЛЬТАТЫ И ОБСУЖДЕНИЕ
Для полного использования двухъядерного потенциала ESP32-S3 и обеспечения плавного рендеринга вычислительная нагрузка распределена между несколькими независимыми задачами в среде FreeRTOS [9].
На нулевом ядре работают две задачи. Задача updatePhysics отвечает за обновление игровой логики. В ее обязанности входит обработка пользовательского ввода, расчет физики (коллизии, перемещения) и обновление состояния сцены. В задаче updateBuffer выполняются преобразование вершин сущностей из трехмерного мирового пространства в двумерные экранные координаты с использованием матричных операций. Результаты расчетов записываются в буфер, доступный для рендерера.
Рисунок 2. Диаграмма последовательности.
Figure 2. Sequence Diagram.
Под задачу рендеринга выделено целое отдельное ядро для максимальной производительности. В ней циклически вызывается метод SceneManager::render(), который передает список сущностей с уже подготовленными (спроецированными) вершинами в GraphicsRenderer, который, в свою очередь, используя активную стратегию, выполняет растеризацию и отправляет готовый кадр на дисплей через DMA.
Для иллюстрации этого процесса представлена Диаграмма последовательности (Sequence Diagram) на рисунке 2.
Модель данных и управление памятью
Класс Entity агрегирует в себе массив объектов Polygon. Важной оптимизацией является то, что Polygon хранит не сами данные вершин, а лишь индексы на массивы вершин, нормалей и текстурных координат в рамках родительской Entity. Это предотвращает дублирование данных в памяти для общих вершин.
Для работы с математическими объектами используется шаблонный класс Vector, что позволяет выбирать тип данных в зависимости от требуемой точности и экономии памяти. Например, для хранения координат вершин используется int16_t, а для текстурных координат – uint8_t, что в несколько раз сокращает объем потребляемой RAM по сравнению с типом float.
Рисунок 3. Диаграмма классов.
Figure 3. Class Diagram.
Управление памятью является критически важным аспектом. Кадровый буфер (холст) размещается исключительно во внутренней быстрой SRAM для обеспечения высокой скорости доступа при растеризации. Из-за ограничений на размер непрерывного блока памяти холст делится на две логические части (половины экрана), которые рендерятся и передаются по отдельности. Объемные данные, такие как текстуры и Z-буфер, размещаются во внешней PSRAM, несмотря на ее более высокую латентность.
Структура хранения геометрических данных будет визуализирована с помощью Диаграммы классов для Entity (Class Diagram) на рисунке 3. Она детализирует состав класса Entity, показывает связь "один-ко-многим" с Polygon, а также то, как Polygon ссылается на данные через индексы.
Организация многозадачности
Система организована по принципу конвейерной обработки данных, где подготовка следующего кадра происходит параллельно с отрисовкой текущего:
-
• задача физики (Core 0): циклически обновляет состояние сцены, включая обработку пользовательского ввода, вычисление
коллизий и анимацию объектов. Работает с высокой частотой для обеспечения отзывчивости;
-
• задача геометрических преобразований (Core 0): выполняет матричные преобразования
вершин из локального в мировое и экранное пространство. Метод Entity::updateBuffer() кэширует результаты расчетов для последующего использования рендерером;
-
• задача рендеринга (Core 1): в основном цикле приложения вызывает SceneManager::render(), который через GraphicsRenderer и активную стратегию рендеринга выполняет
растеризацию подготовленных данных и отправку кадра на дисплей через DMA.
Такое разделение позволяет достичь параллелизма на уровне задач: пока одно ядро занимается математическими вычислениями для следующего кадра, другое – визуализирует текущий.
Для предотвращения состояний гонки при доступе к общим данным (массивам вершин) используется минималистичный подход к синхронизации. Вместо тяжеловесных мьютексов применяется стратегия "один пишет – один читает" с двойной буферизацией критических данных. Задача updateBuffer записывает преобразованные вершины в буфер, в то время как renderScene читает данные из предыдущего, уже подготовленного буфера. Переключение буферов происходит атомарно после завершения полного цикла рендеринга.
Результаты экспериментальной проверки
Экспериментальная проверка разработанной архитектуры проводилась на микроконтроллере ESP32-S3 с подключенной PSRAM 8 МБ и дисплеем ST7789 с разрешением 240×240 пикселей. В качестве тестовой сцены использовалась 3D-модель персонажа, состоящая из 1385 треугольников, с применением текстурирования и динамического освещения. Фотография устройства с полностью отрисованным кадром представлена на рисунке 4.
Рисунок 4. Отрисованный кадр.
Figure 4. Rendered frame.
В ходе тестирования были получены следующие количественные показатели:
-
• Средняя частота кадров: 17 FPS
-
• Среднее время обработки кадра: 59 521 мкс
-
• Время растеризации: 35 897 мкс (60.3% от общего времени)
-
• Время DMA-передачи: 13 151 мкс (22.1% от общего времени)
-
• Количество обрабатываемых треугольников за кадр: 1385
-
• Производительность на треугольник: 25.9 мкс
Архитектура продемонстрировала устойчивую работу без сбоев и с минимальным количеством артефактов визуализации. Ключевым достижением является подтверждение работоспособности предложенной модульной структуры и эффективности распараллеливания задач. Система успешно переключается на тестовую сцену и реализует выбранную для нее логику стратегии отрисовки.
ЗАКЛЮЧЕНИЕ
В ходе работы была успешно разработана и реализована архитектура программного 3D-движка, ориентированного на микроконтроллеры семейства ESP32. Достигнута основная цель исследования – создание расширяемой, эффективной и отзывчивой системы 3D-рендеринга, функционирующей в условиях жёстких ограничений вычислительных ресурсов, памяти и энергопотребления, характерных для встраиваемых платформ [10].
Подтверждена принципиальная возможность построения производительных интерактивных 3D-систем на микроконтроллерах без аппаратной графической поддержки. Практическая значимость и работоспособность предложенных решений доказаны экспериментально: на тестовой установке с микроконтроллером ESP32-S3 достигнута стабильная частота 17 кадров в секунду при рендеринге сложной сцены, содержащей 1385 текстурированных треугольников с динамическим освещением. Ключевым фактором успеха стало сочетание модульной объектно-ориентированной архитектуры, основанной на паттернах «Стратегия» и «Состояние», с эффективным распараллеливанием вычислительной нагрузки между ядрами процессора посредством ОС реального времени FreeRTOS. Применение специализированной модели управления памятью, включая разделение кадрового буфера и размещение данных в зависимости от критичности к задержкам, позволило преодолеть фундаментальные ограничения встроенной памяти.
Разработанный движок не только решает конкретную задачу рендеринга, но и представляет собой готовую архитектурную основу. Его модульность и низкая связность компонентов упрощают адаптацию, модификацию и интеграцию в более сложные проекты, такие как интерфейсы IoT-устройств, портативные игровые системы или инструменты визуализации данных.