Mesh Converter
Scope
Игровой движок W4 использует собственный формат хранения ассетов. Следовательно, прежде чем использовать сторонний ассет, его необходимо преобразовать в наш формат. Сделать это можно с помощью инструмента Mesh Converter, который поставляется вместе с нашим SDK.
Mesh Converter позволяет преобразовывать ассеты из формата Autodesk FBX (.fbx). Другие форматы не поддерживаются.
Technical limitations
Конвертер может преобразовать любой fbx со следующими ограничениями:
1. В связи с аппаратными и программными особенностями некоторых популярных моделей устройств skinned mesh может содержать:
- не более 28 костей
- не более 8 вершин на кость
How to use
Загрузка репозитория проекта описана в статье Quick Start. Файл конвертера W4MeshConverter.bin находится в каталоге w4framework/tools . Конвертация запускается из командной строки, как это описано на следующем примере и в разделе Short manual.
Mesh Exmple
Preparing
Возьмем для примера Utah teapot. Если посмотрите файл с помощью утилиты Autodesk FBX Review, увидите примерно то же, что на рисунке.
Обратите внимание на положение носика чайника при просмотре fbx, мы вернемся к этому чуть позже.
Converting
Скопируем файл модели в директорию конвертера.
Далее, для преобразования модели в формат нашего движка (asset) необходимо выполнить:
./W4MeshConverter utah-teapot.fbx teapot
В результате появится директория teapot содержащая данные ассета.
Adding to the project structure
Для работы с ассетом необходимо скопировать его директорию (в нашем случае это teapot) в директорию resources проекта. Директория resources располагается на том же уровне структуры проекта, что и sources. Таким образом, структура проекта станет подобна следующей:
. └── W4TemplateGame ├── resources │ └── teapot │ ├── Animations │ ├── BoneInfo │ ├── Materials │ │ ├── defaultMaterial.matInst │ │ └── defaultSkinnedMaterial.matInst │ ├── Splines │ ├── teapot.asset │ └── VertexData │ ├── Utah Teapot Quads_0.ib │ └── Utah Teapot Quads.vb └── sources └── main.cpp
Code example
Загрузка:
auto asset = Asset::load(Path("resources/teapot", "teapot.asset"));
Добавление в Render (отображение на экране):
auto root = RootNode::make(); root->addChild(asset->getRoot()); Render::instance().getPass(0)->setRoot(root);
Полный код примера:
#include "W4Framework.h" W4_USE_UNSTRICT_INTERFACE class AssetSample : public w4::IGame { public: AssetSample() = default; ~AssetSample() = default; void onStart() override { auto cam = Render::instance().getScreenCamera(); cam->setWorldTranslation({0.f, 0, -50.f}); auto asset = Asset::load(Path("resources/teapot", "teapot.asset")); auto root = RootNode::make(); root->addChild(asset->getRoot()); Render::instance().getPass(0)->setRoot(root); } }; W4_RUN(AssetSample)
Result
В результате выполнения должен отобразиться тот же чайник, но с небольшим отличием.
Если сравнить рисунки, можно заметить, что нос чайника в FBX Review смотрит в одну сторону, а в результате выполнения программы в другую. Это происходит из-за различий в системах координат и поведении конвертера.
Система координат FBX Scene Axis and Unit Conversion является правосторонней (с осью Y направленной верх), тогда как Система координат W4 левосторонняя (ось Y также направлена верх).
Animated mesh Exmple
Для анимированных мешей порядок работы не сильно отличается от описанного выше.
Preparing
Анимированную модель можно найти в интернете. Возьмем, например, Rigged Hand. Просмотр с помощью Autodesk FBX Review покажет примерно следующее:
Converting
Так же как в примере выше (с обычным мешем), скопируем модель в папку конвертера и преобразуем в формат W4 Engine:
./W4MeshConverter Hand_rigged.FBX hand
В результате выполнения в текущей папке будет получена директория hand, содержащая данные ассета.
Adding to the project structure
Скопируем полученный каталог ассета hand в каталог resources нашего проекта. Примерная структура проекта после этого:
. └── W4TemplateGame ├── resources │ └── hand │ ├── Animations │ │ └── Take 001.ssa │ ├── BoneInfo │ │ ├── bone_main_hande.skeleton │ │ └── Hand_rigged.skin │ ├── hand.asset │ ├── Materials │ │ ├── defaultMaterial.matInst │ │ └── defaultSkinnedMaterial.matInst │ ├── Splines │ └── VertexData │ ├── Hand_rigged_0.ib │ └── Hand_rigged.vb └── sources └── main.cpp
Code example
Загрузим asset и добавим его в дерево отрисовки:
auto asset = Asset::load(Path("resources/hand", "hand.asset")); render::getRoot()->addChild(asset->getRoot());
Если мы попробуем сейчас собрать проект, то ничего не увидим. Потому что камера попала “внутрь” asset’a.
Возьмем камеру и передвинем её подальше (возможно, придется задать другие значения, в зависимости от размера окна браузера, размера объекта и т.п.):
auto cam = render::getScreenCamera(); cam->setWorldTranslation({0.f, 125.f, -300.f});
Если сейчас собрать проект, то на экране появится рука, но она не будет двигаться.
Чтобы она задвигалась, нужно запустить аниматор у соответствующего skinned mesh’a. Известно, что skinned mesh у нас один и у него одна анимация, поэтому в цикле пройдем по всему дереву asset’a и всем skinned mesh’ам в нём и будем проигрывать анимацию (в нашем примере - первую):
asset->getRoot()->traversal([&](Node& node) { if(node.is<SkinnedMesh>()) { auto skinned = node.as<SkinnedMesh>(); skinned->getAnimator(0).setIsLooped(true); skinned->play(0); } });
Полный код примера:
#include "W4Framework.h" W4_USE_UNSTRICT_INTERFACE class MeshAnimatedSample : public w4::IGame { public: MeshAnimatedSample() = default; void onStart() override { auto asset = Asset::load(Path("resources/hand", "hand.asset")); render::getRoot()->addChild(asset->getRoot()); auto cam = render::getScreenCamera(); cam->setWorldTranslation({0.f, 150.f, -300.f}); asset->getRoot()->traversal([&](Node &node) { if (node.is<SkinnedMesh>()) { auto skinned = node.as<SkinnedMesh>(); skinned->getAnimator(0).setIsLooped(true); skinned->play(0); } }); } }; W4_RUN(MeshAnimatedSample)
Result
В результате выполнения вышеописанной программы отобразится следующая анимация:
Short manual
Basics
Конвертация utah-teapot.fbx в ассет с именем asset в текущей директории:
./W4MeshConverter utah-teapot.fbx
Конвертация utah-teapot.fbx в ассет с именем teapot в текущей директории:
./W4MeshConverter utah-teapot.fbx teapot
Конвертация utah-teapot.fbx в ассет с именем teapot, который будет сохранен в директории ~/some/dir:
./W4MeshConverter utah-teapot.fbx teapot ~/some/dir
Common keys
Справка:
-h, --help
Вывод статистики сцены:
-v, --verbose
Пример статистики:
(DEBUG) ==================== Scene statistics ==================== (DEBUG) Nodes: 2 (DEBUG) Geometries: 1 (DEBUG) Poses: 0 (DEBUG) Materials: 1 (DEBUG) Textures: 0 (DEBUG) ====================== Axis & Scale ====================== (DEBUG) Up: +Y, Front: +ParityOdd, System: RightHanded (DEBUG) Scale: 1.000000 (DEBUG) ================ Mesh: Red_label ================ (DEBUG) Vertex count: 404 (DEBUG) Index count: 2118 (DEBUG) All polygons are triangles: 1 (DEBUG) ========================================================== (DEBUG) create default material... (DEBUG) create default skinned material...
Управление размером (scale) на конвертации, где arg - значение, например (10, 1, 0.1):
--scale arg
Переворот вертикальной оси V текстурных координат, если флаг указан, то к текстурным координатам будет применено преобразование вида V = 1.0 - V:
--uv-flip
Setting limitations
Для всех Mesh'ей могут быть заданы ограничения на максимальное количество вершин и индексов. Для Skinned Mesh'ей могут быть заданы ограничения на максимальное количество костей и максимальное количество костей на вершину.
Модель, которая не соответствует заданным ограничениям, можно принудительно сконвертировать с помощью флага force, однако работоспособность в таком случае не гарантируется:
-f, --force
Установка ограничения на максимальное количество вершин на объект, где arg - значение, по умолчанию не задано:
--max-vertex arg
Установка ограничения на максимальное количество индексов на объект, где arg - значение, по умолчанию не задано:
--max-index arg
Установка ограничения на максимальное количество костей для Skinned Mesh, где arg - значение, по умолчанию 28, при установке значения выше, чем значение по умолчанию, работоспособность не гарантируется:
--max-bones arg
Установка ограничения на максимальное количество костей на вершину для Skinned Mesh, где arg - значение, по умолчанию 8, при установке значения выше, чем значение по умолчанию, работоспособность не гарантируется:
--max-bones-per-vertex arg