В нескольких предыдущих уроках мы добавляли 3D-объекты на сцену последовательно: сначала загружали (или даже создавали с нуля) меш, строили на его основе объект, затем настраивали его материал, например, изменяли цвет или прицепляли текстуру. Все эти действия можно описать в текстовом файле формата json с расширением .ob, и тогда можно будет загружать из ресурсов готовый 3D-объект всего одной строкой. DDD будет выполнять все действия по загрузке меша (и, возможно, связанного с ним скелета) и настройке материала за кулисами. Вам останется только присоединить этот объект к нужному Месту, и, если всё прошло без ошибок, объект появится на экране. Такая загрузка 3D-объектов является темой данного урока.
Фактически загрузка и вывод на экран одного объекта занимает всего три строки программы, и, если бы урок ограничился только этим, то он бы занял всего пару абзацев. Поэтому я решил в цикле вывести на экран несколько объектов.
Откройте модуль scena.d и добавьте в него импорт модуля стандартной библиотеки std.random, содержащий генераторы случайных чисел и функции работы с этими генераторами:
import std.math, std.conv, std.random;
Переходите к концу функции сцена, и объявите там несколько переменных, с которыми мы будем в дальнейшем работать:
Объект объект_мяч; Место место_мяча; string название_места; Кватернион поворот;
Определим список названий объектов, которые мы будем загружать:
auto типы_мячей = ["детский мячик", "волейбольный мяч", "футбольный мяч"];
Если вы посмотрите содержимое каталога ресурсов ресурсы/объекты, то найдёте там несколько текстовых файлов с расширением .ob с содержимым в json-формате. В них описываются все атрибуты 3D-объекта: имя, данные меша и данные материала. Вот пример файла детский мячик.ob:
{ "имя": "детский мячик", "меш": { "имя": "детский мячик" }, "материал": { "диффузная_текстура": "детский мячик" } }
Имя в данных меша должно соответствовать имени ресурса меша, также в этих данных может присутствовать поле скелет с именем соответствующего ресурса (но скелеты и скелетная анимация не являются темой данного урока). Данные материала кроме имени ресурса текстуры может содержать другие параметры материала: различные виды цвета, степень блика и т. д., полный перечень полей приведён в документации к модулю ddd.material.
Объекты, которые мы будем загружать в данном уроке (различные мячи) являются самыми простыми — в них есть только название ресурса меша и ресурса текстуры.
Мы будем заполнять места в матрице из мячей, для этого объявим два вложенных цикла, проходящих по координатам X и Y соответственно:
for (int x=-3; x<-1; x++) for (int y=-2; y<3; y++) { }
Можно заметить, что координаты X у нас отрицательные, это для того, чтобы мячами заполнялась пустая область слева нашей сцены (центральную и правую части мы уже заполнили в предыдущих уроках).
Входим внутрь фигурных скобок, окаймляющих тело цикла, и добавляем туда:
объект_мяч = менеджер.получить_объект(choice(типы_мячей));
Функция choice из модуля стандартной библиотеки std.random случайным образом выбирает и возвращает один из элементов массива, переданного ей. Т.к. мы ей передаём наш массив со строками — названиями ресурсов объектов, то функция будет возвращать одно из этих названий. Функция менеджера получить_объект по полученному ей названию ресурса возвращает 3D-объект (если при загрузке всех требуемых ресурсов, создании самого объекта и его составляющих не произошло никаких ошибок).
Теперь нам нужно создать Место, к которому будет присоединён наш объект мяча.
Одним из обязательных параметров в конструкторе класса Место является имя создаваемого экземпляра. Это имя должно быть уникальным. Для обеспечения уникальности имён всех Мест нам придётся создавать такие имена специальным образом, а именно добавим к слову «мяч» координаты мяча:
название_места = "мяч_" ~ to!string(x) ~ "_" ~ to!string(y);
Чтобы мячи были повёрнуты случайным образом, создадим кватернион поворота с помощью функции получения случайного числа uniform01:
поворот = Кватернион((uniform01()-0.5)*PI, Вектор3(uniform01(), uniform01(), uniform01()));
Теперь у нас всё готово, и мы можем создать требуемое Место:
место_мяча = менеджер.начальное_место.создать_ребёнка(название_места, Вектор3(x, y, 0), поворот, Вектор3(0.5f, 0.5f, 0.5f));
Четвёртым аргументом мы передаём масштаб (уменьшаем все мячи в два раза), т. к. изначальные меши мячей для нашей сцены крупноваты.
Осталось только присоединить наш объект к Месту:
место_мяча.присоединить_объект(объект_мяч);
Если вы всё сделали правильно, то результат должен быть похожим на это:
При
каждом новом запуске программы конкретный
состав мячей будет различным.
Благодаря тому, что мы вывели на экран сразу 10 объектов вместо одного, урок получился не таким уж и маленьким. Но, фактически, к теме самого урока относятся только объяснение структуры .ob-файла в пункте 3 и получение объекта мяча в пункте 5, остальное можно считать «нескучным дополнением».
На приведённом
скриншоте хорошо видно,
что мы уже загадили
заполнили различными объектами всю эту
сцену, так что следующий
урок мы начнём с новой пустой сцены.