本日はMixedRealityModelingTools枠です。
〇データフォーマットの定義
MRMTではデータの送信フォーマットにMessagePackを使用しています。
開発時はBlender側とプラットフォーム側で個のフォーマットが一致しているという条件のもとデータの送受信が行えます。
Unity側からカメラ位置情報をBlenderに送信しますが、この場合もまずデータのフォーマットを定義する必要があります。
今回は次のように定義しました。
・ヘッダー:データによって処理を変えるために使用
・cameratranfform:Unityのカメラ位置
・camerarotation:Unityのカメラ角度
cameraに関してはtransformに角度をまとめることも考えたのですが、処理の都合と今後の機能開発のために分離支えています。
[DataContract]
public class UnityCameraData
{
[DataMember] public string header;
[DataMember] public List<float> cameratransform;
[DataMember] public List<float> camerarotation;
}
次にMessagePackを使用したカスタムシリアライズ、デシリアライズについての処理です。
ここでは定義した独自のフォーマットでMessagePackを使用した処理を行うための処理になります。
IFormatterResolverを継承したリゾルバークラスとIMessagePackFormatter<(データフォーマットクラス)>を継承するフォーマッターは次のようになります。
なおフォーマッターは、先に定義したデータクラスを使用してデータをフォーマットするクラスです。
リゾルバーとはフォーマッターを使用してデータのシリアライズ、デシリアライズするためのメソッドを定義します。
public class CustomUnityCameraResolver : IFormatterResolver
{
//MessagePackの機能とフォーマッターを使用してカスタムリゾルバーを作成
public static readonly IFormatterResolver Instance = CompositeResolver.Create(
new IMessagePackFormatter[] { new UnityCameraDataFormatter() },
new IFormatterResolver[] {
StandardResolver.Instance,
UnityResolver.Instance
}
);
public IMessagePackFormatter<T> GetFormatter<T>()
{
return Instance.GetFormatter<T>();
}
}
public class UnityCameraDataFormatter:IMessagePackFormatter<UnityCameraData>
{
//シリアライズする際のカスタムメソッド
public void Serialize(ref MessagePackWriter writer, UnityCameraData value, MessagePackSerializerOptions options)
{
//フォーマットのデータの数 それぞれの方に合わせてカスタムシリアライズを定義
writer.WriteArrayHeader(3);
options.Resolver.GetFormatterWithVerify<string>().Serialize(ref writer, value.header, options);
options.Resolver.GetFormatterWithVerify<List<float>>().Serialize(ref writer, value.cameratransform, options);
options.Resolver.GetFormatterWithVerify<List<float>>().Serialize(ref writer, value.camerarotation, options);
}
//フォーマッターのデータに合わせてカスタムデシリアライザーを定義
public UnityCameraData Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
if (reader.TryReadNil())
{
return null;
}
options.Security.DepthStep(ref reader);
int length = reader.ReadMapHeader();
//フォーマット内のデータが3の場合のみ処理(フォーマットに合っていないデータは処理しない)
if (length != 3)
{
throw new MessagePackSerializationException("Invalid map length.");
}
//データの初期化
string header = null;
List<float> cameratransform = null;
List<float> camerarotation = null;
//データの大きさ処理
for (int i = 0; i < length; i++)
{
string key = reader.ReadString();
switch (key)
{
case "header":
header = options.Resolver.GetFormatterWithVerify<string>().Deserialize(ref reader, options);
break;
case "cameratransform":
cameratransform = options.Resolver.GetFormatterWithVerify<List<float>>().Deserialize(ref reader, options);
break;
case "camerarotation":
camerarotation = options.Resolver.GetFormatterWithVerify<List<float>>().Deserialize(ref reader, options);
break;
default:
reader.Skip();
break;
}
}
reader.Depth--;
return new UnityCameraData() { header = header, cameratransform = cameratransform, camerarotation = camerarotation };
}
〇カメラデータの取得とBlender側に送信
上記で作成したフォーマットに従いUnityのカメラ情報を取得して送信するメソッドが次になります。
public byte[] SendCameraTransformData()
{
Transform cameraTransform = _camera.transform;//カメラの情報を取得
//UnityCameraDataのフォーマットに従い新しいデータを作成
UnityCameraData cameraData = new UnityCameraData
{
header = "UCAM", //ヘッダー "U"nity "CAM"era
cameratransform = new List<float>
{
cameraTransform.position.x,
cameraTransform.position.z,
cameraTransform.position.y
},
camerarotation = new List<float>
{
cameraTransform.eulerAngles.x +90,
cameraTransform.eulerAngles.z,
cameraTransform.eulerAngles.y
}
};
//MessagePackを使用してcameraDataをシリアライズ
var options = MessagePackSerializerOptions.Standard.WithResolver(CompositeResolver.Create(
new IMessagePackFormatter[] { new UnityCameraDataFormatter() },
new IFormatterResolver[] {
CustomUnityCameraResolver.Instance
}
));
byte[] serializedData = MessagePackSerializer.Serialize(cameraData, options);
return serializedData;
}
最後にTCPCliant側でBlenderにデータを送信するメソッドは次になります。
public void SendCameraDataToUnity()
{
var bytes = _unitySendData.SendCameraTransformData();
Debug.Log(BitConverter.ToString(bytes).Replace("-", ""));
_stream.Write(_unitySendData.SendCameraTransformData(), 0, _unitySendData.SendCameraTransformData().Length);
}
ここではcpClient(ipAddress, port).GetStream().Write()を使用してデータの書き込みを行います。
本日は以上です。