ことれいのもり

Assimpのモデルが回転する?PreTransformVerticesフラグとアニメーションの関係

はじめに

Assimpを使ってFBXモデルを読み込んだときに、「モデルが変な方向を向いてる」ということはありませんか?

アニメーションがないモデルでは、意図しない回転が起きることがあります。


実は、アニメーションの有無によってAssimpの読み込みフラグを切り替えることで、解決できる場合があります。

この記事ではその具体的な方法を紹介します。

アニメーションがないモデルの時

アニメーションがないモデルを読み込むとき、aiProcess_PreTransformVerticesのフラグをつけると上手くいくことがあります。

このフラグは、モデル内のノード階層(親子関係)やボーンの情報を削除し、全ての頂点に最終的な変換行列を適用します。

つまり、途中で回転やスケーリングが入っているノード構造でも、全部一つの空間に統合するので、意図しない回転の影響を受けにくくなります。


ただし、この処理を行なうとボーン・階層構造・アニメーションの情報は失われます

なので、アニメーションがないモデルにのみ適用しましょう。


以下のコードは、私が実際にアニメーションがないモデルを読み込んでいるときのものです。


const aiScene* scene = importer.ReadFile(fbxFilePath.narrow(),
    aiProcess_Triangulate
    | aiProcess_JoinIdenticalVertices
    | aiProcess_LimitBoneWeights
    | aiProcess_ImproveCacheLocality
    | aiProcess_FlipUVs
    | aiProcess_ConvertToLeftHanded
    | aiProcess_PreTransformVertices
);


アニメーションがあるモデルの時

アニメーションがあるモデルの時は先程紹介した aiProcess_PreTransformVertices のフラグを使わずに読み込みます。

このフラグを使ってしまうと、アニメーションに必要なボーン構造や階層構造が失われてしまうからです。


以下は、私がアニメーション付きのFBXモデルを読み込む際に使用しているフラグ設定です。


const aiScene* scene = importer.ReadFile(fbxFilePath.narrow(),
    aiProcess_Triangulate
    | aiProcess_JoinIdenticalVertices
    | aiProcess_LimitBoneWeights
    | aiProcess_ImproveCacheLocality
    | aiProcess_FlipUVs
    | aiProcess_ConvertToLeftHanded
);


この二つを使い分けるときのコード例

アニメーションの有無で読み込みフラグを自動で変えたい、という場合は scene->HasAnimation() を使うことで実装できます。

仮のシーン「tempScene」でアニメーションの有無を確認し、読み込みフラグをif文を使って切り替えます。


const aiScene* tempScene = importer.ReadFile(fbxFilePath.narrow(),
    aiProcess_Triangulate
    | aiProcess_JoinIdenticalVertices
    | aiProcess_LimitBoneWeights
    | aiProcess_ImproveCacheLocality
    | aiProcess_FlipUVs
    | aiProcess_ConvertToLeftHanded
);

if (!tempScene)
{
    throw std::runtime_error("FBXファイルのロードに失敗しました");
}

    // アニメーション:有 -> tempSceneと同じフラグ
    if (tempScene->HasAnimations())
    {
        scene = importer.ReadFile(fbxFilePath.narrow(),
            aiProcess_Triangulate
            | aiProcess_JoinIdenticalVertices
            | aiProcess_LimitBoneWeights
            | aiProcess_ImproveCacheLocality
            | aiProcess_FlipUVs
            | aiProcess_ConvertToLeftHanded
        );
    }
    // アニメーション:無 -> aiProcess_PreTransformVerticesを追加
    else
    {
        scene = importer.ReadFile(fbxFilePath.narrow(),
            aiProcess_Triangulate
            | aiProcess_JoinIdenticalVertices
            | aiProcess_LimitBoneWeights
            | aiProcess_ImproveCacheLocality
            | aiProcess_FlipUVs
            | aiProcess_ConvertToLeftHanded
            | aiProcess_PreTransformVertices
        );
    }

    if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)
    {
        Console << U"Assimp読み込みエラー:" << Unicode::FromUTF8(importer.GetErrorString());
        return;
    }


おわりに

アニメーションの有無によって、Assimpの読み込みフラグを切り替えることで、回転のトラブルを回避できることを紹介しました。

このほかにもAssimpに関する記事をいくつか投稿しているので、ぜひ他の記事もチェックしてみてください!

参考リンク