├── .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__
--------------------------------------------------------------------------------