Mesh Converter

From Ciliz|W4
Revision as of 14:28, 19 May 2020 by Azelenkin (talk | contribs)

Scope

The W4 game engine uses its own asset storage format. Therefore, before using a third-party asset, it must be converted. You can do this using the Mesh Converter tool that comes with the W4 SDK.

Mesh Converter converts assets from Autodesk FBX (.fbx) format. Other formats are not supported.

Technical limitations

Mesh Converter can convert any fbx with the following restrictions:

1. Due to the hardware and software features of some popular device models, a skinned mesh may contain:

  • no more than 28 bones
  • no more than 8 vertices per bone

How to use

Downloading the project repository is described in the article Quick Start. The W4MeshConverter.bin file is located in the w4framework/tools directory. The conversion should be started from the command line, as described in the following example and in the section Short manual.

Mesh Exmple

Preparing

Take the Utah teapot as an example. If you view the file using the utility Autodesk FBX Review, you will see approximately the same as in the following figure.

D1b94d56-cb70-428b-ac1c-65701c690238.png

Pay attention to the position of the spout of the teapot when viewing fbx, we will return to this later.

Converting

Copy the model file to the converter directory.

Next, to convert the model to the W4 Engine format (asset), you should:

./W4MeshConverter utah-teapot.fbx teapot

As a result, the 'teapot' directory will appear. It contains asset data.

Adding to the project structure

To work with an asset, you need to copy its directory (in our case, it is 'teapot') into the directory 'resources' of the project. The resources directory is located at the same level of the project structure as the 'sources' directory. Thus, the structure of the project will become similar to the following:

.
└── 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

Loading:

auto asset = Asset::load(Path("resources/teapot", "teapot.asset"));

Adding to Render (show on screen):

auto root = RootNode::make();
root->addChild(asset->getRoot());
Render::instance().getPass(0)->setRoot(root);

Full source code for the example:

#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

As a result of execution, the same teapot should be displayed, but with a slight difference.

1b952599-fc03-428f-96e8-ae86935b46d8.png

If you compare the drawings, you will notice that the spout of the teapot in the FBX Review is directed in one direction, and as a result of the program in the other. This is due to differences in coordinate systems.

The FBX coordinate system Scene Axis and Unit Conversion is right-handed (with the Y coordinate direction up, whereas W4 coordinate system is left-sided (the Y axis is also directed up).

Animated mesh Exmple

Working with animated meshes is not much different from the one described above.

Preparing

An animated model can be found on the Internet. Take, for example, the Rigged Hand.

If you view it using Autodesk FBX Review you will see something like the following:

Converting

As in the example with a simple mesh, you should copy the model to the converter directory and convert it to the W4 Engine format:

./W4MeshConverter Hand_rigged.FBX hand

As a result, the 'hand' directory will appear. It contains asset data.

Adding to the project structure

Copy the 'hand' directory to the 'resources' directory of the project. An approximate project structure after this:

.
└── 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

Download asset and add it to the render tree:

auto asset = Asset::load(Path("resources/hand", "hand.asset"));
render::getRoot()->addChild(asset->getRoot());

If we try to build the project now, we will not see anything. Because the camera is "inside" the asset.

Take the camera and move it away (you may need to set other values, depending on the size of the browser window, the size of the object, etc.):

auto cam = render::getScreenCamera();
cam->setWorldTranslation({0.f, 125.f, -300.f});
 

If you assemble the project now, a hand will appear on the screen, but it will not move.

To move it, you need to run the animator on the corresponding skinned mesh. It is known that we have one skinned mesh and it has one animation, so in a loop we go through the entire asset tree and all skinned meshes in it and we will play the animation (in our example - the first one):

asset->getRoot()->traversal([&](Node& node)
{
  if(node.is<SkinnedMesh>())
  {
    auto skinned = node.as<SkinnedMesh>();
    skinned->getAnimator(0).setIsLooped(true);
    skinned->play(0);
  }
});

Full source code for the example:

#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

As a result of the above program, the animation will play:

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