本日は筆者が開発しているMixedRealityModelingTools枠です。
〇MixedRealityModelingToolsとは?
MixedRealityModelingToolsとは筆者が個人的に開発しているBlenderのソリューションで、目的としてBlenderからMixedRealityアプリケーション開発ツールと連携して、モデルのリアルタイムロードではなくリアルタイムビルドを実現します。
現在はβ版としてBlenderToUnityの開発を行っており、コア機能開発を中心に行っています。
〇UV情報を取得
今回はBlenderからメッシュを送信する際のデータにUV情報を併せて組み込みます。
メッシュの情報を送信するコア部分に関しては過去の記事を参考にしてください。
〇UVの取得
UVの取得の詳しい方法はこちらの記事を参考にしてください。
一度全頂点を取得して、UVレイヤーに参照しています。
これをget_mesh_data関数で取得します。
get_mesh_data関数では3角ポリゴンに合わせるためにモディファイアを適応した後にverticesとして全頂点データを取得・格納しています。
def get_mesh_data():
obj = bpy.context.view_layer.objects.active
print(f"Active object name: {obj.name}")
# Add Triangulate modifier
triangulate_mod = obj.modifiers.new(name="Triangulate", type='TRIANGULATE')
triangulate_mod.keep_custom_normals = True
triangulate_mod.quad_method = 'BEAUTY'
triangulate_mod.ngon_method = 'BEAUTY'
# Apply modifiers and get the new mesh data
bpy.context.view_layer.update()
depsgraph = bpy.context.evaluated_depsgraph_get()
obj_eval = obj.evaluated_get(depsgraph)
temp_mesh = bpy.data.meshes.new_from_object(obj_eval)
bpy.ops.mesh.customdata_custom_splitnormals_clear()
# Get vertices and triangles ここで全頂点データを取得
vertices = [[v.co.x, v.co.y, v.co.z] for v in temp_mesh.vertices]
ここで取得した頂点データを各データの配列に代入しています。
ここに新しくUVsを追加します。
#uvについての処理
uvs = []
for loop in temp_mesh.loops:
uv = temp_mesh.uv_layers.active.data[loop.index].uv #uvレイヤーを参照する
uvs.extend([uv.x, uv.y])#追加
これでuvsにuv情報が格納されます。
〇送信するメッシュ情報にUV情報を組み込む
send_mesh_data_to_unity関数でデータを送信するメソッドは次になります。
def send_mesh_data_to_unity(mesh_data):
vertices, triangles, normals, uvs = 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()
uvs_list = np.array(uvs, dtype='<f4').flatten().tolist() #uv情報をfloatの配列に格納
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,
'uvs': uvs_list #辞書にuvsを追加
}
# serialize MessagePack
serialized_mesh_data = msgpack.packb(data_dict)
# Check Deserialization
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}")
おこなっていることはデータのフォーマットにuvsを追加し、格納しているだけです。
以上でUV情報をUnity側に送信できるようになりました。
本日は以上です。
〇メッシュを送る処理全文
import bpy
import socket
・・・
import numpy as np
・・・
#Unityにデータを送信する関数
def send_mesh_data_to_unity(mesh_data):
vertices, triangles, normals, uvs = 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()
uvs_list = np.array(uvs, dtype='<f4').flatten().tolist() #uv情報をfloatの配列に格納
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,
'uvs': uvs_list #辞書にuvsを追加
}
# serialize MessagePack
serialized_mesh_data = msgpack.packb(data_dict)
#print(f"Serialized data (bytes): {serialized_mesh_data.hex()}")
#Verification
#verification_mesh_data(serialized_mesh_data)
# Check Deserialization
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}")
#Blenderのメッシュ情報を取得
def get_mesh_data():
obj = bpy.context.view_layer.objects.active
print(f"Active object name: {obj.name}")
# Add Triangulate modifier
triangulate_mod = obj.modifiers.new(name="Triangulate", type='TRIANGULATE')
triangulate_mod.keep_custom_normals = True
triangulate_mod.quad_method = 'BEAUTY'
triangulate_mod.ngon_method = 'BEAUTY'
# Apply modifiers and get the new mesh data
bpy.context.view_layer.update()
depsgraph = bpy.context.evaluated_depsgraph_get()
obj_eval = obj.evaluated_get(depsgraph)
temp_mesh = bpy.data.meshes.new_from_object(obj_eval)
bpy.ops.mesh.customdata_custom_splitnormals_clear()
# Get vertices and triangles ここで全頂点データを取得
vertices = [[v.co.x, v.co.y, v.co.z] for v in temp_mesh.vertices]
triangles = []
for p in temp_mesh.polygons:
triangles.extend(p.vertices)
#uvについての処理
uvs = []
for loop in temp_mesh.loops:
uv = temp_mesh.uv_layers.active.data[loop.index].uv #uvレイヤーを参照する
uvs.extend([uv.x, uv.y])
#print(uv.x,uv.y)
# Remove Triangulate modifier
obj.modifiers.remove(triangulate_mod)
# Get normals
normals = [[v.normal.x, v.normal.y, v.normal.z] for v in temp_mesh.vertices]
# Don't forget to remove the temporary mesh data
bpy.data.meshes.remove(temp_mesh)
print(f"Mesh data generated: vertices={len(vertices)}, triangles={len(triangles)}, normals={len(normals)}")
return (vertices, triangles, normals ,uvs)