夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

MixedRealityModelingToolsその⑩ Blenderから送信するメッシュ情報にUV情報を組み込む

本日は筆者が開発しているMixedRealityModelingTools枠です。

〇MixedRealityModelingToolsとは?

MixedRealityModelingToolsとは筆者が個人的に開発しているBlenderのソリューションで、目的としてBlenderからMixedRealityアプリケーション開発ツールと連携して、モデルのリアルタイムロードではなくリアルタイムビルドを実現します。

現在はβ版としてBlenderToUnityの開発を行っており、コア機能開発を中心に行っています。

〇UV情報を取得

今回はBlenderからメッシュを送信する際のデータにUV情報を併せて組み込みます。

メッシュの情報を送信するコア部分に関しては過去の記事を参考にしてください。

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

〇UVの取得

UVの取得の詳しい方法はこちらの記事を参考にしてください。

redhologerbera.hatenablog.com

一度全頂点を取得して、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)