この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
概要
前回の記事にThreeDPoseTracker(Unity) -> VMCtoMOP(Unity) -> MopUE4という形でUnityツールの骨格認識経由でUE4のモデルを動かしましたが、リリース版のものを使ったので、中身はどういう感じか分かりませんでした。
モーション周りの勉強のため、プロジェクト上でモーションデータ取り出したいと思います。最新の ThreeDPoseTracker(Unity) は現時点 Close Source になっているらしいですが、VMCtoMOPはOpen Sourceなので、VMCtoMOPのプロジェクトを立ち上げ、ソース改造し、モーション(VMCとMOP両方)を出力してみたいと思います。
マシン環境
CPU : Intel i7-6920HQ
GPU : AMD Radeon Pro 460
Memory : 16GB
System : Windows 10 (with .NET 5 installed)
IDE : Visual Studio 2019 Community
Editor : Visual Studio Code
Terminal : Windows Terminal (or Command Prompt)
Engine : Unity 2020.3.17f1 Personal
事前準備
GitHub: VMCtoMOP by HAL9HARUKU まず上記のプロジェクトをダウンロードします(zipファイルかgit cloneかどちでも大丈夫)、。展開(Clone)したものをUnity Hubで開いて、Safe Modeを無視し、Ignoreを押してプロジェクトを開きます。
VMCtoMOP 依存ライブラリなどを参照することで、下記のパッケージも用意します: - TextMeshPro 3.0.4 (Unity 公式) - UniVRM v0.66.0 - uOSC v0.0.2 - UniRx Ver 7.1.0 - UniTask Ver.2.2.5 - VRoid: Vivi
Unity Packages
Assets -> Import Package -> Custom Packageでダウンロードした四つパッケージをプロジェクトに追加します。
TextMeshPro
TextMeshProは公式のPackage ManagerでInstallできます。
それからMainSceneを開くと、TMP Importerのことが聞かれます。Import TMP Essentialsを選択してください。
VRoid Vivi
版権などの問題だと思いますが、キャラクターモデルViviはプロジェクトに含まれていません。外部リンクVRoid: ViviでViviのVRMファイルをダウンロードします(サイトのアカウント登録が必要)。
先ほどUniVRMが追加されたので、メニューにVRM0ボタンが表示されます。VRM0 -> ImportでダウンロードしたViviのVRMファイルをプロジェクトに追加します。
もともとシーンにあったViviを削除して、追加されたViviをシーンに入れて、新しいViviを Manager -> Manager(Script) -> Animator と Manager -> Mop Sender(Script) -> Animator の参照にします(Drag&Drop)。
シーンにあるViviを選択し、InspectorのとこでVRM Meta(Script) -> Information -> Versionにワーニングが出ていて、適当な数字を入れれば大丈夫です。
Viviのポジションを(0,0,0)にしてください。
ソースの改造
.json
の形で高速、大量なデータの書き込みは問題が発生してますので(解決したら修正します)、.txt
の形でモーションデータを保存します。
モーションが発生するタイミングはTime.deltaTime
で加算し、記録されます。
VMCモーションデータ(for Unity)の出力
まずOscServer.csにソースコードを追加し、VMCモーションデータをアウトプットします。
using System.IO;
public void Run(int port)
{
// ......省略
CreateFileAndWriter();
}
private void Update()
{
// lock(lockObject_)
// {
// while (parser_.messageCount > 0)
// {
// var message = parser_.Dequeue();
// onDataReceived.Invoke(message);
OutputVmcMotion(message);
// }
// }
time += Time.deltaTime;
}
FileStream fileStream = null;
StreamWriter writer = null;
float time = .0f;
private void CreateFileAndWriter()
{
var dirInfo = Directory.CreateDirectory("D:/MotionData/");
string fileName = "MotionVmc" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".txt";
fileStream = File.Create(dirInfo.FullName + fileName);
writer = new StreamWriter(fileStream, System.Text.Encoding.UTF8);
}
private void OutputVmcMotion(Message message)
{
if(message.address == "/VMC/Ext/Root/Pos" || message.address == "/VMC/Ext/Bone/Pos")
{
string address = message.address;
string name = (string)message.values[0];
Vector3 pos = new Vector3((float)message.values[1], (float)message.values[2], (float)message.values[3]);
Quaternion rot = new Quaternion((float)message.values[4], (float)message.values[5], (float)message.values[6], (float)message.values[7]);
writer.WriteLine($"a:{address}, n:{name}, p:{pos}, r:{rot}, t:{time}");
}
}
private void OnDestroy()
{
writer?.Close();
}
CreateFileAndWriter()
で現時点をファイル名(txt)としてD:/MotionData/
にVMCモーションデータを保存するファイルを作って、ファイルに書き込むStreamWriterを準備します。
OutputVmcMotion(Message message)
でVMCのモーションデータをa:{address}, n:{name}, p:{pos}, r:{rot}, t:{time}
の形で作ったファイルに保存します。
ファイルに書き込むことが終ったら(プログラムが中断されたら)OnDestroy()
にStreamWriter.Close()
でファイルを解放してください。
MOPモーションデータ(for UE4)の出力
Unreal Engine用のMOPモーションデータを保存するため、MopSender.csを改造します。
MopSender.cs
using System;
using System.IO;
private void Start()
{
//......省略
CreateFileAndWriter();
}
private void OnDestroy()
{
//......省略
writer?.Close();
}
private void SendMotion()
{
//......省略
time += Time.deltaTime;
}
private void PostBodySize()
{
for (var parameterIndex = 0; parameterIndex < BoneParameterNum; ++parameterIndex)
{
//......省略
OutputMopBodySize(message);
}
}
private void PostBones()
{
// var sb = new System.Text.StringBuilder();
for (var parameterIndex = 0; parameterIndex < BoneParameterNum; ++parameterIndex)
{
//......省略
uOSC.Message message = new uOSC.Message($"/Mop/BoneControl/{BoneNameList[parameterIndex]}",
-location.x * 100.0f, location.z * 100.0f, location.y * 100.0f,
-rotation.x, rotation.z, rotation.y, rotation.w);
this.sendBundle.Add(message);
OutputMopBone(message);
}
}
FileStream fileStream = null;
StreamWriter writer = null;
float time = .0f;
private void CreateFileAndWriter()
{
var dirInfo = Directory.CreateDirectory("D:/MotionData/");
string fileName = "MotionMop" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".txt";
fileStream = File.Create(dirInfo.FullName + fileName);
writer = new StreamWriter(fileStream, System.Text.Encoding.UTF8);
}
private void OutputMopBodySize(uOSC.Message message)
{
string name = message.address;
Vector3 size = new Vector3(
Convert.ToSingle(message.values[0]),
Convert.ToSingle(message.values[1]),
Convert.ToSingle(message.values[2]));
string str = $"n:{name}, s:{size}, t:{time}";
writer.WriteLine(str);
}
private void OutputMopBone(uOSC.Message message)
{
string name = message.address;
Vector3 pos = new Vector3(
Convert.ToSingle(message.values[0]),
Convert.ToSingle(message.values[1]),
Convert.ToSingle(message.values[2]));
Quaternion rot = new Quaternion(
Convert.ToSingle(message.values[3]),
Convert.ToSingle(message.values[4]),
Convert.ToSingle(message.values[5]),
Convert.ToSingle(message.values[6]));
string str = $"n:{name}, p:{pos}, r:{rot}, t:{time}";
writer.WriteLine(str);
}
CreateFileAndWriter()
で現時点をファイル名(txt)としてD:/MotionData/
にMOPモーションデータを保存するファイルを作って、ファイルに書き込むStreamWriterを準備します。
Unreal Engineに転送するMOPモーションデータはBody Size(size)とBone Data(position, rotation)二種類があるらしいので、OutputMopBodySize(uOSC.Message message)
と OutputMopBone(uOSC.Message message)
を用いいします。VMCの場合はaddress
とname
に分けていますが、MOPは骨パスはname
にまとめているらしいです。
Body Sizeはn:{name}, s:{size}, t:{time}
、Bone Dataはn:{name}, p:{pos}, r:{rot}, t:{time}
という感じにフォマードし、D:/MotionData/
に記録されます。
プロジェクト実行
前回の記事の流れて(モーションデータの記録だけなので、UE4の部分は起動しなくても大丈夫)、VMCtoMOPリリース版の代わりに、今回作ったUnityプロジェクトを実行します。
実行されたら、スクリーンショットの感じでVMCとMOP両方のモーションデータが保存されるはずです。
最後
モーションデータを保存できて、画面上Key Annotationの描画やモーションの機械学習などができるかもしれないと思います。ただ、実際使いたいモーションデータのフォマードに合わせて一部追加改造が必要です。
自分がモーションについて知識が少ないので、またVMCとMOPについて詳しく調べたいと思います。
以上です。