Difference between revisions of "Basic Concept"

From Ciliz|W4
(Marked this version for translation)
 
(4 intermediate revisions by the same user not shown)
Line 3: Line 3:
 
<translate>
 
<translate>
 
<!--T:1-->
 
<!--T:1-->
В статье описаны основные решения, используемые в W4 Game Engine, и их API.
+
В статье описаны основные решения, используемые в W4 Game Engine:
 +
* Координатная истема
 +
* Нодовая система
 +
* API основных классов
 
</translate>
 
</translate>
 +
 
== Coordinate System ==
 
== Coordinate System ==
 
[[File:Concept 01.png|thumb|<translate><!--T:2--> Координатная система</translate>]] <translate><!--T:3--> Используется [https://en.wikipedia.org/wiki/Cartesian_coordinate_system#In_three_dimensions left-handed координатная система] и вращение производится против часовой стрелки, если смотреть в направлении оси.</translate>
 
[[File:Concept 01.png|thumb|<translate><!--T:2--> Координатная система</translate>]] <translate><!--T:3--> Используется [https://en.wikipedia.org/wiki/Cartesian_coordinate_system#In_three_dimensions left-handed координатная система] и вращение производится против часовой стрелки, если смотреть в направлении оси.</translate>
Line 76: Line 80:
 
| <syntaxhighlight lang="c++">void traversal(const Callback&)
 
| <syntaxhighlight lang="c++">void traversal(const Callback&)
  
void traversal(const PredicateC & predicate, const Callback&)
+
void traversal(const PredicateC & predicate, const Callback&)
  
 
template<typename T> void traversalTyped(const std::function<void(w4::cref<T>)>&);</syntaxhighlight> || <translate><!--T:19--> Выполнение функтора начиная с текущего узла и вниз по иерархии. </translate>
 
template<typename T> void traversalTyped(const std::function<void(w4::cref<T>)>&);</syntaxhighlight> || <translate><!--T:19--> Выполнение функтора начиная с текущего узла и вниз по иерархии. </translate>
Line 284: Line 288:
 
             //<translate><!--T:52--> добавляем спутник как "ребёнка" орбиты</translate>
 
             //<translate><!--T:52--> добавляем спутник как "ребёнка" орбиты</translate>
 
             orbitContainer->addChild(moonNode);
 
             orbitContainer->addChild(moonNode);
             //<translate><!--T:53--> устанавливаем позицию телав на орбите</translate>
+
             //<translate><!--T:53--> устанавливаем позицию тела на орбите</translate>
 
             moonNode->setLocalTranslation({moon.m_orbit, 0, 0});
 
             moonNode->setLocalTranslation({moon.m_orbit, 0, 0});
 
             moonNode->getMaterialInst()->setParam("baseColor", moon.m_color);
 
             moonNode->getMaterialInst()->setParam("baseColor", moon.m_color);
Line 495: Line 499:
 
<!--T:113-->
 
<!--T:113-->
 
Возможные значения параметра:</translate>
 
Возможные значения параметра:</translate>
  Animator::PlayType::Forward <translate><!--T:114--> (вперёд)</translate>,
+
  Animator::PlayType::<translate><!--T:114--> Forward (вперёд)</translate>,
  Animator::PlayType::Backward <translate><!--T:115--> (в обратном направлении)</translate>
+
  Animator::PlayType::<translate><!--T:115--> Backward (в обратном направлении)</translate>
 
|-
 
|-
 
| <syntaxhighlight lang="c++">PlayType getPlayType() const</syntaxhighlight>|| <translate><!--T:116--> Возвращает текущее направление проигрывания. Возможные значения см. в '''setPlayType'''</translate>
 
| <syntaxhighlight lang="c++">PlayType getPlayType() const</syntaxhighlight>|| <translate><!--T:116--> Возвращает текущее направление проигрывания. Возможные значения см. в '''setPlayType'''</translate>
Line 521: Line 525:
  
 
==== ParticlesEmitter ====
 
==== ParticlesEmitter ====
<translate><!--T:126-->
+
<translate>
Генератор частиц.
 
 
 
 
<!--T:127-->
 
<!--T:127-->
 
Особенности:
 
Особенности:

Latest revision as of 13:55, 19 June 2020

Other languages:
English • ‎русский

Scope

В статье описаны основные решения, используемые в W4 Game Engine:

  • Координатная истема
  • Нодовая система
  • API основных классов

Coordinate System

Координатная система

Используется left-handed координатная система и вращение производится против часовой стрелки, если смотреть в направлении оси.

Render Tree

Отображаемый на экране результат и зависимость трансформаций объектов друг от друга определяются деревом рендеринга, то есть набором объектов рендеринга. Особенности дерева рендеринга W4 Game Engine:

  • Минимальное дерево рендеринга состоит только из корневого узла.
  • У каждого узла может быть ноль или более подузлов — «детей», но при этом у узла не может быть более одного “родителя“ (самый верхний узел - “корневой“ - родителя не имеет).
  • Для того чтобы объект отобразился на экране и/или пересчитал свои данные, необходимо чтобы он находился в дереве.
  • Иерархия встроенных типов узлов показана на схеме.

Иерархия типов

Назначение и интерфейсы узлов (классов) описаны в следующих параграфах.

Примечания по использованию:

  • При рисовании в несколько проходов, у каждого прохода создаётся своё дерево со своим корневым узлом.
  • У каждого узла можно узнать локальные трансформации (то есть трансформации относительно “родителя“) и мировые, а также задать их.
  • При задании мировых координат узла пересчитываются его локальные координаты, при задании локальных - мировые.
  • У узла, не имеющего родителя трансформации совпадают.
  • Можно временно отключить узел, при этом отключаются и все его “потомки“.

Node

Node - базовый класс любого узла (в том числе RootNode).

Method Description
w4::sptr<render::RootNode> getRoot() const
Возвращает корневой узел дерева или nullptr при её отсутствии
w4::sptr<Node> clone() const
Создаёт копию узла, но не имеющую “родителя“
w4::sptr<Node> getParent() const
Возвращает “родительский“ узел или nullptr при его отсутствии
void setEnabled(bool)
Включает/выключает узел и его “потомков“
void addChild(w4::cref<Node>, bool preserveTransorm = true)

void addChild(const std::string&, w4::cref<Node>, bool preserveTransorm = true)
Добавляет “детей“ к текущему узлу. Возможно задание имени для “ребёнка“.

Параметр "preserveTransform" определяет локальные(false) или глобальные(true) трансформации, которые сохраняются у “ребёнка“.

Например, если дополнить код слева строками:

childNode->setLocalTranslation({1, 0, 0});
parentNode->addChild(childNode);

то узел childNode будет находиться в мировой позиции {1, 0, 0},

а если использовать следующие строки:

childNode->setLocalTranslation({1, 0, 0});
parentNode->addChild(childNode, false);

то узел childNode будет сдвинут на 1 по оси X относительно родителя.

void removeChild(w4::cref<Node>)

void removeChild(const std::string&)

void removeChild(const std::list<w4::sptr<Node>>&)
Отвязка “детей“ от узла по указателю, имени и списку.
void traversal(const Callback&)

void traversal(const PredicateC & predicate, const Callback&)

template<typename T> void traversalTyped(const std::function<void(w4::cref<T>)>&);
Выполнение функтора начиная с текущего узла и вниз по иерархии.

Callback имеет сигнатуру void(Node&) PredicateC - bool(w4::core::Node&)

Последний метод вызывает функтор только для тех узлов, чей тип унаследован от T

void setWorldRotation(math::Rotator::cref, math::vec3::cref worldPt)
Установка поворота относительно точки в мировых координатах
void rotateAroundPoint(const math::Rotator& rotator, const math::vec3& worldPt)
Вращение вокруг точки в мировых координатах
template<typename T> w4::sptr<T> as()

template<typename T> w4::sptr<const T> as()   const

template<typename T> T* asRaw()

template<typename T> const T* asRaw() const
Приведение типа узла (прим. указываемый тип не проверяется)
template<typename T> bool derived_from() const
Проверка, является ли класс узла потомком заданного класса
template<typename T> w4::sptr<T> getChild(const std::string&)
Получение ”ребёнка” по имени с приведением типа (прим. указываемый тип не проверяется)
std::list<w4::sptr<Node>> getAllChildren() const
Получение списка всех узлов, находящихся ниже по иерархии (“дети“, “дети детей“…)
std::list<w4::sptr<Node>> findChildren(std::string const&) const
Поиск “ребёнка“ по имени
std::list<w4::sptr<Node>> findChildrenRecursive(std::string const&) const
Поиск вниз по иерархии по имени
math::vec3::cref getWorldTranslation() const

void setWorldTranslation(math::vec3::cref)

math::vec3::cref getLocalTranslation() const

void setLocalTranslation(math::vec3::cref)
Получение и установка позиции в мировых или локальных координатах
math::vec3::cref getWorldScale() const

void setWorldScale(math::vec3::cref)

math::vec3::cref getLocalScale() const

void setLocalScale(math::vec3::cref)
Получение и установка масштаба в мировых или локальных координатах
math::vec3 getWorldUp() const

math::vec3 getWorldForward() const

math::vec3 getWorldRight() const
Получение нормализованных векторов в направлениях вверх, вперёд и вправо пространства модели в мировых координатах
math::Transform::cref getWorldTransform()     const

void setWorldTransform(math::Transform::cref)

math::Transform::cref getLocalTransform() const

void setLocalTransform(math::Transform::cref)
Получение и установка трансформации в мировых или локальных координатах. Трансформация - сочетание позиции, поворота и масштаба
math::Rotator::cref getWorldRotation() const

void setWorldRotation(math::Rotator::cref)

math::Rotator::cref getLocalRotation() const

void setLocalRotation(math::Rotator::cref)

void rotateLocal(const math::Rotator&rotator)

void rotateWorld(const math::Rotator&rotator)
Получение и установка поворота в мировых или локальных координатах. Методы rotateWorld/Local добавляют поворот к текущим значениям
const std::unordered_set<w4::sptr<Node>>& getChildren() const
Получение списка “детей“
bool isEnabled() const
Возвращает, включен ли узел
bool hasParent() const
Возвращает имеет ли узел “родителя“

Hierarchy Example

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

#include "W4Framework.h"

W4_USE_UNSTRICT_INTERFACE

class Planet
{
public:
//Немного данных о небесном теле:
// - имя
// - цвет
// - радиус (км)
// - радиус орбиты (км)
// - период оборота вокруг главного тела (дней)
// - угол отклонения орбиты относительно плоскости обращения вокруг главного тела
// - наклон оси
// - список спутников
 Planet(const std::string& name, const color& planetColor, float planetRadius, float planetOrbit, float siderealPeriod, float eclipseAngle, float axisTilt, const std::vector<Planet>& moons)
    : m_color(planetColor),
      m_radius(planetRadius),
      m_orbit(planetOrbit),
      m_siderealPeriod(siderealPeriod),
      m_eclipseAngle(eclipseAngle),
      m_axisTilt(axisTilt),
      m_moons(moons)
 {}
 color m_color;
 float m_radius;
 float m_orbit;
 float m_siderealPeriod;
 float m_eclipseAngle;
 float m_axisTilt;
 std::vector<Planet> m_moons;
};

struct SolarDemo : public IGame
{
public:
    void onStart() override
    {
        //на старте создаём солнечную систему
        createSolarSystem();
    }

    void onMove(const event::Touch::Move& evt)
    {
    }

    void onUpdate(float dt) override
    {
        for(auto& rotation: m_rotations)
        {
            //вращаем тела вокруг их главных тел со скоростью 0.5 дня в секунду
            rotation.first->rotateLocal(rotation.second * (dt / 2));
        }
    }

private:

    void createSolarSystem()
    {
        // вот она - Солнечная система!
        const Planet solarSystem("Sun", color::yellow, 695500.f, 0.f, 345.39f, 0.f, 0.f, {
            {"Mercury", color::white,                        2439.7f,   57909050.f, .241f,   7.01f,    .0352f, {}},
            {"Venus",   color::magenta,                      6051.8f,  108208000.f, .615,    3.39f, 177.36f,   {}},
            {"Earth",   color::green,                        6378.f,   149598261.f, 1.f,     0.f,    23.44f,   {
                        {"Moon", color::gray, 1737.1f,  384399.f, 1.f, 0.f, 0.f, {}}
                }},
            {"Mars",    color::red,                          3393.5f,  227939100.f, 1.88f,   1.85f,  25.19f,   {
                        {"Phobos", color::gray, 11.2667f, 9377.2f, .317f,   1.093f, 0.f, {}},
                        {"Demos",  color::gray, 10.f,   23458.f, 1.2625f,   1.85f , 0.f, {}}
                }},
            {"Jupiter", color(1.f, .5f, 0.f, 1.f),          71400.f,   778547200.f, 11.86f,  1.31f,   3.13f,   {
                        {"Callisto", color::gray, 2410.3f, 1882709.f, 16.69f, .205f, 0.f, {}},
                        {"Europa",   color::gray, 1560.8f,  671034.f, 3.55f, .471f, 0.f,  {}},
                        {"Ganymede", color::gray, 2634.1f, 1070412.f, 7.15f, .204f, 0.f,  {}},
                        {"Io",       color::gray, 1818.f,   421700.f, 1.77f, .05f, 0.f,   {}}
                }},
            {"Saturn",  (color::yellow + color::white) / 2, 60000.f,  1433449370.f, 29.46f,  2.49f,  26.73f,   {
                        {"Dione",     color::gray, 560.f,   377415.f, 2.74f,      .028f, 0.f, {}},
                        {"Enceladus", color::gray, 251.4f,  238042.f, 1.370218f, 0.f, 0.f,    {}},
                        {"Tethys",    color::gray, 530.f,   294672.f, 1.887802f, 1.091f, 0.f, {}},
                        {"Titan",     color::gray, 2575.f, 1221865.f, 15.945f,    .306f, 0.f, {}}
                }},
            {"Uranus",  color::cyan,                        25600.f,  2876679082.f, 84.01f,  .77f,   97.77f,   {
                        {"Ariel",   color::gray, 578.9f,  191020.f, 2.520379f,  .26f,  0.f, {}},
                        {"Oberon",  color::gray, 761.4f,  583520.f, 13.463239f, .058f, 0.f, {}},
                        {"Titania", color::gray, 588.9f,  435910.f, 8.705872f,  .34f , 0.f, {}},
                        {"Umbriel", color::gray, 584.7f,  266300.f, 4.144177f,  .205f, 0.f, {}}
                }},
            {"Neptune", color::blue,                        24300.f,  4503443661.f, 164.79f, 1.77f,  28.32f,   {
                        {"Triton", color::gray, 1353.4, 4503443661.f, 164.79f, 1.77f, 0.f, {}}
                }}
        });

        //Создаём Солнце
        auto sun = Mesh::create::sphere(solarSystem.m_radius, 10, 10);
        //Добавляем его в корневой узел
        Render::getRoot()->addChild(sun);

        //Устанавливаем цвет для базового материала
        sun->getMaterialInst()->setParam("baseColor", solarSystem.m_color);
        //Создаём планеты
        createMoons(sun, solarSystem);
        //Устанавливаем масштаб. Увы, расстояния такие, что с реальными расстояниями без лупы видно только Солнце... Но это пример.
        sun->setLocalScale({1.e-7f, 1.e-7f, 1.e-7f});
    }
    void createMoons(cref<Node> planetNode, const Planet& planet)
    {
        //для каждого спутника
        for(const auto& moon: planet.m_moons)
        {
            //для иллюстрации вложенности - создадим узел - орбиту, при вращении которого вокруг центра тело будет передвигаться по орбите
            auto orbitContainer = make::sptr<Node>();
            //отклоняем орбиту от плоскости вращения главного тела
            orbitContainer->setLocalRotation({(planet.m_axisTilt + moon.m_eclipseAngle) * DEG2RAD, 0, 0});
            //создаём тело
            auto moonNode = Mesh::create::sphere(moon.m_radius, 10, 10);
            //добавляем спутник как "ребёнка" орбиты
            orbitContainer->addChild(moonNode);
            //устанавливаем позицию тела на орбите
            moonNode->setLocalTranslation({moon.m_orbit, 0, 0});
            moonNode->getMaterialInst()->setParam("baseColor", moon.m_color);
            //добавляем орбиту как "ребёнка" главного тела. Особое внимание на параметр false - он обозначает, 
            //что при чайлдинге сохраняются локальные трансформы. Таким образом, орбита окажется в той же позиции, 
            //что и планета и наклонена относительно его плоскости обращения
            planetNode->addChild(orbitContainer, false);
            //рекурсивно создаём спутники
            createMoons(moonNode, moon);

            //добавляем в список орбиты и кватернионы для их поворота в локальном пространстве (вычисляем из углов эйлера)
            m_rotations.emplace_back(orbitContainer, Rotator(0, 0, 1 / moon.m_siderealPeriod));
        }
    }

    std::vector<std::pair<sptr<Node>, Rotator>> m_rotations;
};

W4_RUN(SolarDemo)

VisibleNode

Базовый класс для отображаемого узла.

Особенности:

  • Все отображаемые узлы содержат вертексный буфер и состоят из одного и более элемента surface (который содержит индексный буфер).
  • Каждому surface можно назначить свой материал.

Все отображаемые узлы имеют следующие дополнительные методы:

Method Description
const MaterialInstPtr& getMaterialInst(const std::string& surfaceName) const
Возвращает материал указанного surface
const MaterialInstPtr& getMaterialInst() const
Получает материал, установленный для всех surface. Если материалы surface отличаются - выдаёт ошибку в лог и возвращает какой-то материал.
void setMaterialInst(const MaterialInstPtr & m)
Устанавливает материал для всех surface

Mesh

Объект, отображающий геометрию.

Объекты типа Mesh в движке можно создать тремя путями: 1. Загрузить из ресурсов (см. также Mesh Converter):

teapot = Asset::load(Path("resources/teapot", "teapot.asset"))->getRoot()->getChild<Mesh>("Utah Teapot Quads");

2. Вызвать встроенный генератор:

auto sphere = Mesh::create::sphere(радиус, количество параллелей, количество меридианов);
auto box = Mesh::create::box({width, height, depth}); //box - параллелепипед, у которого каждая грань - surface
auto cube = Mesh::create::cube({width, height, depth}); 
auto mappedCube = Mesh::create::mappedCube({width, height, depth}); //параллелепипед с uv координатами под развёртку
auto plane1 = Mesh::create::plane({width, height}, scaleUv); //плоскость по осям XY. scaleUv = false(по умолчанию) - UV от 0 до 1, true - от 0 до ширины/высоты
auto plane2 = Mesh::create::plane({left, down}, {right, up}, scaleUv; //то же самое
auto cylinder = Mesh::create::cylinder(высота, радиус, количество секторов);
auto cone = Mesh::create::cone(верхний радиус, нижний радиус, высота, количество секторов, количество сегментов по вертикали);
auto torus = Mesh::create::torus(радиус кольца, радиус "трубы", количество сегментов кольца, количество сегментов "трубы", угол дуги кольца(2*PI для замкнутого тора));
auto skybox = Mesh::create::skybox(); //Скайбокс. Единичный куб со сторонами, отображаемыми изнутри.

3. Создать из кода:

        auto indicesBuf = make::sptr<UserIndicesBuffer>("Floor indices");
        auto verticesBuf = make::sptr<UserVerticesBuffer<Mesh::VertexFormat>>("floor_" + std::to_string(width) + "x" + std::to_string(height) + "-" + std::to_string(offset));
        indicesBuf->setNeedExport(false);
        verticesBuf->setNeedExport(false);

        resources::MeshVertexDataBuilder vdb(verticesBuf, indicesBuf);
        //позиция, UV, нормаль
        vdb.addVertex({-width / 2 + offset, 0, height / 2}, {offset/width, 0.f}, {0, 1, 0});
        vdb.addVertex({width / 2 - offset, 0, height / 2}, {1.f - offset/width, 0.f}, {0, 1, 0});
        vdb.addVertex({-width / 2, 0, height / 2 - offset}, {0.f, offset/height}, {0, 1, 0});
        vdb.addVertex({width / 2, 0, height / 2 - offset}, {1.f, offset/height}, {0, 1, 0});

        vdb.addVertex({width / 2, 0, -height / 2 + offset}, {0.f, 1.f - offset/height}, {0, 1, 0});
        vdb.addVertex({-width / 2, 0, -height / 2 + offset}, {1.f, 1.f - offset/height}, {0, 1, 0});
        vdb.addVertex({width / 2 - offset, 0, -height / 2}, {offset/width, 1.f}, {0, 1, 0});
        vdb.addVertex({-width / 2 + offset, 0, -height / 2}, {1.f - offset/width, 1.f}, {0, 1, 0});

        vdb.addIndices({2, 1, 0,
                                2, 3, 1,
                                4, 3 ,2,
                                5, 4, 2,
                                5, 6, 4,
                                7, 6, 5});

        vdb.build();

        auto result = make::sptr<Mesh>(verticesBuf->getName(), verticesBuf);
        result->addComponent<Surface>("unnamed", indicesBuf);

        result->setMaterialInst(Material::getDefault()->createInstance());

SkinnedMesh

Объект, отображающий геометрию с анимацией.

Особенности:

  • можно загрузить только из файла;
  • представляет собой геометрию со скелетной анимацией;
  • содержит в себе набор анимаций;
  • содержит в себе API для управления анимациями и позволяет проигрывать несколько анимаций с плавными переходами между ними.
Method Description
w4::cref<core::Node> createSocket(const std::string& boneName)
Создаёт узел для крепления на кости с заданным именем. К этому узлу можно добавлять “детей“
w4::cref<core::Node> getSocket(const std::string& boneName) const
Возвращает узел для крепления на кости с заданным именем
std::vector<std::string> getAvailableAnimations() const
Возвращает список имеющихся анимаций
bool haveAnimation(const std::string& animationName) const
Проверяет наличие анимации с заданным именем
size_t getAnimationIndex(const std::string& animationName) const
Получение индекса анимации по её имени
const std::string& getAnimationName(size_t animationIndex) const
Получение имени анимации по её индексу
void setAnimationStateChangedCallback(std::function<void(Animator&, Animator::State)>)

void setAnimationStateChangedCallback(Animator::State, std::function<void(Animator&)>)
Установить функтор, который вызовется по изменению состояния конкретной анимации. Метод имеет как вариант только для заданного состояния, так и для любого. Состояния анимаций:
Animator::State::Idle(не проигрывается/закончилась), 
Animator::State::Play(проигрывается), 
Animator::State::Pause(приостановлена)

Пример:

node->setAnimationStateChangedCallback(Animator::State::Idle, [](Animator& animator)
{
    W4_LOG_DEBUG("Animator stopped:\n"
                 "\tName: %s,"
                 "\tSpeed: %f,"
                 "\tDuration: %f,"
                 "\tFps: %f",
                    animator.getName().c_str(),
                    animator.getSpeed(),
                    animator.getDuration(),
                    animator.getFps());
});
void play(const std::string& animationName, float duration = 0.f)

void play(size_t animationIndex = 0, float duration = 0.f)
Проигрывание анимации по индексу или имени. Указывается длительность анимации, если она равна нулю - проигрывается анимация целиком
void play(std::initializer_list<std::pair<std::string, float>>, float duration = 0.f)

void play(std::initializer_list<std::pair<size_t, float>>, float duration = 0.f)
Проигрывание списка анимаций с весами. Длительность, если равна нулю - равна анимации с максимальной длительностью

Пример:

skinned->play({{"run", .3f}, {"jump", .7f}});
void pause()
Приостановить все активные анимации
void resume()
Возобновить проигрывание всех приостановленных анимаций
void stop()
Остановить проигрывание всех активных анимаций
bool isPlaying() const
Проверяет, проигрывается ли сейчас любая анимация
Animator & getAnimator(size_t)
Animator & getAnimator(const std::string&)
const Animator & getAnimator(size_t) const
const Animator & getAnimator(const std::string&) const
Получить объект аниматор по имени или индексу. API объекта Animator описан чуть ниже. Используется для управления анимациями с расширенными возможностями.

Управление анимациями через API и SkinnedMesh не являются взаимоисключающими. Так, например, общеупотребительной является практика зацикливания анимаций:

m_skinned->getAnimator("dance").setIsLooped(true);
Animator API
Method Description
void play()
Запуск воспроизведения анимации.

В случае, если она уже проигрывается, она будет остановлена и запущена с начала

void pause()
Приостанавливает воспроизведение анимации
void resume()
Возобновляет воспроизведение анимации
void stop()
Останавливает воспроизведение анимации
void seek(float targetTime)
Устанавливает текущую позицию в анимации на заданное время. Значения автоматически обрезаются сверху и снизу до диапазона [0; длина анимации] или до диапазона, заданного методами setBeginTime/setEndTime
bool isLooped() const
Возвращает, включен ли для данной анимации режим циклическое воспроизведение
float getSpeed() const
Получает множитель скорости воспроизведения анимации (по умолчанию 1.0)
State getState() const
Возвращает состояние анимации

Состояния анимаций:

Animator::State::Idle (не проигрывается/закончилась),
Animator::State::Play (проигрывается),
Animator::State::Pause (приостановлена)
void setPlayType(PlayType)
Устанавливает направление воспроизведения.

Возможные значения параметра:

Animator::PlayType::Forward (вперёд),
Animator::PlayType::Backward (в обратном направлении)
PlayType getPlayType() const
Возвращает текущее направление проигрывания. Возможные значения см. в setPlayType
float getCurrentTime() const
Возвращает текущую позицию в анимации
void setIsLooped(bool)
Включает/выключает для данной анимации режим циклического воспроизведение
void setSpeed(float)
Устанавливает множитель скорости воспроизведения анимации
void setBeginTime(float)
Устанавливает начальное время анимации. Нужно для частичного воспроизведения анимации
void setEndTime(float)
Устанавливает конечное время анимации. Нужно для частичного воспроизведения анимации
StateHandlerId setStateHandler(State state, StateHandler handler)
void resetStateHandler(StateHandlerId handler)
Устанавливает и удаляет callback на смену состояния на заданное. Сигнатура callback - void(Animator&)
void setTimeHandler(float dt, TimeHandler handler)
Устанавливает callback на прохождение заданной временной метки. Сигнатура callback - void(Animator&)
float getFps() const
Возвращает характеристику анимации - количество значений в секунду.
float getDuration() const
Возвращает длительность анимации

ParticlesEmitter

Особенности:

  • ParticlesEmitter может быть загружен только из файла;
  • Входным форматом файла является CoronaSDK (можно создать в любом онлайн-редакторе, например в http://www.effecthub.com/particle2dx, сохранить json с расширением part и текстуру и убедиться, что путь к текстуре является путём от корня проекта).

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

API ParticlesEmitter:

Method Description
void start()
Запуск генерации частиц
void pause()
Приостановка генерации частиц. В этом случае обработка уже выпущенных частиц продолжается
void resume()
Возобновление генерации частиц
void stop()
Остановка генерации частиц. Обработка всех частиц прекращается
State getState() const
Получение состояния

Варианты:

ParticlesEmitter::State::IDLE, 
ParticlesEmitter::State::STARTED, 
ParticlesEmitter::State::PAUSED

Billboard

Плоскость заданного при создании размера, всегда ориентированная на камеру. Имеет методы getSize и setSize.

Plotter

Реализация рисования линиями. Данные плоттера представляют собой информацию о точках (позиция и цвет) и набор индексов для их попарного соединения.

Пример:

auto plotter1 = make::sptr<Plotter>("Plotter_1");
const std::vector<uint32_t> indices = {1, 0};
const std::vector<LinesVertexFormat> vertices = {{{-10, -10, 0}, {1, 0, 0,1}},
                                                 {{10, 10, 0}, {0, 1, 0, 1}}};
plotter1->setLines(vertices, indices);

Представленный выше пример создаст косую линию с цветом, переходящим из красного в зелёный.

Как правило, для создания примитивов используются статические хелперы, возвращающие готовый объект, описанные в классе Plotter:

static w4::sptr<Plotter> build(std::vector<LinesVertexFormat> vertices, std::vector<uint32_t> indices);
static w4::sptr<Plotter> buildFromSegments(std::vector<std::array<w4::math::vec3, 2>> segments, const w4::math::vec4& color);
static w4::sptr<Plotter> buildFromPolyline(std::vector<w4::math::vec3> points, const w4::math::vec4& color);
static w4::sptr<Plotter> buildSphere(float radius, size_t rings, size_t sectors, const w4::math::vec4& color);
static w4::sptr<Plotter> buildOctahedron(std::array<w4::math::vec3, 8> vertices, const w4::math::vec4& color);
static w4::sptr<Plotter> buildCube(std::array<w4::math::vec3, 2> inVertices, const w4::math::vec4& color);
static w4::sptr<Plotter> buildCapsule(float radius, float height, size_t rings, size_t sectors, const w4::math::vec4& color);
static w4::sptr<Plotter> buildMesh(w4::cref<Mesh>, w4::math::vec4::cref color);
static w4::sptr<Plotter> buildMesh(w4::cref<SkinnedMesh>, w4::math::vec4::cref color);
static w4::sptr<Plotter> buildRay(math::vec3::cref startPoint, math::vec3::cref directionPoint, const w4::math::vec4& color);

DataNode

В отличие от VisibleNode, DataNode не отображается на экране. Далее описывается API унаследованных классов.

ArcBallNode

Аркболл для нижележащих объектов иерархии. Реализует контейнер, позволяющий вращать содержимое, как если бы оно находилось в шаре с инерцией.

Method Description
ArcBallNode(const std::string& name = core::Object::defaultName, float radius = 1.f)
Конструктор, принимающий имя и радиус "шара"
void setFriction(float v)
Задать коэффициент затухания скорости. По умолчанию = 0.95
void setSensitivity(float v)
Задать множитель чувствительности к прикосновению. По умолчанию = 1
void setRadius(float r)
Задать радиус
void setVelocity(const math::Rotator& v)
Задать угловую скорость
void enableUpdate(bool flag = true)
void disableUpdate()
Включить/отключить вращение аркболла. Не сбрасывает скорость, при включении - может продолжить вращаться (затухание скорости по времени)
void enableInput(bool flag = true)
void disableInput()
Включение/выключение перехвата прикосновений аркболлом

Camera

Method Description
Camera(const std::string& name)
Camera(const std::string& name, float fov, float aspect, float near, float far)
Конструкторы перспективной камеры. Можно сразу указать FOV(угол обзора камеры по горизонтали), соотношение сторон и clip плоскости. FOV указывается в градусах
Camera(const std::string& name, const math::size& screen, float near, float far)
Конструктор ортокамеры. Указываются размеры и clip плоскости камеры
float getFov() const
void setFov(float v)
Получить, установить FOV(угол обзора камеры по горизонтали). FOV указывается в градусах
float getAspect() const
void setAspect(float v)
Получить/установить соотношение сторон
float getNear() const
void setNear(float v)
Получить/установить near clip плоскость
float getFar() const
void setFar(float v)
Получить/установить far clip плоскость
bool getIsOrtho() const
Получить является ли камера ортокамерой
void setClearColor(const math::vec4& v)
Задать значение цвета для очистки буфера цвета (фоновый цвет для камеры при отсутствии Background или Skybox)
ClearMask getClearMask() const
void setClearMask(ClearMask v)
Получить/установить ,битовую маску режима очистки экрана. Это значение будет применяться при рендеринге каждого кадра.

Значение по умолчанию ClearMask::Color | ClearMask::Depth

Возможные значения:

None

Color - очищать буфер цвета

Depth - очищать буфер глубины

Skybox - отрисовывать ли skybox

Background - отрисовывать ли background

bool hasSkybox() const
w4::cref<Skybox> getSkybox() const
Получить текущий объект skybox или nullptr при его отсутствии
bool hasBackground() const
w4::cref<Background> getBackground() const
Получить текущий объект background или nullptr при его отсутствии
Background

Background представляет собой ресурсовыгодный способ очистки буфера цвета чем-то, что сложнее одного цвета.

Может использоваться двумя способами:

  1. Вызовом метода void setTexture(w4::cref<resources::Texture> texture). При вызове создастся материал по умолчанию (просто отображает текстуру).
  2. Работа с материалами вручную через методы void setMaterial(w4::cref<resources::MaterialInst>) и w4::sptr<resources::MaterialInst> getMaterial(). Вертексный шейдер должен использовать нормализованное пространство координат (т.е. [-1; 1])
Skybox

В случае если необходимо чтобы фон смещался при движении камеры, можно использовать объект Skybox. Он также может использоваться двумя способами:

1. Вызовом метода void setCubemap(w4::cref<resources::Cubemap> texture). При вызове создастся материал по умолчанию (просто отображает текстуру).

Пример:

auto cubemap = Cubemap::get({"resources/textures/left.png",
                             "resources/textures/right.png",
                             "resources/textures/up.png",
                             "resources/textures/down.png",
                             "resources/textures/front.png",
                             "resources/textures/back.png",
                            });
m_cam->setClearMask(ClearMask::Color | ClearMask::Depth | ClearMask::Skybox);
m_cam->getSkybox()->setCubemap(cubemap);

2. Работа с материалами вручную через методы void setMaterial(w4::cref<resources::MaterialInst>) и w4::sptr<resources::MaterialInst> getMaterial(). Вертексный шейдер должен использовать нормализованное пространство координат (т.е. [-1; 1])

PointLight

Точечный источник освещения. Имеет следующий API:

Method Description
math::vec3 getColor() const
void setColor(const math::vec3& c)
Получить/установить цвет света
float getIntensity() const
void setIntensity(float i)
Получить/установить яркость источника света
core::LightDecayRate getDecayRate() const
void setDecayRate(core::LightDecayRate)
Получить/установить алгоритм затухания цвета (None, Linear, Quadratic, Cubic).

SpotLight

Направленный источник освещения в виде конуса с вершиной в точке излучения.

Method Description
float getAngle() const
void setAngle(float r)
Получить/установить верхний угол конуса
math::vec3 getColor() const
void setColor(const math::vec3& c)
Получить/установить цвет света
float getIntensity() const
void setIntensity(float i)
Получить/установить яркость источника света
core::LightDecayRate getDecayRate() const
void setDecayRate(core::LightDecayRate)
Получить/установить алгоритм затухания цвета (None, Linear, Quadratic, Cubic)
float getDecayFactor() const
void setDecayFactor(float f)
Получить/установить степень затухания(“прозрачность“) цвета от 0 до 1(по умолчанию = 1)

Spline

Позволяет использовать траектории, импортированные из fbx (b-spline).

Важно понимать, что в формате FBX Spline содержит только саму траекторию, но не вращения вокруг неё (spin).

Method Description
bool isRepeatable() const
void setRepeatable(bool isRepeatable)
Получить/установить режим повторяющегося “воспроизведения”
void play(float splineTime, std::function<void(const math::Transform&)> updateHandler, std::function<void(bool)> completionHandler = [](bool){})
Запуск “воспроизведения” сплайна

splineTime - конечное время воспроизведения сплайна(для расчёта множителя скорости)

updateHandler - метод, в который будут приходить Transform

completionHandler - метод, который вызовется при завершении “воспроизведения” (если не задано повторение)

void stop()
Остановить “воспроизведение” преобразований
bool isPlaying() const
Возвращает, идёт ли “воспроизведение” сплайна
bool isPaused() const
void pause()
Приостановка “воспроизведения” сплайна
float getDuration() const
Возвращает длительность сплайна в секундах
void setPosition(float pos)
Устанавливает позицию в секундах