← к содержанию

Урок 11. Простой способ загрузки 3D-объектов

В нескольких предыдущих уроках мы добавляли 3D-объекты на сцену последовательно: сначала загружали (или даже создавали с нуля) меш, строили на его основе объект, затем настраивали его материал, например, изменяли цвет или прицепляли текстуру. Все эти действия можно описать в текстовом файле формата json с расширением .ob, и тогда можно будет загружать из ресурсов готовый 3D-объект всего одной строкой. DDD будет выполнять все действия по загрузке меша (и, возможно, связанного с ним скелета) и настройке материала за кулисами. Вам останется только присоединить этот объект к нужному Месту, и, если всё прошло без ошибок, объект появится на экране. Такая загрузка 3D-объектов является темой данного урока.

Фактически загрузка и вывод на экран одного объекта занимает всего три строки программы, и, если бы урок ограничился только этим, то он бы занял всего пару абзацев. Поэтому я решил в цикле вывести на экран несколько объектов.

  1. Откройте модуль scena.d и добавьте в него импорт модуля стандартной библиотеки std.random, содержащий генераторы случайных чисел и функции работы с этими генераторами:

import std.math, std.conv, std.random;
  1. Переходите к концу функции сцена, и объявите там несколько переменных, с которыми мы будем в дальнейшем работать:

    Объект объект_мяч;
    Место место_мяча;
    string название_места;
    Кватернион поворот;
  1. Определим список названий объектов, которые мы будем загружать:

    auto типы_мячей = ["детский мячик", "волейбольный мяч", "футбольный мяч"];

Если вы посмотрите содержимое каталога ресурсов ресурсы/объекты, то найдёте там несколько текстовых файлов с расширением .ob с содержимым в json-формате. В них описываются все атрибуты 3D-объекта: имя, данные меша и данные материала. Вот пример файла детский мячик.ob:

{
    "имя": "детский мячик",
    "меш": {
        "имя": "детский мячик"
    },
    "материал": {
        "диффузная_текстура": "детский мячик"
    }
}

Имя в данных меша должно соответствовать имени ресурса меша, также в этих данных может присутствовать поле скелет с именем соответствующего ресурса (но скелеты и скелетная анимация не являются темой данного урока). Данные материала кроме имени ресурса текстуры может содержать другие параметры материала: различные виды цвета, степень блика и т. д., полный перечень полей приведён в документации к модулю ddd.material.

Объекты, которые мы будем загружать в данном уроке (различные мячи) являются самыми простыми — в них есть только название ресурса меша и ресурса текстуры.

  1. Мы будем заполнять места в матрице из мячей, для этого объявим два вложенных цикла, проходящих по координатам X и Y соответственно:

    for (int x=-3; x<-1; x++)
        for (int y=-2; y<3; y++) {
        }

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

  1. Входим внутрь фигурных скобок, окаймляющих тело цикла, и добавляем туда:

            объект_мяч = менеджер.получить_объект(choice(типы_мячей));

Функция choice из модуля стандартной библиотеки std.random случайным образом выбирает и возвращает один из элементов массива, переданного ей. Т.к. мы ей передаём наш массив со строками — названиями ресурсов объектов, то функция будет возвращать одно из этих названий. Функция менеджера получить_объект по полученному ей названию ресурса возвращает 3D-объект (если при загрузке всех требуемых ресурсов, создании самого объекта и его составляющих не произошло никаких ошибок).

  1. Теперь нам нужно создать Место, к которому будет присоединён наш объект мяча.

    1. Одним из обязательных параметров в конструкторе класса Место является имя создаваемого экземпляра. Это имя должно быть уникальным. Для обеспечения уникальности имён всех Мест нам придётся создавать такие имена специальным образом, а именно добавим к слову «мяч» координаты мяча:

            название_места = "мяч_" ~ to!string(x) ~ "_" ~ to!string(y);
    1. Чтобы мячи были повёрнуты случайным образом, создадим кватернион поворота с помощью функции получения случайного числа uniform01:

            поворот = Кватернион((uniform01()-0.5)*PI, Вектор3(uniform01(), uniform01(), uniform01()));
    1. Теперь у нас всё готово, и мы можем создать требуемое Место:

            место_мяча = менеджер.начальное_место.создать_ребёнка(название_места,
                                                                  Вектор3(x, y, 0),
                                                                  поворот,
                                                                  Вектор3(0.5f, 0.5f, 0.5f));

Четвёртым аргументом мы передаём масштаб (уменьшаем все мячи в два раза), т. к. изначальные меши мячей для нашей сцены крупноваты.

  1. Осталось только присоединить наш объект к Месту:

            место_мяча.присоединить_объект(объект_мяч);
  1. Если вы всё сделали правильно, то результат должен быть похожим на это:


При каждом новом запуске программы конкретный состав мячей будет различным.

Благодаря тому, что мы вывели на экран сразу 10 объектов вместо одного, урок получился не таким уж и маленьким. Но, фактически, к теме самого урока относятся только объяснение структуры .ob-файла в пункте 3 и получение объекта мяча в пункте 5, остальное можно считать «нескучным дополнением».

На приведённом скриншоте хорошо видно, что мы уже загадили заполнили различными объектами всю эту сцену, так что следующий урок мы начнём с новой пустой сцены.