Magis3D
Проектирование и разработка web-сервиса обработки 3D-моделей
Ссылка на проект
Что решает Magis3D

- создание 3D-поверхностей по формулам;
- загрузка CSV/TXT и построение сетки;
- импорт OBJ-моделей в сцену;
- сохранение и экспорт результата.
Проект показывает полный путь от входных данных до готовой 3D-сцены.
Путь пользователя в системе
- пользователь входит в систему или продолжает работу как гость;
- в рабочей области создаёт поверхность, загружает файл или импортирует модель;
- результат обрабатывается в браузере и сразу отображается в 3D-окне;
- готовая сцена сохраняется в базе или выгружается в файл.
Стартовый экран

- аккаунт нужен для сохранения сцен;
- гостевой режим оставляет быстрый доступ;
- после входа открывается рабочая область.
Создание аккаунта

- производится проверка полей до создания аккаунта;
- email приводится к единому виду;
- пароль не сохраняется открытым текстом;
- после регистрации выдаётся токен сессии.
Проверка данных на сервере
router.post('/register', async (req, res) => {
const { name, email, password } = req.body || {};
// Производится проверка обязательных полей.
if (!name || !email || !password) {
return res.status(400).json({ error: 'Заполните все поля' });
}
// Email нормализуется перед записью и сравнением.
const normalizedEmail = String(email).toLowerCase().trim();
// Пароль хранится только в виде bcrypt-хэша.
const passwordHash = await bcrypt.hash(String(password), 10);
// После создания аккаунта формируется токен сессии.
const token = createToken(user);
return res.status(201).json({ user, token });
});
Валидация выполняется на backend, поэтому её нельзя обойти изменением интерфейса.
Пароль преобразуется в bcrypt-хэш, а клиент получает JWT для дальнейших запросов.
Восстановление входа
const savedToken = localStorage.getItem('authToken');
// Если токен есть, выполняется запрос /auth/me.
if (savedToken) {
this.fetchMe(savedToken)
.then(user => {
// Сессия восстановлена без повторного ввода пароля.
this.currentUser = user;
this.isGuest = false;
this.showApp();
})
.catch(() => {
// Некорректный токен удаляется из браузера.
localStorage.removeItem('authToken');
localStorage.removeItem('currentUser');
});
}
Приложение проверяет сохранённый токен.
Пользователь не вводит пароль каждый раз.
При ошибке сессия безопасно сбрасывается.
Окно рендера и панели управления

- рендер занимает центральную часть интерфейса;
- панели отвечают за создание, импорт, сохранение и экспорт;
- изменения сразу отображаются в 3D-окне.
Запуск модулей приложения
initMainApp() {
// Создаётся viewer на базе Three.js.
this.viewer = new SurfaceViewer('viewer-container', this.authManager);
// Менеджер поверхностей связывается с областью рендера.
this.surfaceManager = new SurfaceManager(this.viewer, this.authManager);
this.viewer.setSurfaceManager(this.surfaceManager);
// Отдельные классы отвечают за сцены, генерацию и OBJ.
this.sceneManager = new SceneManager(this.authManager, this.surfaceManager);
this.generator = new SurfaceGenerator();
this.objProcessor = new OBJModelProcessor();
}
Viewer отвечает за отображение сцены.
SurfaceManager управляет объектами.
Генератор и OBJ-процессор вынесены отдельно.
Параметрическая поверхность

- задаются диапазоны параметров u и v;
- для каждой точки вычисляются x, y, z;
- точки соединяются в треугольную сетку;
- готовая геометрия передаётся в Three.js.
Формулы превращаются в 3D-сетку
// Для каждого узла параметрической сетки вычисляются координаты.
for (let i = 0; i <= uSeg; i++) {
for (let j = 0; j <= vSeg; j++) {
const u = uMin + i * uStep;
const v = vMin + j * vStep;
const x = this.parser.evaluate(eqX, { u, v }) * scale;
const y = this.parser.evaluate(eqY, { u, v }) * scale;
const z = this.parser.evaluate(eqZ, { u, v }) * scale;
vertices.push(x, y, z);
}
}
// Соседние точки объединяются в треугольники для WebGL.
triangleIndices.push(a, b, d);
triangleIndices.push(a, d, c);
Формулы вычисляются много раз по сетке.
Результат хранится как массив вершин.
Треугольники нужны для WebGL-рендера.
Построение поверхности по таблице

- файл загружается на сервер;
- разделитель определяется автоматически;
- из строк выбираются координаты X/Y/Z;
- точки преобразуются в поверхность.
Ограничение формата и разбор координат
const upload = multer({
fileFilter: (req, file, cb) => {
// Загрузка разрешена только для CSV/TXT файлов.
if (/\.(csv|txt)$/i.test(file.originalname)) cb(null, true);
else cb(new Error('Допустимы только CSV/TXT файлы'));
},
limits: { fileSize: 80 * 1024 * 1024 }
});
// Строки файла преобразуются в числовые X/Y/Z точки.
const rows = lines.map(line => parseCSVLine(line, delim));
const { indices, hasHeader } = resolveXYZColumns(rows, delim);
Сервер принимает только нужные типы файлов.
Есть ограничение размера загрузки.
Координаты приводятся к внутреннему формату.
Готовая 3D-модель в сцене

- OBJ содержит вершины и грани модели;
- модель разбирается в браузере;
- геометрия приводится к формату сцены;
- объект отображается вместе с остальными элементами.
Разбор вершин и граней
lines.forEach((line) => {
const parts = line.trim().split(/\s+/);
// Строки v содержат координаты вершин.
if (parts[0] === 'v') {
positions.push(Number(parts[1]), Number(parts[2]), Number(parts[3]));
}
// Строки f содержат грани модели.
if (parts[0] === 'f') {
const face = parts.slice(1).map(token => this.parseFaceIndex(token));
for (let i = 1; i < face.length - 1; i++) {
triangles.push(face[0], face[i], face[i + 1]);
}
}
});
Вершины попадают в массив координат.
Грани разбиваются на треугольники.
После разбора модель можно рендерить.
Нормализация модели

- производится проверка индексов граней;
- повторяющиеся вершины объединяются;
- рассчитываются границы и размеры модели;
- модель становится совместима со сценой.
Запись сцены пользователя

- сохранение доступно авторизованному пользователю;
- сцена связывается с аккаунтом;
- данные сцены хранятся как JSON;
- превью используется для галереи.
Сцена записывается в SQLite
router.post('/', authenticateToken, async (req, res) => {
const { title, sceneData, previewImage } = req.body;
// Сохранение разрешено только после авторизации.
if (!title || !sceneData) {
return res.status(400).json({ error: 'Название и данные обязательны' });
}
// Сцена связывается с id текущего пользователя.
await run(`INSERT INTO scenes
(user_id, title, scene_data, preview_image)
VALUES (?, ?, ?, ?)`,
[req.user.id, title.trim(), JSON.stringify(sceneData), previewImage]
);
});
Middleware определяет пользователя по JWT.
Данные сцены сериализуются в JSON.
Запись можно восстановить при открытии.
Публичные сцены из базы

- выводятся публичные сцены;
- показываются автор, дата и превью;
- пользователь может открыть готовый результат.
Выгрузка результата

- экспорт разрешён только для корректной геометрии;
- OBJ подходит для дальнейшего редактирования;
- STL подходит для инженерных сценариев;
- файл формируется и скачивается из браузера.
OBJ и STL формируются из геометрии
exportSurface(surface, format) {
// Экспорт разрешён только для поверхности с геометрией.
if (!surface.vertices || !surface.triangleIndices) {
throw new Error('Некорректные данные поверхности');
}
switch (format) {
case 'obj':
content = this.exportSurfaceAsOBJ(surface);
filename = `${this.sanitizeFilename(surface.name)}.obj`;
break;
case 'stl':
content = this.exportSurfaceAsSTL(surface);
filename = `${this.sanitizeFilename(surface.name)}.stl`;
break;
}
this.downloadFile(content, filename, mimeType);
}
Сначала выполняется проверка наличия вершин.
Формат выбирается через switch.
Готовый файл отдаётся пользователю.
Интерфейс на мобильном экране

- панели перестраиваются под узкий экран;
- основные действия остаются доступны;
- 3D-viewer остаётся главным элементом;
- презентация подготовлена в 4:3 под проектор.
UML-диаграмма компонентов проекта
- frontend отделён от backend, поэтому интерфейс и API можно развивать независимо;
- Three.js отвечает только за визуализацию, а не за бизнес-логику;
- авторизация, сохранение и экспорт разделены на отдельные сервисы;
- SQLite хранит пользователей и сцены в структурированном виде.
На слайде показаны реальные зависимости, а не декоративные блоки.
Результат дипломной работы
- реализован web-сервис для интерактивной работы с 3D-сценами;
- поддержаны формулы, CSV/TXT и импорт OBJ;
- добавлены аккаунты, сохранение сцен и публичная галерея;
- реализован экспорт результата в OBJ/STL.
Полный цикл: ввод данных → обработка → визуализация → хранение → выгрузка результата.