現在BlenderとUnityを連携させるパッケージMixedRealityModelingToolを開発しています。
ここまではMessagePackを使用してBlenderで選択中のメッシュデータをUnityに送信し、Unityでデシリアライズしてメッシュを構成することまで実現しています。
今回はメッシュデータとともにオブジェクト名を送信します。
オブジェクト名をメッシュデータとともに送信することで、オブジェクトをUnity側で区別することができます。
〇Blenderでオブジェクト名を取得する
Blender側で現在選択しているオブジェクト名を取得するコードは次になります。
bpy.context.view_layer.objects.active.name
これによってオブジェクト名を取得できます。
〇Unity側でMessagePackのフォーマットにオブジェクト名のデータを追加する
今回はMessagePackを使用してJson形式のようなデータでデータを格納、シリアライズ化して送信しています。
この時シリアライズ、デシリアライズにおいてフォーマットがBlender及びUnityで正しく一致している必要があります。
この辺りの処理については過去の記事を参考にしてください。
これまでは頂点、メッシュのインデックス、法線の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に送信できるようになりました。