├── .gitignore ├── LICENSE.md ├── NOTICE.md ├── README.md └── src ├── CMakeLists.txt ├── ConvertEncoding.h ├── FbxShapeUtils.h ├── main.cpp └── vmd.h /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | build 3 | *.fbx 4 | *.fbm 5 | *.vmd -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Takuya Isaki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /NOTICE.md: -------------------------------------------------------------------------------- 1 | This software contains Autodesk® FBX® code developed by Autodesk, Inc. Copyright 2019 Autodesk, Inc. All rights, reserved. Such code is provided “as is” and Autodesk, Inc. disclaims any and all warranties, whether express or implied, including without limitation the implied warranties of merchantability, fitness for a particular purpose or non-infringement of third party rights. In no event shall Autodesk, Inc. be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of such code. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vmdtofbx 2 | vmdファイルに含まれる表情データのみを面のメッシュに記録し、fbx形式にして出力するプロジェクト 3 | 4 | [DeepWiki](https://deepwiki.com/VirtualLiveLab/vmdtofbx) 5 | 6 | ## 環境 7 | - cmake 3.17 and above 8 | 9 | - FBX SDK 2020.3.7
10 | Link: https://aps.autodesk.com/developer/overview/fbx-sdk 11 | 12 | 13 | - Windows の場合 14 | - Visual Studio 17 2022 15 | 16 | - Linux の場合 17 | - GCC version 9.3 and above 18 | - iconv 19 | 20 |
21 | 22 | ## ビルド方法 23 | 24 | ### Windows 25 | 26 | 1. CMakeLists.txt の編集 27 | 28 | 導入した FBX SDK のパスに合わせて `FBX_SDK_ROOT` の設定パスを変えてください。 29 | ```CMake 30 | set(FBX_SDK_ROOT "C:/Program Files/Autodesk/FBX/FBX SDK/2020.3.7") 31 | ``` 32 | 33 | 2. ビルド 34 | 35 | - 動的リンクの場合 36 | 37 | ```Bash 38 | cd src 39 | cmake -S . -B build -DFBX_SHARED=1 40 | cmake --build build --config # Release または Debug 41 | ``` 42 | 43 | - 静的リンクの場合 44 | 45 | ```Bash 46 | cd src 47 | cmake -S . -B build -DFBX_STATIC_RTL=1 48 | cmake --build build --config # Release または Debug 49 | ``` 50 | 51 | いずれも *build/\* 下にビルドされたファイルが出力されます。
52 | 動的リンクの場合、同ディレクトリに libfbxsdk.dll がコピーされます。 53 | 54 | 55 | ### Linux 56 | 57 | ```Bash 58 | cd src 59 | cmake -S . B build -DCMAKE_BUILD_TYPE= # Release または Debug 60 | cmake --build build 61 | ``` 62 | 63 | *build* 下にビルドされたファイルが生成され、*build/\* 下に libfbxsdk.so がコピーされます。 64 | 65 | 66 | ### 注意 67 | FBX SDK には libfbxsdk の pdb ファイルが含まれていません。したがって、FBX SDK のみで Debug ビルドを行うと、デバッグ情報が見つからない旨のエラーが出ると思います(MSVC の場合、LNK4099エラー)。必要であれば、[ウェブサイト](https://aps.autodesk.com/developer/overview/fbx-sdk)の「FBX PDB」より pdb ファイルを入手してください。 68 | 69 | 70 |
71 | 72 | ## 使用方法 73 | まず vmdファイルを引数にとり、その後「"変換したい名前=変換後の名前"」という形式でシェイプキー名の変換を指定してください。 74 | 75 | ``` 76 | path/to/vmdtofbx path/to/.vmd "あ=a" "い=i" "う=u" "え=e" "お=o" 77 | ``` 78 | 79 | vmdファイルと同じディレクトリに「.fbx」が生成されます。 80 | 81 |
82 | 83 | License 84 | ------- 85 | 86 | [MIT](LICENSE.md)ですがコメントくれたら作者は喜びます(*'ω'*) 87 | 88 | **注意:** FBX SDK の License Agreement 1.1.5条に基づき、[NOTICE](/NOTICE.md)ファイルにおいて、FBX ライブラリ使用に関する文を記載しています。 89 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.17) 2 | project(vmdtofbx) 3 | 4 | # FBX SDK のパスを指定 - ビルド前に変更してください 5 | set(FBX_SDK_ROOT "C:/Program Files/Autodesk/FBX/FBX SDK/2020.3.7") 6 | 7 | # OS の確認 8 | if(NOT WIN32 AND NOT UNIX) 9 | message(FATAL_ERROR "Only Windows (MSVC) or UNIX is supported.") 10 | endif() 11 | 12 | # Windows のみの FbxAnsiToUTF8() への代替 13 | if(UNIX) 14 | find_package(Iconv REQUIRED) 15 | endif() 16 | 17 | # CMAKE_CXX_FLAGS ではなく Abstraction によって MSVC runtime library を指定 18 | if(POLICY CMP0091) 19 | cmake_policy(SET CMP0091 NEW) 20 | endif(POLICY CMP0091) 21 | 22 | # アーキテクチャの種類を取得 23 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 24 | if("${CMAKE_C_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM64") 25 | SET(FBX_ARM 1) 26 | set(FBX_ARCH arm64) 27 | else() 28 | set(FBX_ARCH x64) 29 | endif() 30 | endif() 31 | 32 | # fbxsdk.cmake で使用される変数の設定と、そのサンプルスクリプトの実行 33 | set(FBX_BUILD_ROOT ${CMAKE_BINARY_DIR}) 34 | include("${FBX_SDK_ROOT}/samples/fbxsdk.cmake") 35 | 36 | # Dynamic Link の場合の Processer Definition の設定 37 | if(FBX_SHARED) 38 | add_compile_definitions(FBXSDK_SHARED) 39 | endif() 40 | 41 | # プロジェクトのソースを追加 42 | add_executable(${PROJECT_NAME} 43 | main.cpp 44 | ConvertEncoding.h 45 | FbxShapeUtils.h 46 | vmd.h 47 | ) 48 | 49 | # コンパイルオプションの設定 50 | if(WIN32) 51 | target_compile_options(${PROJECT_NAME} PRIVATE /source-charset:UTF-8) 52 | elseif(UNIX) 53 | target_compile_options(${PROJECT_NAME} PRIVATE -finput-charset=UTF-8) 54 | endif() 55 | 56 | # FBX SDK には libfbxsdk の pdb ファイルが含まれていない(同ウェブサイトで別途配布) 57 | # そのため、Debug ビルドの際の LNK4099 エラーは出力されないようにしておく 58 | if(WIN32) 59 | target_link_options(${PROJECT_NAME} PRIVATE /IGNORE:4099) 60 | endif() 61 | 62 | # ライブラリのリンク 63 | if(WIN32) 64 | if(FBX_SHARED) 65 | target_link_libraries(${PROJECT_NAME} PRIVATE fbxsdk) 66 | else() 67 | # 公式ドキュメント「Configuring the FBX SDK for Windows」の Configuring Visual Studio を参照 68 | target_link_options(${PROJECT_NAME} PRIVATE $<$:/NODEFAULTLIB:LIBCMT>) 69 | target_link_libraries(${PROJECT_NAME} PRIVATE fbxsdk $<$:wininet.lib>) 70 | endif() 71 | elseif(UNIX) 72 | target_link_libraries(${PROJECT_NAME} PRIVATE fbxsdk Iconv::Iconv) 73 | endif() 74 | 75 | # ライブラリリンク後の設定(fbxsdk.cmakeで定義された関数) 76 | fbx_target_finalize(${PROJECT_NAME}) -------------------------------------------------------------------------------- /src/ConvertEncoding.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifdef _WIN32 5 | #include 6 | #include 7 | #else 8 | #include 9 | #endif 10 | 11 | #ifdef _WIN32 12 | 13 | bool IsShiftJISEnvironment() 14 | { 15 | return GetConsoleCP() == 932; // 932 = Shift_JIS 16 | } 17 | 18 | std::string sjis_to_utf8(const std::string &input) 19 | { 20 | std::string name_converted; 21 | char *utf8Str = nullptr; 22 | size_t utf8Size = 0; 23 | 24 | FbxAnsiToUTF8(input.c_str(), utf8Str, &utf8Size); 25 | if (utf8Str) 26 | { 27 | name_converted = std::string(utf8Str); 28 | FbxFree(utf8Str); 29 | } 30 | return name_converted; 31 | } 32 | 33 | #else 34 | 35 | bool IsShiftJISEnvironment() 36 | { 37 | return false; 38 | } 39 | 40 | std::string sjis_to_utf8(const std::string &input) 41 | { 42 | iconv_t cd = iconv_open("UTF-8", "SHIFT_JIS"); 43 | if (cd == (iconv_t)-1) 44 | { 45 | perror("iconv_open failed"); 46 | return ""; 47 | } 48 | 49 | size_t inSize = input.size(); 50 | size_t outSize = inSize * 4; 51 | char *inBuf = const_cast(input.c_str()); 52 | std::vector outBuf(outSize); 53 | char *outPtr = outBuf.data(); 54 | 55 | if (iconv(cd, &inBuf, &inSize, &outPtr, &outSize) == (size_t)-1) 56 | { 57 | perror("iconv failed"); 58 | iconv_close(cd); 59 | return ""; 60 | } 61 | 62 | iconv_close(cd); 63 | return std::string(outBuf.data()); 64 | } 65 | 66 | #endif -------------------------------------------------------------------------------- /src/FbxShapeUtils.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // シェイプアニメーション記録用の四角いメッシュを作成 7 | FbxMesh *CreateSquareMesh(FbxScene *pScene) 8 | { 9 | FbxMesh *lMesh = FbxMesh::Create(pScene, "VMDshapeAnimation"); 10 | 11 | // 四角いメッシュの4つの頂点を定める 12 | FbxVector4 vertices[4] = { 13 | {-50, -50, 0}, // Bottom left 14 | {50, -50, 0}, // Bottom right 15 | {50, 50, 0}, // Top right 16 | {-50, 50, 0} // Top left 17 | }; 18 | 19 | // メッシュに頂点(Control Point)を登録 20 | lMesh->InitControlPoints(4); 21 | for (int i = 0; i < 4; i++) 22 | { 23 | lMesh->SetControlPointAt(vertices[i], i); 24 | } 25 | 26 | // 登録した Control Point からポリゴンを構成 27 | lMesh->BeginPolygon(); 28 | for (int i = 0; i < 4; i++) 29 | { 30 | lMesh->AddPolygon(i); 31 | } 32 | lMesh->EndPolygon(); 33 | 34 | return lMesh; 35 | } 36 | 37 | // メッシュ内のシェイプキー関連要素を設定 38 | void ConfigureBlendShapeDeformer(FbxMesh *pMesh, std::vector pShapekeyNames) 39 | { 40 | // BlendShapeDeformer を作成 41 | FbxBlendShape *lBlendShapeDeformer = FbxBlendShape::Create(pMesh, "Deformer_VMDshapeAnimation"); 42 | pMesh->AddDeformer(lBlendShapeDeformer); 43 | 44 | for (int i = 0; i < pShapekeyNames.size(); i++) 45 | { 46 | const char *shapekey_name = pShapekeyNames.at(i).c_str(); 47 | 48 | // BlendShapeChannel を作成 49 | FbxBlendShapeChannel *lBlendShapeChannel = FbxBlendShapeChannel::Create(lBlendShapeDeformer, shapekey_name); 50 | lBlendShapeDeformer->AddBlendShapeChannel(lBlendShapeChannel); 51 | 52 | // Shape を作成し、BlendShapeChannel に登録 53 | FbxShape *targetshape = FbxShape::Create(pMesh, shapekey_name); 54 | lBlendShapeChannel->AddTargetShape(targetshape); 55 | } 56 | } 57 | 58 | // メッシュ内のシェイプキーの AnimationCurve を作成し、シェイプキー名とのマップを返す 59 | std::unordered_map CreateShapeCurveMap(FbxMesh *pMesh, FbxAnimLayer *pAnimLayer) 60 | { 61 | std::unordered_map shapecurvemap; 62 | FbxScene *lScene = pMesh->GetScene(); 63 | FbxBlendShape *lBlendShapeDeformer = nullptr; 64 | 65 | // メッシュの BlendShape Deformer の取得 66 | for (int i = 0; i < pMesh->GetDeformerCount(); i++) 67 | { 68 | FbxDeformer *lDeformer = pMesh->GetDeformer(i); 69 | if (lDeformer->Is()) 70 | { 71 | lBlendShapeDeformer = FbxCast(lDeformer); 72 | break; 73 | } 74 | } 75 | 76 | if (lScene && lBlendShapeDeformer) 77 | { 78 | for (int i = 0; i < lBlendShapeDeformer->GetBlendShapeChannelCount(); i++) 79 | { 80 | FbxBlendShapeChannel *shapekey = lBlendShapeDeformer->GetBlendShapeChannel(i); 81 | 82 | // AnimationCurveNode と AnimationCurve を作成 83 | FbxAnimCurveNode *lAnimCurveNode = FbxAnimCurveNode::CreateTypedCurveNode(shapekey->DeformPercent, lScene); 84 | FbxAnimCurve *lAnimCurve = FbxAnimCurve::Create(lScene, shapekey->GetName()); 85 | 86 | // CurveNode を AnimationLayer および Property に、Curve を CurveNode の Channel に接続 87 | pAnimLayer->AddMember(lAnimCurveNode); 88 | shapekey->DeformPercent.ConnectSrcObject(lAnimCurveNode); 89 | lAnimCurveNode->ConnectToChannel(lAnimCurve, "DeformPercent"); 90 | 91 | // マップにシェイプキー名と Curve を登録 92 | shapecurvemap.emplace(shapekey->GetName(), lAnimCurve); 93 | } 94 | } 95 | 96 | return shapecurvemap; 97 | } 98 | 99 | // 既存のシェイプキーの名称を変更 100 | void UpdateShapekeyName(FbxMesh *pMesh, std::string pOldName, std::string pNewName) 101 | { 102 | FbxBlendShape *lBlendShapeDeformer = nullptr; 103 | 104 | // メッシュの BlendShape Deformer の取得 105 | for (int i = 0; i < pMesh->GetDeformerCount(); i++) 106 | { 107 | FbxDeformer *lDeformer = pMesh->GetDeformer(i); 108 | if (lDeformer->Is()) 109 | { 110 | lBlendShapeDeformer = FbxCast(lDeformer); 111 | break; 112 | } 113 | } 114 | 115 | if (lBlendShapeDeformer) 116 | { 117 | for (int i = 0; i < lBlendShapeDeformer->GetBlendShapeChannelCount(); i++) 118 | { 119 | FbxBlendShapeChannel *shapekey = lBlendShapeDeformer->GetBlendShapeChannel(i); 120 | if (std::string(shapekey->GetName()) == pOldName) 121 | { 122 | // BlendShapeChannel と Shape の両方の名称を変える 123 | shapekey->SetName(pNewName.c_str()); 124 | shapekey->GetTargetShape(0)->SetName(pNewName.c_str()); 125 | } 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "vmd.h" 4 | #include "FbxShapeUtils.h" 5 | #include "ConvertEncoding.h" 6 | using namespace std; 7 | 8 | // 変換状況をデバッグ表示する関数 9 | void DebugConverting(uint32_t frame_no, string name_processing, unordered_map shape_rename_map); 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | // vmdファイルの読み込み 14 | filesystem::path vmdfilepath(argv[1]); 15 | if (!filesystem::exists(vmdfilepath)) 16 | { 17 | cerr << "Error : Cannot find the vmd file. -> " << vmdfilepath.string() << endl; 18 | return -1; 19 | } 20 | ifstream vmdfile(vmdfilepath, ios::binary); 21 | 22 | // vmdファイルから、表情アニメーション全フレームと、シェイプキーの一覧を取得 23 | vector skindata = ReadAndGetSkinData(vmdfile); 24 | vector shapekey_names = GetShapekeyNames(skindata); 25 | 26 | // FBX SDK では UTF-8 で扱う必要あり 27 | for (auto &name : shapekey_names) 28 | { 29 | name = sjis_to_utf8(name); 30 | } 31 | 32 | // 引数を用いて、シェイプキー名称の変更前後のマップを作成 33 | unordered_map shape_rename_map; 34 | for (int i = 2; i < argc; ++i) 35 | { 36 | string arg(argv[i]); 37 | size_t pos = arg.find('='); 38 | if (pos != string::npos) 39 | { 40 | string key = arg.substr(0, pos); 41 | string value = arg.substr(pos + 1); 42 | shape_rename_map[key] = value; 43 | } 44 | } 45 | 46 | // FbxManager, FbxIOSettings の設定と新規Scene の作成 47 | FbxManager *lSdkManager = FbxManager::Create(); 48 | FbxIOSettings *IOSettings = FbxIOSettings::Create(lSdkManager, IOSROOT); 49 | lSdkManager->SetIOSettings(IOSettings); 50 | FbxScene *lScene = FbxScene::Create(lSdkManager, "New Scene"); 51 | 52 | // 出力先パスの設定と、Exporter の準備 53 | string fbxfilename = vmdfilepath.stem().string() + ".fbx"; 54 | filesystem::path outputfbxpath = vmdfilepath.parent_path() / fbxfilename; 55 | FbxExporter *lExporter = FbxExporter::Create(lSdkManager, ""); 56 | 57 | // Initialize() に渡す出力パスが Shift-JIS だった場合、Initialize() は true を返すが Export時にエラーが起きる 58 | string outputfbxpathStr = IsShiftJISEnvironment() ? sjis_to_utf8(outputfbxpath.string()) : outputfbxpath.string(); 59 | 60 | bool exporter_prepared = lExporter->Initialize(outputfbxpathStr.c_str(), -1, IOSettings); 61 | 62 | if (exporter_prepared) 63 | cout << "The exporter successfully initialized." << endl; 64 | else 65 | { 66 | cerr << "Initializing the exporter failed..." << endl; 67 | cout << lExporter->GetStatus().GetErrorString() << endl; 68 | vmdfile.close(); 69 | lSdkManager->Destroy(); 70 | return -1; 71 | } 72 | 73 | // FbxAnimStack と FbxAnimationLayer の作成 74 | FbxAnimStack *lAnimStack = FbxAnimStack::Create(lScene, "Take_VMDshapeAnimation"); 75 | FbxAnimLayer *lAnimLayer = FbxAnimLayer::Create(lScene, "BaseAnimation"); 76 | lAnimStack->AddMember(lAnimLayer); 77 | 78 | // アニメーションを記録するメッシュの作成 79 | FbxMesh *lMesh = CreateSquareMesh(lScene); 80 | FbxNode *lMeshNode = FbxNode::Create(lScene, "VMDshapeAnimation"); 81 | lMeshNode->SetNodeAttribute(lMesh); 82 | lScene->GetRootNode()->AddChild(lMeshNode); 83 | 84 | // メッシュにシェイプキーを作成 85 | ConfigureBlendShapeDeformer(lMesh, shapekey_names); 86 | 87 | // シェイプキーの AnimationCurve を設定し、シェイプキー名とのマップを作成 88 | unordered_map shapecurvemap = CreateShapeCurveMap(lMesh, lAnimLayer); 89 | 90 | // フレーム毎にシェイプキーに対応する AnimationCurve を取得してアニメーションを記録 91 | for (const auto &frame : skindata) 92 | { 93 | string shapekey_name = sjis_to_utf8(string(frame.SkinName)); 94 | auto it = shapecurvemap.find(shapekey_name); 95 | if (it != shapecurvemap.end()) 96 | { 97 | FbxAnimCurve *lCurve = it->second; 98 | if (lCurve) 99 | { 100 | lCurve->KeyModifyBegin(); 101 | 102 | // 表情の1フレーム分のキーを登録 103 | FbxTime lTime; 104 | lTime.SetFrame(frame.FrameNo, FbxTime::eFrames30); // MMD は 30fps 105 | int keyindex = lCurve->KeyAdd(lTime); 106 | 107 | // MMDでのシェイプキー値は 0~1 なので、fbxに合わせて100倍する 108 | lCurve->KeySet(keyindex, lTime, frame.Weight * 100.0, FbxAnimCurveDef::eInterpolationLinear); 109 | 110 | lCurve->KeyModifyEnd(); 111 | 112 | // ターミナルに変換状況をデバッグ表示 113 | DebugConverting(frame.FrameNo, frame.SkinName, shape_rename_map); 114 | } 115 | } 116 | } 117 | 118 | // 名称変更前後のマップ(引数の指定から作成)を元に、既存のシェイプキー名を変更 119 | for (const auto &map : shape_rename_map) 120 | { 121 | string name_old = IsShiftJISEnvironment() ? sjis_to_utf8(map.first) : map.first; 122 | string name_new = map.second; 123 | UpdateShapekeyName(lMesh, name_old, name_new); 124 | } 125 | 126 | // Scene の出力 127 | if (lExporter->Export(lScene)) 128 | cout << "\nProgram Success!" << endl; 129 | else 130 | { 131 | cout << "\nError occurred while exporting the scene..." << endl; 132 | cout << lExporter->GetStatus().GetErrorString() << endl; 133 | } 134 | 135 | // Cleanup 136 | vmdfile.close(); 137 | lSdkManager->Destroy(); 138 | 139 | return 0; 140 | } 141 | 142 | void DebugConverting(uint32_t frame_no, string name_processing, unordered_map shape_rename_map) 143 | { 144 | string key = IsShiftJISEnvironment() ? name_processing : sjis_to_utf8(name_processing); 145 | 146 | // 現在キー登録中の名前が変換前後のマップに含まれていれば、その対応を出力する 147 | unordered_map::const_iterator it = shape_rename_map.find(key); 148 | if (it != shape_rename_map.end()) 149 | { 150 | cout << frame_no << " " << key << " -> " << it->second << endl; 151 | } 152 | } -------------------------------------------------------------------------------- /src/vmd.h: -------------------------------------------------------------------------------- 1 | // VMD format & functions 2 | // source : https://blog.goo.ne.jp/torisu_tetosuki/e/bc9f1c4d597341b394bd02b64597499d 3 | 4 | #ifndef __VMD_H__ 5 | #define __VMD_H__ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #pragma pack(push, 1) 14 | 15 | static const size_t VMD_HEADER_SIZE = 50; 16 | static const size_t VMD_MOTION_SIZE = 111; 17 | 18 | // 表情データ 19 | struct VMD_SKIN 20 | { 21 | char SkinName[15]; // Shift_JIS 22 | uint32_t FrameNo; 23 | float Weight; 24 | }; 25 | 26 | // vmdファイル内の表情データ部分の読み出し 27 | std::vector ReadAndGetSkinData(std::ifstream &vmdfile) 28 | { 29 | // skin count 部分まで読み飛ばす 30 | vmdfile.ignore(VMD_HEADER_SIZE); 31 | uint32_t vmd_motion_count; 32 | vmdfile.read(reinterpret_cast(&vmd_motion_count), sizeof(vmd_motion_count)); 33 | for (size_t i = 0; i < static_cast(vmd_motion_count); i++) 34 | { 35 | vmdfile.ignore(VMD_MOTION_SIZE); 36 | } 37 | 38 | // skin count 部分の読み出し 39 | uint32_t vmd_skin_count; 40 | vmdfile.read(reinterpret_cast(&vmd_skin_count), sizeof(vmd_skin_count)); 41 | 42 | // skin data の取得 43 | std::vector skindata; 44 | for (size_t i = 0; i < static_cast(vmd_skin_count); i++) 45 | { 46 | VMD_SKIN vmd_skin; 47 | vmdfile.read(reinterpret_cast(&vmd_skin), sizeof(VMD_SKIN)); 48 | skindata.push_back(vmd_skin); 49 | } 50 | return skindata; 51 | } 52 | 53 | // 取得した vmdの表情の全データより、シェイプキー一覧の抽出 54 | std::vector GetShapekeyNames(std::vector pSkinData) 55 | { 56 | std::vector shapekey_names; 57 | for (const auto &skin : pSkinData) 58 | { 59 | std::string shapekey_name(skin.SkinName); 60 | auto it = std::find(shapekey_names.begin(), shapekey_names.end(), shapekey_name); 61 | if (it == shapekey_names.end()) 62 | { 63 | shapekey_names.push_back(shapekey_name); 64 | } 65 | } 66 | return shapekey_names; 67 | } 68 | 69 | #pragma pack(pop) 70 | 71 | #endif //__VMD_H__ --------------------------------------------------------------------------------