夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

Blenderでサーバーを立てMessagePackでメッシュを送信する その⑧Unity側でヘッダー情報をもとにデシリアライズの処理を分ける

本日はMixedRealityModelingToolsについての開発です。

昨日はマテリアル情報を送信できるようになりましたので今回はUnityの処理になります。

〇Headerの定義

今まではMessagePackでシリアライズされた形式のデータであるかそうでないかという区別ができればよかったので次のようなコードでシリアライズに失敗した場合は通常のメッセージとして扱っていました。

 public void StartConnection()
        {
          ・・・
            new Thread(() =>
            {
               ・・・
                while (true)
                {
                    var bytesRead = _stream.Read(responseBytes, 0, responseBytes.Length);
                    ・・・
                    try
                    {
                        var meshData = DeserializeMeshData(responseBytes);

                      _objectBuilder.meshData = meshData;
                      _objectBuilder._isGetMeshData = true;
                    }
                    catch
                    {
                        Debug.Log("Received: " + 
                        Encoding.ASCII.GetString(responseBytes, 0, bytesRead));
                    }
                }
            }).Start();
            UpdateConnectionStatus();
        }

DeserializeMeshData()ではMeshDataというメッシュのデータを格納するクラスにデータを格納しています。

    [DataContract]
    public class MeshData
    {
        [DataMember]
        public string objectname;
        
        [DataMember]
        public List<float> vertices;
    
        [DataMember]
        public List<int> triangles;
    
        [DataMember]
        public List<float> normals;
    }

 マテリアルのデータは上記の形式とは異なるためまず受け取ったデータがメッシュについてのデータなのか?マテリアルに関してのデータなのかを区別する必要が発生します。

 今回はヘッダーをデータにつけることで解決させます。

 まずは送信側であるBlenderのコード側でheaderを定義します。

    MESH_HEADER = "MESH"  # メッシュデータのヘッダー
    # Build data as Dictionary
    data_dict = {
        'header': MESH_HEADER,
        'objectname' : bpy.context.view_layer.objects.active.name,
        'vertices': vertices_list,
        'triangles': triangles_list,
        'normals': normals_list
    }
                MAT_HEADER = "MATE"
                mat_data_dict = {
                    'header': MAT_HEADER,
                    'materialname': [selected_material_name],
                    'rgba': rgba_list
                }

これによってメッシュのデータにはMESH、MATEの文字列が冒頭につくようになります。

\x83\xa6header\xa4MATE\として冒頭部にMETAという情報が含まれる

Unity側ではこの情報をもとに処理を分けていきます。

〇Unity側でヘッダー情報をもとに処理を分ける

ヘッダー情報を取得するためには文字列のデータから一部の文字列を取得するGetString()を使用します。

GetString("文字列",int 取得したい文字数(冒頭部から), int 取得したい長さ)という使い方をします。

            string header = Encoding.ASCII.GetString(data, 9, 4);

今回の場合は9番目の文字から4文字(MESH、MATE)取得することでヘッダー情報を取得できます。

フォーマットによって若干異なるものの、基本的に冒頭部にヘッダー情報が含まれます。

   private void ProcessReceivedData(byte[] data, int length)
        {
            // Get the header from the received data
            string header = Encoding.ASCII.GetString(data, 9, 4);
            if (header == "MESH")
            {
              ・・・
     //メッシュデータの処理
            }
            else if (header == "MATE")
            {
      ・・・
               //マテリアルデータの処理
            }
            else
            {
                Debug.Log($"Received unknown data with header: {header}");
            }
        }

以上で複数のデータフォーマットの処理に対応できるようになりました。

この仕組みによって今後データ形式が増えても上記if文の処理を追加すればよいということになり非常に拡張性が生まれました。

本日は以上です。