夜風のMixedReality

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

Blenderでサーバーを立てMessagePackでメッシュを送信する その⑥オブジェクト名をUnityに送る

本日はBlenderモデリング枠、Unity枠です。

現在BlenderとUnityを連携させるパッケージMixedRealityModelingToolを開発しています。

ここまではMessagePackを使用してBlenderで選択中のメッシュデータをUnityに送信し、Unityでデシリアライズしてメッシュを構成することまで実現しています。

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

今回はメッシュデータとともにオブジェクト名を送信します。

オブジェクト名をメッシュデータとともに送信することで、オブジェクトをUnity側で区別することができます。

Blenderでオブジェクト名を取得する

Blender側で現在選択しているオブジェクト名を取得するコードは次になります。

bpy.context.view_layer.objects.active.name

これによってオブジェクト名を取得できます。

〇Unity側でMessagePackのフォーマットにオブジェクト名のデータを追加する

今回はMessagePackを使用してJson形式のようなデータでデータを格納、シリアライズ化して送信しています。

この時シリアライズ、デシリアライズにおいてフォーマットがBlender及びUnityで正しく一致している必要があります。

この辺りの処理については過去の記事を参考にしてください。

redhologerbera.hatenablog.com

これまでは頂点、メッシュのインデックス、法線の3つのデータを送信していたためフォーマットは次のようになっていました。

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

メッシュデータとともにオブジェクト名を取得するには次のようにobjectnameを追加します。

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

この改修によって4つのデータを扱うことになるためデータのシリアライズ、デシリアライズに関しても回収します。

public void Serialize(ref MessagePackWriter writer, MeshData value, MessagePackSerializerOptions options)
    {
        writer.WriteMapHeader(4);//3つではなく4つのデータに改修
        writer.Write("objectname");//objectnameのデータを追加
        options.Resolver.GetFormatterWithVerify<string>().Serialize(ref writer, value.objectname, options);
        writer.Write("vertices");
        options.Resolver.GetFormatterWithVerify<List<float>>().Serialize(ref writer, value.vertices, options);
        writer.Write("triangles");
        options.Resolver.GetFormatterWithVerify<List<int>>().Serialize(ref writer, value.triangles, options);
        writer.Write("normals");
        options.Resolver.GetFormatterWithVerify<List<float>>().Serialize(ref writer, value.normals, options);
    }

    public MeshData Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
    {
        if (reader.TryReadNil())
        {
            return null;
        }

        options.Security.DepthStep(ref reader);

        int length = reader.ReadMapHeader();
        if (length != 4)//4つのデータ形式ではない場合に変更
        {
            throw new MessagePackSerializationException("Invalid map length.");
        }

        string objectname = null;//objectnameのデータを作成
        List<float> vertices = null;
        List<int> triangles = null;
        List<float> normals = null;

        for (int i = 0; i < length; i++)
        {
            string key = reader.ReadString();
            switch (key)
            {
                case "objectname"://追加
                    objectname = options.Resolver.GetFormatterWithVerify<string>().Deserialize(ref reader, options);
                    break;
                case "vertices":
                    vertices = options.Resolver.GetFormatterWithVerify<List<float>>().Deserialize(ref reader, options);
                    break;
                case "triangles":
                    triangles = options.Resolver.GetFormatterWithVerify<List<int>>().Deserialize(ref reader, options);
                    break;
                case "normals":
                    normals = options.Resolver.GetFormatterWithVerify<List<float>>().Deserialize(ref reader, options);
                    break;
                default:
                    reader.Skip();
                    break;
            }
        }

        reader.Depth--;

        return new MeshData { objectname = objectname, vertices = vertices, triangles = triangles, normals = normals };//objectnameを追加
    }

これによってUnity側でデータのフォーマットの改修が完了しました。

Blender側でのフォーマットの改修

Unity側でフォーマットの改修が完了したため次はデータ送信に対してBlenderを改修していきます。

といっても基本的にデータを自称に登録する際のdata_dictにobjectnameを追加しているのみとなります。

def send_mesh_data_to_unity(mesh_data):
    vertices, triangles, normals = mesh_data

    # Convert numpy arrays to list
    vertices_list = np.array(vertices, dtype='<f4').flatten().tolist()
    triangles_list = np.array(triangles, dtype='<i4').flatten().tolist()
    normals_list = np.array(normals, dtype='<f4').flatten().tolist()

    # データを辞書として構築
    data_dict = {
        'objectname' : bpy.context.view_layer.objects.active.name,#追加
        'vertices': vertices_list,
        'triangles': triangles_list,
        'normals': normals_list
    }

    # MessagePackでシリアライズ
    serialized_mesh_data = msgpack.packb(data_dict)

    #print(f"Serialized data (bytes): {serialized_mesh_data.hex()}")
    #Verification
    #verification_mesh_data(serialized_mesh_data)  
    # ここでデシリアライズの確認を行う
    try:
        deserialized_data = msgpack.unpackb(serialized_mesh_data)
        print("Deserialization success!")
        #print(deserialized_data)  # もし必要ならば、デシリアライズされたデータを出力する
    except Exception as e:
        print(f"Deserialization error: {e}")
        return  # エラーが発生した場合、関数をここで終了する

    for client in server_thread.clients:
        try:
            client.sendall(serialized_mesh_data)
            #print(serialized_mesh_data)
          
        except Exception as e:
            print(f"Error while sending mesh data to client: {e}")

以上でメッシュデータに加えオブジェクト名をUnityに送信できるようになりました。