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

Урок 12. Пример простой анимации объектов

Настало время добавить на экран движений. В этом уроке рассматривается самый простой вариант анимации – движения и вращения объектов, которые сами по-себе остаются неизменяемыми, статическими. Изменениям подвергаются только объекты Место, к которым эти 3D-объекты присоединены.

Мы заставим игрушечный самолётик двигаться на экране по окружности. Он состоит из двух объектов: собственно корпуса самолёта с крыльями и, отдельным объектом, винта. Каждый из этих объектов будет присоединён к своему Месту, и каждое из них будет двигаться по-своему.

  1. Создайте новый пустой файл scena.d вместо того, что мы использовали в предыдущих уроках. Небольшую часть оттуда мы здесь почти повторим, но и её проще вписать заново, чем разбираться, что удалить, а что исправить.

Добавим в модуль необходимые импорты:

import std.math, std.conv;
import ddd, ddd.mesto, ddd.lamp, ddd.vector, ddd.quaternion, ddd.ddd_object;
  1. Добавим пару констант, которые будут управлять скоростью движения самолётика и скоростью вращения его винта:

const float СКОРОСТЬ_САМОЛЁТА = 1f;
const float СКОРОСТЬ_ВИНТА = 10f;
  1. Определим переменные для хранения объектов Место, которые мы будем изменять в каждом кадре:

Место центральное_место, место_винта;
  1. Снова создайте функцию сцена и добавьте туда код, задающий цвет фона и создающий освещение. Этот код почти целиком (за исключением координат расположения лампы и цвета фона) повторяет начало функции сцена из четвёртого урока (и последующих):

void сцена() {

    менеджер.визуализатор.задать_цвет_фона([0.5, 0.8, 1, 1]); // Голубой цвет
    
    auto лампа0 = new Лампа("свет0", 0);
    лампа0.задать_диффузный_свет([1,1,1,1]);   // Белый цвет
    auto место_лампы0 = менеджер.начальное_место.создать_ребёнка("Место лампы0", 
                                                       Вектор3(2,2,6),
                                                       Кватернион.НОЛЬ);
    место_лампы0.присоединить_объект(лампа0);
}
  1. Создадим объект Места, которое будет родительским по отношению к местам самолётика и (косвенно) винта, будет участвовать в движении этих объектов, но к нему самому мы 3D-объекты крепить не будем:

    центральное_место = менеджер.начальное_место.создать_ребёнка("Центральное место",
                                                    Вектор3(0, 0, 1),
                                                    Кватернион(0, Вектор3(0, 0, 1)));

Это центральное_место будет центром всей сцены, и именно оно будет задавать общее вращение всей сцене.

  1. Теперь приступим к рисованию самолёта.

    1. Получим объект самолётика из ресурсов:

    auto объект_самолётик = менеджер.получить_объект("самолётик");
    1. Создадим объект Места, к которому будет крепиться самолётик:

    auto место_самолётика = центральное_место.создать_ребёнка("Место самолётика",
                                            Вектор3(0, -1, 0),
                                            Кватернион(-PI/2, Вектор3(0, 1, 0)));

Передаваемые в конструктор координаты задают сдвиг от центра на одну единицу расстояния по координате Y (вниз, т. к. стоит -1). Кроме того, задаётся поворот на 90 градусов вокруг вертикальной оси, т. к. меш самолёта смоделирован с видом «сзади», а нам сейчас нужен вид «сбоку».

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

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

    auto объект_винт = менеджер.получить_объект("винт самолётика");
    место_винта = место_самолётика.создать_ребёнка("Место винта",
                                            Вектор3(0, 0, 0),
                                            Кватернион.НОЛЬ);	
    место_винта.присоединить_объект(объект_винт);

В данный момент мы здесь не делаем никаких сдвигов и поворотов относительно родительского Места.

Теперь, если вы скомпилируете и запустите ваше приложение, то должны получить такую картинку с готовым к старту самолётиком:



  1. Чтобы заставить его двигаться, создайте в модуле scena.d новую функцию обновление_сцены с одним аргументом длительность_кадра типа float. Она будет вызываться каждый кадр, в её аргументе будет находиться время, прошедшее после предыдущего кадра в секундах (обычно это число сильно меньше единицы).

void обновление_сцены(float длительность_кадра) {
}
    1. Внутрь этой функции добавьте команды, которые будут задавать поворот объектов центральное_место и место_винта вокруг их локальной оси Z:

    центральное_место.крен(длительность_кадра * СКОРОСТЬ_САМОЛЁТА);
    место_винта.крен(длительность_кадра * СКОРОСТЬ_ВИНТА);
  1. Осталось последнее действие – мы должны указать менеджеру DDD, что наша новая функция является функцией обновления сцены. Откройте модуль urok.d и вставьте такую команду перед вызовом функции запустить_визуализацию:

менеджер.задать_функцию_обновления_сцены(&обновление_сцены);
  1. Если вы все сделали правильно, то после компиляции в окне вашей программы самолётик должен двигаться по круговой орбите вокруг центра окна, а его винт самостоятельно вращаться:



  1. Вы можете попробовать поизменять значение констант, определённых в шаге 2, и это должно влиять на скорость движения самолётика и скорость вращения его винта. Если вы не пропускали шестой урок про настройки программы, то можете попробовать преобразовать эти константы в настройки, чтобы можно было влиять на эти две скорости без перекомпиляции программы.