DirectXTKでmixamoのモデルをアニメーションさせる方法を解説します。

 

 まずFBXをsdkmeshにするためにcontentexporterを使用します。

 contentexporterを使用するためにはFBX SDKに含まれているlibfbxsdk-md.liblibxml2-md.libが必要になるのでFBX SDKをダウンロードします。私はWindowsのVS2019を使用しているのでFBX SDK 2020.3.2 VS2019 をダウンロードしました。

 

 FBX SDKのインストールが完了したら2020.3.2/lib/vs2019/x64/debugにあるlibfbxsdk-md.liblibxml2-md.libをcontentexporterのimportfbxの中にコピーします。

 

 FBX SDKをインストールしたファイル内のincludeをcontentexporterの中にコピーして名前をFBXSDKに変更します。

 

 contentexporterのソリューションファイルを開きImportFBXのプロパティを開きます。

 

 プロパティの構成プロパティ/C/C++/全般の追加インクルードディレクトリを..\FBXSDK;..\DirectXTex;..\DirectXMesh;..\UVAtlas\inc;%(AdditionalIncludeDirectories)に変更します。

 

 ビルドをするとcontentexporter-main\importfbx\x64\Debug_2019の中にContentExporter.exeができます。ContentExporter.exeにFBXファイルをドラッグアンドドロップするだけでsdkmeshが生成されます。アニメーション付きのFBXならsdkmesh_animも生成されます。

 

 mixamoからモデルをダウンロードしてContentExporter.exeでsdkmeshに変換します。DirectXでsdkmeshをアニメーションさせるにはAnimation.cppAnimation.hを使用します。

 

 モデルの描画とアニメーションに必要な変数は以下の通りです。

 

//モデル
    std::unique_ptr<DirectX::Model> mpModel;

    //SDKアニメーション
    DX::AnimationSDKMESH  mpAnimSdk;

    //スケルトン
    DirectX::ModelBone::TransformArray mpBone;

    //アニメーションスケルトン
    DirectX::ModelBone::TransformArray mpAnimBone;

 

 モデルとアニメーションの読み込み以下のように行います。

 

auto device = pDR.GetD3DDevice();

    //sdkmeshの読み込み
    mpModel = Model::CreateFromSDKMESH(device, L"Resources/Models/Walking.sdkmesh",
        *pGI.GetEffectFactory(),
        ModelLoader_Clockwise | ModelLoader_IncludeBones);

    size_t nbones = mpModel->bones.size();
    mpAnimBone = ModelBone::MakeArray(nbones);
    mpModel->CopyBoneTransformsTo(nbones, mpAnimBone.get());

    mpBone = ModelBone::MakeArray(nbones);
    mpModel->CopyAbsoluteBoneTransforms(nbones, mpAnimBone.get(), mpBone.get());

    for (size_t j = 0; j < nbones; ++j)
    {
        mpBone[j] = XMMatrixMultiply(mpModel->invBindPoseMatrices[j], mpBone[j]);
    }

    //アニメーションの読み込み
    DX::ThrowIfFailed(
        mpAnimSdk.Load(L"Resources/Models/untitled2.sdkmesh_anim")
    );

    mpAnimSdk.Bind(*mpModel);

    mpModel->UpdateEffects([&](DirectX::IEffect* effect)
        {
            auto skin = dynamic_cast<DirectX::SkinnedEffect*>(effect);
            if (skin)
            {
                skin->SetPerPixelLighting(true);
            }
        });

 

アニメーションの再生は以下の通りです。

 

//アニメーションの再生速度
    float anim_speed = 0.02f;
//アニメーションの更新
    mpAnimSdk.Update(anim_speed);

  size_t nbones = mpModel->bones.size();
    mpAnimSdk.Apply(*mpModel, nbones, mpBone.get());

 

モデルの描画は以下の通りです。

 

GetVariousInstance& pGI = GetVariousInstance::GetInstance();
    Camera& pCm = Camera::GetInstance();

    auto context = DX::DeviceResources::GetInstance().GetD3DDeviceContext();

    size_t nbones = mpModel->bones.size();

    mpModel->DrawSkinned(
        context
        , *pGI.GetCommonStates()
        , nbones, mpBone.get()
        , world
        , pCm.GetView()
        , pCm.GetProjection());

 

アニメーションが最後まで再生されない場合はmixamoからモデルをダウンロードする際にDownload SettingでSkinをWithout Skinに変更してダウンロードしContentExporter.exeで生成されたsdkmesh_animを使用すると最後まで再生されます。

Unityでゲームを作るときに新しいエディターで始めると、不都合なことがあります。

それは、Unityで様々なことを調べているときに大抵のものは古いバージョンでの情報になるので最新のバージョンとは異なることがあるためです。

 

例えば(2022年)の最新バージョンでゲームを作ろうとしたとき、一部のアウトレット接続ができないという問題が発生しました。

しかし、古いバージョンでは問題なくできたため、やはり最新のものより過去のもののほうが使いやすいと感じました。

 

このように最新のエディターよりも過去のもののほうが使いやすいということもあると思いました。

DirectXTKでエフェクシアを使う方法を調べてみた。

 

まずエフェクシアのサイトからEffekseer For DXライブラリをダウンロードする。

 

ダウンロードしたものの中にあるプロジェクトに追加すべきファイル_VC用の中から必要なものを使う。

 

必要なものは以下の通り

 

Debugビルドの場合

Effekseer_vs2019_x86_d.lib

EffekseerRendererDX11_vs2019_x86_d.lib

Releaseビルドの場合

Effekseer_vs2019_x86.lib

EffekseerRendererDX11_vs2019_x86.lib

 

Effekseer.h

Effekseer.Modules.h

Effekseer.SIMD

EffekseerRendererDX11

 

以上

 

libはプロジェクトのライブラリディレクトリとリンカーの追加の依存ファイルから設定する必要がある。

 

使い方は大体DXライブラリと同じだった。

 

エフェクシアの読み込みに必要な変数

// Effekseerで使用するパーツをメンバ変数に追加する
    // レンダラ
        EffekseerRendererDX11::RendererRef mRenderer;

        // マネージャ
        Effekseer::ManagerRef mManager;

        // エフェクト
        Effekseer::EffectRef mEffect;

   //ハンドル
        Effekseer::Handle mHandle;

 

初期化

ID3D11Device1* device = DX::DeviceResources::GetInstance().GetD3DDevice();
    ID3D11DeviceContext1* context = DX::DeviceResources::GetInstance().GetD3DDeviceContext();
    // レンダラの作成
    mRenderer = EffekseerRendererDX11::Renderer::Create(device, context, 8000);

    // マネージャの作成
    mManager = Effekseer::Manager::Create(8000);

    // 描画モジュールの設定
    mManager->SetSpriteRenderer(mMember.mRenderer->CreateSpriteRenderer());
    mManager->SetRibbonRenderer(mMember.mRenderer->CreateRibbonRenderer());
    mManager->SetRingRenderer(mMember.mRenderer->CreateRingRenderer());
    mManager->SetTrackRenderer(mMember.mRenderer->CreateTrackRenderer());
    mManager->SetModelRenderer(mMember.mRenderer->CreateModelRenderer());

    // テクスチャ、モデル、カーブ、マテリアルローダーの設定
    mManager->SetTextureLoader(mMember.mRenderer->CreateTextureLoader());
    mManager->SetModelLoader(mMember.mRenderer->CreateModelLoader());
    mManager->SetMaterialLoader(mMember.mRenderer->CreateMaterialLoader());
    mManager->SetCurveLoader(Effekseer::MakeRefPtr<Effekseer::CurveLoader>());

    // 描画の始点位置を確認
    Effekseer::Vector3D pos = Effekseer::Vector3D(10.0f, 5.0f, 20.0f);

    // レンダラの射影行列を設定
    float width = static_cast<float>(DX::DeviceResources::GetInstance().GetOutputSize().right);
    float height = static_cast<float>(DX::DeviceResources::GetInstance().GetOutputSize().bottom);
    mMember.mRenderer->SetProjectionMatrix(
        Effekseer::Matrix44().PerspectiveFovRH(
            90.0f / 180.0f * 3.14f,
            width / height,
            1.0f,
            500.0f)
    );

    // レンダラのカメラ行列を設定

    Effekseer::Vector3D eye;
    Effekseer::Vector3D target;
    Effekseer::Vector3D up;

    mMember.mRenderer->SetCameraMatrix(
        Effekseer::Matrix44().LookAtRH(
            eye,
            target,
            up
        )
    );

 

読み込み

Effekseer::EffectRef Effect = Effekseer::Effect::Create(mMember.mManager, (const EFK_CHAR*)FilePath);

    // エフェクトの読み込み
    mMember.mEffect = Effect;

    mMember.mHandle;

 

エフェクシアの実行

Effekseer::EffectRef Effect = mEffect;

    //エフェクトを停止する
    mManager.Get()->StopEffect(mHandle);

    //エフェクトを原点の位置で再生
    mHandle = mManager->Play(Effect, position.x, position.y, position.z);

 

エフェクシアの更新

mManager->Update();

 

//エフェクシアの描画

mRenderer->BeginRendering();
    // レンダラのカメラ行列を設定
    SetRender();
   mManager->Draw();
 mRenderer->EndRendering();

それいけ魔女ちゃん

 

Shooting

 

玉職人

 

NotesClicker

 

BlueTile

 

 

Mr,BANDIT

 

 

道が現れる

 

BattingCenter

 

箱庭戦争

 

DirectXTKで日本語のフォントを使う方法を調べてみた。

 

まず参考になったのがこちら

 

DirectXTKのMakeSpriteFontの問題と解決策 - Qiita

 

このページを参考にするだけで超簡単に日本語フォントを使えるようになった。

どのようなな方法かというとDirectXTKをダウンロードし中に入っているMakeSpriteFontを使いspritefontを新しく作成する方法である。

 

必要なものは二つ。

1.DirectXTKの中にあるMakeSpriteFont

2.MakeSpriteFontModify.zip 

 

以上である。

MakeSpriteFontModify.zip は以下のページからダウンロードできる。

DirectXTKでフォント表示、日本語対応 – ZeroGram

 

手順は以下の通り

1.MakeSpriteFontModifyの中にあるmodifyの中のTrueTypeImporter.csをMakeSpriteFontのフォルダの中にコピーする。

2.MakeSpriteFontModifyの中にあるmodifyの中のGlyphPacker.csを開きPositionGlyphの関数をMakeSpriteFontの中にあるGlyphPacker.csのPositionGlyphと差し替える。

3.MakeSpriteFontModifyの中にあるmodifyの中のGlyphPacker.csを開きArrangeGlyphsの関数をMakeSpriteFontの中にあるGlyphPacker.csのArrangeGlyphsと差し替える。

4.MakeSpriteFontの中にあるMakeSpriteFont.csprojを開きビルドする。

5.ビルドしてできたbinの中にあるDebugの中のMakeSpriteFont.exeをコマンドプロンプトで開きMakeSpriteFont.exe "MS ゴシック" myfile.spritefont /FontSize:34 /CharacterRegion:32-126 /CharacterRegion:0x3000-0x30ff /CharacterRegion:0xff00-0xffef /CharacterRegion:0x4e00-0x9fff /CharacterRegion:0x2000-0x2fffと入力し実行する。

 

コマンドプロンプトで実行するとmyfile.spritefontというファイルがどこかに作られるのでそれをDirectXTKで読み込むと日本語フォントが使えます。

"MS ゴシック"の部分は別のフォントやダウンロードしたフォントでも問題なくできます。

listとvectorでは処理速度が五倍ぐらい差があります。

繰り返しの処理の多い部分ではvectorを使うほうが無難です。

それと以前書いたlistとiteratorでの弾の管理ですが、ゲーム中にnewで弾を作っているので処理が遅くなっています。

あらかじめ弾を初期化時に作っておいてゲームループ中では作ったものを使いまわすのが処理が最も軽くなるやり方ですね。

ゲームループ中にnewをするのはメモリリークの原因になるのでダメです。

チームでゲーム制作をして大変だと思ったことは作業の分担、連携が難しいってことです。

まず誰にどんな仕事が割り振られるのか決めないといけないし作業の環境も合わせないといけないので非常にやりずらいと思いました。

他のところがどういう作業をしているか把握できないの連絡を取り合って進捗を話し合わなければいけません。

なれないこともあり非常に苦労しました。

 

人数が多い分作業効率も上がると思っていましたが足並みを合わせないといけないのでかえって時間がかかった気もします。

 

一人のやったほうが気楽でいいなと思いました。