Главная » Игры » LDraw + Unity. Как я Lego генерировал

LDraw + Unity. Как я Lego генерировал

Всех с наступающим! Меня зовут Гриша, и я основатель CGDevs. Уже не за горами праздники, кто-то уже нарядил ёлку, поел мандаринов и во всю заряжается новогодним настроением. Но сегодня речь пойдёт не об этом. Сегодня мы поговорим про замечательный формат под названием LDraw и про плагин для Unity, который я реализовал и выложил в OpenSource. Ссылка на проект и исходники к статье, как всегда, прилагаются. Если вы так же, как и я любите лего – добро пожаловать под кат.

LDraw – это открытый стандарт для LEGO CAD программ, позволяющий пользователям создавать модели и сцены LEGO.
Формат LDraw
Начнём с того, что такое LDraw? 0. В целом существую разные программы и плагины, с помощью которых можно визуализировать LDraw (к примеру, есть плагин для Blender).
Сам формат хорошо задокументирован, и мы поговорим про его последнюю версию, а точнее про 1. 2.

Файлы, поддерживаемые форматом, должны иметь расширение ldr, dat или mdp. LDraw – это текстовый формат, файлы которого должны быть созданы с кодировкой UTF-8. Каждая строка файла – это отдельная команда, отвечающая за определённую функцию.
Важной деталью формата является правосторонняя система координат (Y направлен вверх) – подробнее обсудим позже в контексте юнити, а также то, что формат является рекурсивным (большая часть файлов содержит указание на другие файлы)

Команды LDraw

Всего формат LDraw поддерживает 6 типов команд. В целом с этой информацией можно ознакомиться в официальной документации, но рассмотрим немного в контексте Unity.

Комментарий или мета команда – это специальные команды, которых мы почти не будем касаться в плагине. 0. META command additional parameters Пример: 0 !

Ссылка на файл. 1. Выглядит она как — 1 colour x y z a b c d e f g h i file, где параметры являются TRS матрицей (подробнее про TRS можно прочитать в этой статье). По сути, самая сложная в интеграции и интересная команда. В контексте юнити в форме
/ a d g 0 \
| b e h 0 |
| c f i 0 |
\ x y z 1 /

Линия – не используется в случае Unity, нужно чтобы подчеркнуть грани определённым цветом в CAD системах. 2.

Треугольник и квадрат. 3,4. Это важно, так как-то же юнити в зависимости от обхода треугольника определяет направление calculated нормали, а также какая сторона треугольника является задней, а какая передней (что так же важно для отрисовки и куллинга) Команды достаточно простые, но есть один важный нюанс, так как формат LDraw не рассчитан на 3д моделирование, то обход треугольников и квадратов в нём не стандартизирован.

Пример команд:
Треугольник — 3 colour x1 y1 z1 x2 y2 z2 x3 y3 z3
Квадрат — 4 colour x1 y1 z1 x2 y2 z2 x3 y3 z3 x4 y4 z4

Опциональная линия – тоже не используется. 5.

Цвета в LDraw

Цвета хорошо задокументированы в этих двух статьях www.ldraw.org/article/299.html и www.ldraw.org/article/547.html, но поговорим про особенности, с которыми я столкнулся при реализации. Как можно заметить в большинстве команд, отвечающих за отрисовку, цвет идёт сразу после типа команды. В формате присутствуют 3 типа файлов. Тут стоит чуть подробнее поговорить про форматы и так называемый “Scope” формата.

Если не рендерить отдельные детали – указанный в них цвет не важен. DAT – по сути это базовые элементы из которых уже собираются детали, либо какие-то базовые детали. Чаще всего там стоят стандартные цвета официального стандарта.

Правило довольно простое, хотя на сайте описано сложным языков. LDR – это самое интересное, с точки зрения цветов, и где Scope играет роль. Если вы из одного ldr ссылаетесь на другой – игнорируйте цвет указанный в корневом.

Для примера часть файла 30051-1 — X-wing Fighter — Mini.mpd (X-wing на картинке выше):

Пример

1 71 -10 0 50 0 0 1 0 1 0 -1 0 0 60470a.dat
1 71 10 0 50 0 0 -1 0 1 0 1 0 0 60470a.dat
0 STEP
1 19 0 8 50 0 0 -1 0 1 0 1 0 0 4032b.dat
0 STEP
0 ROTSTEP 35 55 0 ABS
1 19 0 -16 0 0 0 -1 0 1 0 1 0 0 3623.dat
1 72 0 -16 50 0 0 -1 0 1 0 1 0 0 3022.dat
0 STEP
1 72 0 -8 -70 1 0 0 0 1 0 0 0 1 30051 - Nose.ldr

Во всех dat файлах мы учитываем указанный цвет, а в команде 1 72 0 -8 -70 1 0 0 0 1 0 0 0 1 30051 — Nose.ldr – игнорируем 72, и используем значения из файла 30051 — Nose.ldr.

С точки зрения цвета так же не особо важен. MDP – это файл модели, чаще всего содержит в себе описание нескольких ldr файлов. Единственное, что мы учитываем при парсинге — это мета-команду FILE.

Модели в LDraw

Многие интересные наборы можно найти на официальном сайте omr.ldraw.org, но, помимо этого, многие можно найти на отдельных форумах.
Про формат поговорили, теперь пора поговорить немного про плагин для Unity. Самое прекрасное в формате LDraw, что у него достаточно много фанатов среди любителей лего.

Плагин для Unity

Результаты вы можете увидеть в картинках из статьи. Плагин предоставляет возможность генерировать 3д модели на основе файлов LDraw. Модели не оптимизированы и всегда генерируют backface. Важно: если у вас слабое устройство, лучше открывайте только сцены mini в папке Demo.

На данный момент поддержана большая часть описанного выше. А теперь поговорим немного про реализацию.

Проблема в том, что в формате правосторонняя система координат, а в Unity – левосторонняя. Одной из, пожалуй, самых главных особенностей являются разные системы координат. Отрицательный Y обыграть просто – отражаем все координаты относительно Vector3.up и получаем нужные (умножаем на -1). Что это, по сути, означает, что все повороты и TRS матрица будут работать неверно. Так как формат рекурсивный, то просто отражать матрицу – нельзя, так как Matrix. Но вот в случае с TRS матрицей всё сложнее. Пока я пришёл к не совсем верному решению в виде того, что разрешил отрицательный scale, что нужно будет переделать в будущих версиях. Identity везде превратится в матрицу отражения и каждая вложенность будет отражать нашу модель по оси Y, что приведёт к неправильному отображению (если сохранять положительный scale).

Для квадов реализовано то, чтобы треугольники смотрели в одну сторону: Вторая особенность, это ориентация треугольников.

Код подготовки для квадратов

public override void PrepareMeshData(List<int> triangles, List<Vector3> verts)
); var indexes = Vector3.Dot(nA, nB) > 0 ? new int[] {0, 1, 3, 2} : new int[] {0, 1, 2, 3}; for (int i = 0; i < indexes.Length; i++) { verts.Add(v[indexes[i]]); }
}

Но вот однозначно определить базируясь на формате, в какую сторону в принципе должны быть направлены треугольники — нетривиальная задача. По этой причине сейчас генерируются обе стороны всегда.

Кроме того, из-за того, что формат рекурсивный, иерархическая система Unity пришлась как никогда кстати.

С помощью рекурсии в двух методах, мы генерируем нужные нам меши и применяем TRS (реализацию можно прочитать в прошлой статье), и таким образом получаем в удобном формате все необходимые для нас смещения:

Методы для генерации модели на сцене


public class LDrawModel
{
public GameObject CreateMeshGameObject(Matrix4x4 trs, Material mat = null, Transform parent = null) { if (_Commands.Count == 0) return null; GameObject go = new GameObject(_Name); var triangles = new List<int>(); var verts = new List<Vector3>(); for (int i = 0; i < _Commands.Count; i++) { var sfCommand = _Commands[i] as LDrawSubFile; if (sfCommand == null) { _Commands[i].PrepareMeshData(triangles, verts); } else { sfCommand.GetModelGameObject(go.transform); } } if (mat != null) { var childMrs = go.transform.GetComponentsInChildren<MeshRenderer>(); foreach (var meshRenderer in childMrs) { meshRenderer.material = mat; } } if (verts.Count > 0) { var visualGO = new GameObject("mesh"); visualGO.transform.SetParent(go.transform); var mf = visualGO.AddComponent<MeshFilter>(); mf.sharedMesh = PrepareMesh(verts, triangles); var mr = visualGO.AddComponent<MeshRenderer>(); if (mat != null) { mr.sharedMaterial = mat; } } go.transform.ApplyLocalTRS(trs); go.transform.SetParent(parent); return go; }
}
public class LDrawSubFile : LDrawCommand
{ public void GetModelGameObject(Transform parent) { _Model.CreateMeshGameObject(_Matrix, GetMaterial(), parent); }
}

И по итогу мы получаем такие красивые визуализации:

Подробнее можно посмотреть в репозитории на Github.

Сглаживание некоторых форм
2. В целом по развитию плагина очень много идей, хочется ввести такие функциональности, как:
1. Конструктор и выгрузка моделей обратно в формат LDraw
4. Генерация только front face
3. Unwrap UV для лайтмапов
6. По круче шейдер для пластика с subsurface scattering (и правильный набор материалов в целом)
5. 8 миллона полигонов) Оптимизация моделей (сейчас большинство состоят из 500к+, а к примеру модель эйфелевой башни 2.

(Все изображения для статьи сделаны с помощью плагина) Весь код проекта выложен под MIT лицензией, но вот лицензию на конкретные модели советую смотреть на ресурсах LDraw. Но и на данный момент, плагин позволяет использовать модельки из лего в Unity3d, что достаточно прикольно.

Если будет время – буду продолжать его развивать и буду рад помощи в этом нелёгком деле. Спасибо за внимание, надеюсь вы узнали для себя что-то новое, и вас заинтересовал формат и плагин!


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

Все лунные растения погибли

Не успело человечество порадоваться первым растениям, выращенным на поверхности Луны (в биоконтейнере космического зонда «Чанъэ-4»), как в тот же день от китайских учёных пришло печальное известие: все лунные растения погибли. Эксперимент завершён.Главный проектировщик эксперимента, профессор Чунцинского университета Се Гэнсинь (Xie ...

SAP HANA: где и как эффективно использовать big data и машинное обучение

На парковке аэропорта установлены 20 шлагбаумов для въезда. Рассмотрим конкретный кейс. Зима. Чтобы отслеживать нарушителей, камера распознавания номерных знаков строго фиксирует номер автомобиля, и только после этого открывается шлагбаум. Все номера автомобилей в снегу. Ухудшение погодных условий. Как итог — ...