本日は昨日に引きつづき自身が開発中のパッケージMixedRealityModelingTools(仮)の機能紹介を行います。
昨日はUnity側のTCPクライアントの実装を見ていきました。
本日はBlenderから送信されたメッシュデータの処理を解説します。
〇メッシュデータのフォーマット
Blender側ではメッシュデータのフォーマットを次のように定義していました。
data_dict = { 'vertices': vertices_list, 'triangles': triangles_list, 'normals': normals_list }
これを可視化すると次のようになります。
'vertices': [1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0], 'triangles': [4, 2, 0, 2, 7, 3, 6, 5, 7, 1, 7, 5, 0, 3, 1, 4, 1, 5, 4, 6, 2, 2, 6, 7, 6, 4, 5, 1, 3, 7, 0, 2, 3, 4, 0, 1], 'normals': [0.5773503184318542, 0.5773503184318542, 0.5773503184318542, 0.5773503184318542, 0.5773503184318542, -0.5773503184318542, 0.5773503184318542, -0.5773503184318542, 0.5773503184318542, 0.5773503184318542, -0.5773503184318542, -0.5773503184318542, -0.5773503184318542, 0.5773503184318542, 0.5773503184318542, -0.5773503184318542, 0.5773503184318542, -0.5773503184318542, -0.5773503184318542, -0.5773503184318542, 0.5773503184318542, -0.5773503184318542, -0.5773503184318542, -0.5773503184318542]
このデータがバイナリとして送信されUnity側で受信します。
そのためUnity側でもバイナリをデシリアライズするうえでフォーマットの定義が必要です。
次のコードで行っています。
using MessagePack; using MessagePack.Resolvers; using MessagePack.Formatters; using MessagePack.Unity; using System.Collections.Generic; using System.Runtime.Serialization; using UnityEngine; namespace MixedRealityModelingTools.Core { [DataContract] public class MeshData { [DataMember] public List<float> vertices; [DataMember] public List<int> triangles; [DataMember] public List<float> normals; } ・・・
MeshDataクラスがデータを格納するクラスになります。
[DataContract] public class MeshData { [DataMember] public List<float> vertices; [DataMember] public List<int> triangles; [DataMember] public List<float> normals; }
[DataContract]を付けたクラスではデータコントラクトと呼ばれるクライアントとのデータの取り決めを行い通信においてデータを保証することができます。
[DataMember]の属性を付けた変数は、データ コントラクトの一部である型のメンバーを識別するものです。 これにより、データコントラクトをシリアル化できるシリアライザーが、その変数をJSONなどの形式に変換したり、逆に変換したりできます。
次にMeshDataクラスを使用してデータをデシリアライズ処理について紹介しいます。
〇MeshDataFormatter
Blenderから受け取ったバイナリデータは次のコードでデシリアライズしています。
using MessagePack; using MessagePack.Formatters; using UnityEngine; using System.Collections.Generic; using MessagePack.Resolvers; using MixedRealityModelingTools.Core; public class MeshDataFormatter : IMessagePackFormatter<MeshData> { ・・・ public MeshData Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.TryReadNil()) { return null; } options.Security.DepthStep(ref reader); int length = reader.ReadMapHeader(); if (length != 3) { throw new MessagePackSerializationException("Invalid map length."); } string objectname = null; 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 }; } } ・・・
データが頂点、メッシュのインデックス、法線の3つのデータであるかどうかをチェックしています。
int length = reader.ReadMapHeader(); if (length != 3) { throw new MessagePackSerializationException("Invalid map length."); }
ここで違う形式の場合はエラーが出るようになっています。
形式があっているかをチェックしたデータはデシリアライズされます。
最初に各データを収めるListを初期化・定義してデータの数switch文でキーワードに応じてデータを格納しています。
string objectname = null; 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; } }
以上がメッシュデータの格納クラスとデシリアライズの処理です。
これによってバイナリデータからデータが格納できるようになりました。
次回は格納したデータを使用してメッシュを構成する処理を説明します