本日は筆者が開発している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)