Для чего нужна данная статья? :
Создать мультиплатформенное графическое приложение с:
- 3D-сценой на движке Bevy, Fyrox или Godot Rust.
- Физикой с Rapier и Legion ECS.
- Низкоуровневым рендерингом через wgpu, Vulkano, OpenGL.
- GUI-интерфейсом (egui, iced, gtk-rs, slint).
- Веб-версией (WebGPU, WebGL, Canvas API).
- Обработкой изображений (image, resvg).
- Вычислениями на GPU (CUDA, OpenCL, wgpu-compute).
Найти альтернативы для работы с графикой:
✅ Игровые движки (Bevy, Fyrox, Godot Rust)
✅ Низкоуровневые графические API (wgpu, Vulkano, OpenGL)
✅ 2D/3D-визуализация (wgpu, raqote, Skia, Cairo)
✅ GUI (egui, iced, slint, gtk-rs)
✅ Веб-графика (WebGPU, WebGL, Canvas API)
✅ Физика и игровые ECS (Rapier, Legion)
✅ Обработка изображений (image, resvg)
✅ GPGPU-вычисления (CUDA, OpenCL, wgpu-compute)
Зачем Вам это уметь? :
1. 2D-графика
Библиотеки для рендеринга 2D-графики:
- wgpu – безопасная и кроссплатформенная графическая абстракция на основе Vulkan, Metal, DX12 и OpenGL.
- vulkano – безопасная обертка над Vulkan.
- glow – безопасная обертка над OpenGL.
- minifb – минималистичная библиотека для создания окон и рендеринга пикселей.
- pixels – простой буфер пикселей поверх wgpu.
- softbuffer – библиотека для прямого управления буфером кадра без GPU.
Библиотеки для 2D-отрисовки и векторной графики:
- image – работа с растровыми изображениями.
- resvg – отрисовка SVG.
- raqote – рендеринг векторной графики в стиле Cairo.
- skia-safe – биндинги для Google Skia.
- cairo-rs – биндинги для Cairo.
2. 3D-графика
Графические движки:
- Bevy – современный ECS-движок с поддержкой wgpu.
- Fyrox – удобный 3D-движок с GUI-редактором.
- Godot Rust – Rust-биндинги для Godot.
- Macroquad – удобный движок без зависимостей.
- Tetra – 2D-игровой движок с OpenGL.
Прямой доступ к графическим API:
- wgpu – поддерживает Vulkan, DX12, Metal.
- vulkano – безопасная работа с Vulkan.
- ash – низкоуровневые биндинги к Vulkan.
- glium – удобный слой над OpenGL.
- glutin – создание окон с OpenGL.
3. GUI (Графический интерфейс пользователя)
Фреймворки на Rust:
- egui – быстрый и удобный GUI на wgpu.
- druid – декларативный GUI с поддержкой piet.
- iced – вдохновлен Flutter.
- slint – декларативный GUI в стиле Qt/QML.
- orbtk – для Redox OS и не только.
- fltk-rs – биндинги для FLTK.
Биндинги для классических GUI-фреймворков:
- gtk-rs – GTK для Rust.
- qt-rs – биндинги к Qt/QML.
- native-windows-gui – Windows GUI.
4. Графика для научных расчетов и визуализации данных
5. Web-графика (WebAssembly + Rust)
- WebGPU (wgpu-rs) – WebGPU в браузере.
- Canvas API – рендеринг в <canvas> через wasm-bindgen.
- WebGL (gl-rs) – биндинги к WebGL.
- Three-d – 3D-рендеринг на WebAssembly.
6. GameDev и физика
- Rapier – физический движок 2D/3D.
- NPhysics – физический движок.
- Legion – ECS-фреймворк для игр.
- hecs – еще один ECS-фреймворк.
7. Инструменты для работы с шейдерами
- naga – транслятор шейдеров.
- spirv-cross – работа с SPIR-V.
- rust-gpu – написание шейдеров на Rust.
8. Графика с использованием GPU (GPGPU)
- cuda-rs – работа с CUDA.
- wgpu-compute – вычисления на GPU через WebGPU.
- ocl – OpenCL в Rust.
- rust-gpu – Rust для GPU.
Давайте создадим прорисовку куба на экране.
- bevy::prelude::* — основной движок для 3D-сцены, ECS, рендеринга.
- bevy_rapier3d — физика (Rapier).
- burn::* — ML-фреймворк (autodiff для градиентов, NdArray-бэкенд).
- rayon — параллелизм для генерации данных ML.
- wgpu::* — низкоуровневый доступ к GPU для compute-шейдера Mandelbrot.
- egui_plot — графики в GUI.
- flume — безопасный канал для mapping буфера wgpu (без futures_intrusive).
- ::core::fmt — обязательный импорт для derive(Module, Debug) в burn (no_std совместимость).
Константы COMPUTE_WIDTH/HEIGHT — размер текстуры для Mandelbrot (800×600).
- Mlp — кастомная нейросеть (MLP с двумя линейными слоями + Gelu-активация). MLP (Multi-Layer Perceptron) — это простейший вид нейронной сети, где слои соединены последовательно. Здесь используется два линейных слоя (простые матричные умножения) и функция активации GELU (вариант ReLU, который лучше работает с современными моделями).
Пример:
Представьте, что вы учитесь предсказывать цену дома по его площади и количеству комнат. MLP берёт эти два числа, умножает их на веса (параметры), добавляет смещение, а затем применяет GELU, чтобы результат не был слишком большим или маленьким.
- Только forward-пропуск.
Зависит от абстракции Backend (можно переключить на wgpu для GPU-обучения).Forward-пропуск — это процесс, когда нейросеть получает входные данные и вычисляет выходные, не обучаясь. То есть, она просто "пропускает" данные через себя, не изменяя свои веса.
Пример:
Вы даёте сети фотографию кошки, и она говорит, что это кошка — но не учится на этом примере.
Backend — это "движок", который выполняет все вычисления. Здесь используется абстракция, позволяющая легко переключаться между CPU и GPU (например, с помощью библиотеки wgpu для ускорения на видеокарте).
Пример:
Представьте, что вы можете готовить еду на плите (CPU) или в микроволновке (GPU). Backend — это выбор, на чём готовить.
- #[derive(Module, Debug)] — burn-макрос для автоматической сериализации/клонирования параметров. Это специальная команда для Rust, которая автоматически добавляет модели возможности:
- Module — позволяет модели работать как часть нейросети (например, сохранять и загружать веса).
- Debug — позволяет выводить информацию о модели для отладки.
Пример:
Как если бы у вас был конструктор Lego, и вы могли бы легко копировать или сохранять свои постройки.
MlpConfig — конфигурация модели (hidden = 64).Это настройки модели, где hidden = 64 означает, что в скрытом слое 64 нейрона. Чем больше это число, тем сложнее модель, но тем дольше она учится.
Пример:
Как если бы вы выбрали, сколько этажей будет в вашем доме: 64 — это средний размер.
MlManager — менеджер модели (NonSend ресурс, так как burn-модели не Sync из-за lazy инициализации параметров).MlManager — это "управляющий" моделью. Он не может быть передан между потоками (NonSend), потому что параметры модели инициализируются только при первом использовании (lazy), и это небезопасно для многопоточности.
Пример:
Как если бы у вас был личный помощник, который работает только в одном кабинете и не может одновременно быть в другом.
Генерация данных:
- Многопоточность: rayon распараллеливает генерацию 400 точек sin(x).Rayon — это библиотека для языка Rust, которая помогает автоматически распределять работу между несколькими потоками (ядрами процессора).
Простыми словами: Представьте, что вам нужно нарисовать 400 точек на графике функции sin(x). Вместо того чтобы рисовать их по одной, вы нанимаете несколько художников, и каждый рисует свою часть точек одновременно. Так работа идёт быстрее.
Пример: Если у вас 4 ядра процессора, Rayon может разделить генерацию 400 точек на 4 части и выполнить их параллельно.
Тренировка:
- Создаётся тензор x/y с .require_grad() (autodiff).Тензор — это многомерный массив (например, таблица чисел). Метод .require_grad() включает автоматическое дифференцирование (autodiff) для этого тензора.
Простыми словами: Представьте, что у вас есть лист бумаги с числами (тензор). Вы говорите компьютеру: "Следи, как эти числа меняются, чтобы потом можно было понять, как они влияют на результат".
Пример: Если вы учите модель предсказывать цену дома, тензор может содержать данные о площади, количестве комнат и т.д. .require_grad() позволяет модели понимать, как изменение каждого параметра влияет на итоговую цену.
- Клонируется модель (burn поддерживает clone для параметров). Клонирование модели — это создание её точной копии с теми же параметрами.
Простыми словами: Представьте, что у вас есть рецепт торта. Вы делаете его копию, чтобы можно было экспериментировать с новым рецептом, не портя оригинал.
Пример: В машинном обучении иногда нужно запустить несколько экспериментов с одной и той же моделью, но с разными данными или параметрами. Клонирование позволяет это сделать.
- Adam-оптимизатор, 300 эпох, MSE-loss.Это алгоритм, который помогает модели "учиться" — подстраивать свои параметры, чтобы делать более точные предсказания.
300 эпох: Эпоха — это один полный проход по всем обучающим данным. 300 эпох означает, что модель увидит все данные 300 раз.
MSE-loss: Mean Squared Error — это способ измерить, насколько модель ошибается. Чем меньше MSE, тем точнее модель.
Простыми словами: Представьте, что вы учитесь стрелять из лука. Adam-оптимизатор — это тренер, который подсказывает, как поправить прицел. 300 эпох — это 300 тренировок. MSE-loss — это среднее расстояние от стрелы до мишени.
- Backward + step — автоматические градиенты (autodiff). Backward: Это шаг, на котором модель считает, как ошибка зависит от каждого параметра (градиенты).Step: Это шаг, на котором модель обновляет свои параметры, чтобы уменьшить ошибку.
Простыми словами: Представьте, что вы поднимаетесь на гору и хотите спуститься вниз. Backward — это когда вы смотрите, в каком направлении идти, чтобы спускаться быстрее. Step — это когда вы делаете шаг в этом направлении.
- Результат сохраняется в y_pred для графика. y_pred — это предсказания модели, которые сохраняются для построения графика.
Простыми словами: После обучения модель предсказывает значения (например, y = sin(x)) и сохраняет их в переменную y_pred, чтобы потом можно было нарисовать график и сравнить с реальными данными.
3. GPGPU абстракция (ООП + SOLID + многопоточность)
WgpuComputeBackend — реализация на WGPU — это современный графический API (интерфейс программирования), который позволяет работать с графикой и вычислениями на GPU (видеокарте). Он похож на Vulkan или DirectX, но более универсален и работает на разных платформах.
Пример:
Представьте, что вы хотите нарисовать красивую картинку или сделать сложные расчёты. Вместо того чтобы загружать процессор (CPU), вы передаёте эту работу видеокарте (GPU), которая справляется с такими задачами гораздо быстрее.
- Создаёт compute-шейдер (mandelbrot.wgsl — классический Mandelbrot на GPU). Compute-шейдер — это программа, которая выполняется на GPU и предназначена для вычислений, а не для рисования. Здесь используется шейдер, который рассчитывает множество Мандельброта (известный фрактал).
Пример:
Представьте, что у вас есть кухонный комбайн (GPU), который может очень быстро нарезать овощи (выполнять вычисления). Compute-шейдер — это рецепт, по которому комбайн работает.
- Storage буфер для результата (RGBA8). Storage буфер — это область памяти на GPU, где хранятся данные, полученные после вычислений. RGBA8 означает, что каждый пиксель хранится как 4 байта: красный, зелёный, синий и альфа-канал (прозрачность).
Пример:
Представьте, что вы рисуете картину. Storage буфер — это холст, на котором хранятся все цвета и детали вашей картины.
- Dispatch workgroups (8×8 = 64 threads per group). GPU делит работу на группы потоков (workgroups). Здесь каждая группа состоит из 8×8 = 64 потоков. Каждый поток выполняет часть вычислений.
Пример:
Представьте, что вы красите забор. Вместо того чтобы красить его одному, вы нанимаете 64 человека (потоков), каждый из которых красит свой кусочек. Работа идёт гораздо быстрее.
- Staging буфер + map_async + flume-канал для безопасного чтения результата. Staging буфер — временная память, куда GPU копирует результаты, чтобы их можно было прочитать на CPU. map_async — асинхронное чтение данных из GPU, чтобы не блокировать основную программу. flume-канал — безопасный способ передачи данных между потоками в Rust.
Пример:
Представьте, что вы печёте пирог (GPU делает вычисления). Чтобы не обжечься, вы сначала кладёте его на поднос (staging буфер), потом аккуратно переносите на стол (map_async), и finally передаёте гостям через сервировку (flume-канал).
Многопоточность: Вычисление Mandelbrot запускается в отдельном std::thread::spawn (не блокирует Bevy-рендер). Вычисление Mandelbrot запускается в отдельном потоке, чтобы не блокировать основной рендер (отрисовку) в Bevy (игровом движке).
Пример:
Представьте, что вы готовите ужин и одновременно разговариваете по телефону. Вы не хотите, чтобы приготовление еды мешало разговору, поэтому делаете их параллельно.
4. Bevy приложение (ECS архитектура + интеграция всего)
main() — стандартный Bevy App — это игровой движок на языке Rust. DefaultPlugins — набор стандартных модулей (плагинов), которые добавляют базовую функциональность: окно, графику, обработку событий и т.д.
Пример:
Представьте, что вы строите дом. DefaultPlugins — это фундамент, стены и крыша, без которых дом не будет домом.
- DefaultPlugins + WindowPlugin (1280×720). Плагин, который создаёт окно для вашего приложения с разрешением 1280 на 720 пикселей.
Пример:
Как экран телевизора: вы указываете, какой он будет по размеру. - EguiPlugin, RapierPhysicsPlugin + DebugRender. EguiPlugin — добавляет интерфейс (кнопки, графики, меню). RapierPhysicsPlugin — добавляет физику (гравитация, столкновения).
Пример:
Egui — как панель управления в игре (меню, кнопки).
Rapier — как законы физики: если бросить мяч, он упадёт на пол. - insert_non_send_resource(MlManager::new()) — модель только в main thread. Создаётся ресурс MlManager (например, для машинного обучения), который работает только в основном потоке программы.
Пример:
Как если бы у вас был помощник, который может работать только в одной комнате (основной поток). - Startup системы: setup_scene, setup_compute_backends. Startup системы — функции, которые выполняются один раз при запуске программы. setup_scene — настраивает сцену (камера, свет, объекты). setup_compute_backends — настраивает вычислительные модули (например, для работы с графикой или данными).
Пример:
Как подготовка к спектаклю: расставляют декорации (setup_scene) и настраивают свет (setup_compute_backends).
- Обычные системы: gui_system, update_compute_texture.
ComputeResources — ресурс для хранения бэкендов, текущего индекса, pending результата (Arc<Mutex<...>> для thread-safe) и текстуры. Ресурс для хранения данных, которые нужны для вычислений (например, текстуры, результаты вычислений).
Пример:
Как коробка с инструментами: там лежат всё, что нужно для работы (текстуры, результаты).
setup_compute_backends - Создаётся модуль для вычислений на GPU (видеокарте) с помощью библиотеки wgpu.
Пример:
Как если бы вы наняли суперкомпьютер для сложных расчётов, чтобы не нагружать основной компьютер.:
- Берёт wgpu device/queue из Bevy рендера.
- Создаёт WgpuComputeBackend.
- Создаёт дефолтную текстуру (серый фон).
setup_scene - SVG (векторное изображение) → Pixmap (растровое изображение) → текстура для объектов в Bevy.
Пример:
Как если бы вы нарисовали картинку на бумаге (SVG), отсканировали её (Pixmap) и наклеили на куб в игре (Bevy Image).:
- Камера, свет.
- SVG → Pixmap → Bevy Image (текстура для кубов).
- 5 динамических кубов с физикой (падают на пол).
- Пол (fixed).
- Плоскость для Mandelbrot (unlit материал с динамической текстурой).
gui_system (egui):
- Кнопка "Обучить MLP" → ml.train() (в main thread).
- Если trained — график sin(x) vs предсказание (egui_plot).
- ComboBox для выбора бэкенда (пока только wgpu).
- Кнопка "Вычислить Mandelbrot" → spawn thread с compute_mandelbrot → результат в pending.
update_compute_texture - Обновляет текстуру (картинку) на объекте, если есть новые данные.
Пример:
Как если бы вы рисовали картину и периодически добавляли новые детали.
Запускается отдельный поток для вычисления фрактала Мандельброта (сложная математическая картинка).
Пример:
Как если бы вы наняли отдельного художника, чтобы он нарисовал сложную картину, пока вы занимаетесь другими делами.
- Берёт pending результат, обновляет .data текстуры (Bevy поддерживает динамическое обновление).
5. Как всё работает вместе (поток выполнения)
- Запуск: Bevy создаёт окно, инициализирует физику, рендер, egui.
- Startup: Сцена (кубы падают), compute backend, дефолтная текстура.
- Каждый кадр:Физика обновляется (Rapier).
egui рисует окно.
Если нажата кнопка ML — тренировка (300 эпох ~0.1-0.5 сек на CPU).
График обновляется.
Если нажата кнопка Mandelbrot — отдельный поток вычисляет на GPU (быстро), результат копируется в текстуру → плоскость показывает фрактал. - Многопоточность: Rayon для данных ML, thread для GPGPU — рендер/UI не фризится.