本日は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()を使用してデータの書き込みを行います。
本日は以上です。