本日は昨日に引きつづき自身が開発中のパッケージ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;
}
}
以上がメッシュデータの格納クラスとデシリアライズの処理です。
これによってバイナリデータからデータが格納できるようになりました。
次回は格納したデータを使用してメッシュを構成する処理を説明します