本日は筆者のツールMixedRealityModelingTools枠です。
現状筆者が開発しているMRMTではBlenderからメッシュを送信することができますが、単一のマテリアルにのみ対応しています。
〇マルチマテリアルのメッシュ
マテリアルはメッシュに紐づいていますが、通常一つのメッシュに対して一つのマテリアルのみが対応します。
しかし1つのオブジェクトで複数のマテリアルは使用できます。
この場合1つのつながったメッシュではなくデータ上ではマテリアルごとのメッシュが重なり合って1つのメッシュを構成することになります。
イメージとしては成形色ごとに分けられたプラモデルを考えるとわかりやすいです。

成形色=マテリアルごとに分割されたパーツを組み合わせて一つのオブジェクトになるという意味で分かりやすいと思います。
つまり、マルチマテリアルのメッシュをUnityに送信するためにはマテリアル数と同じ長さの配列を用意し、メッシュデータを対応するように格納すればよいということになります。
今回はMRMTでマルチマテリアルのオブジェクトに対応できるようにこの部分のBlender側の組み込みを行います。
〇メッシュデータの取得の仕組み
現行版MRMTのBlender側アドオンではget_mesh_dataというメソッドでメッシュデータを取得しています。
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)
uvs = []
for p in temp_mesh.polygons:
for loop_index in p.loop_indices:
uv = temp_mesh.uv_layers.active.data[loop_index].uv
uvs.extend([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)}, uvs={len(uvs)}")
return (vertices, triangles, normals ,uvs)
詳しい処理の解説は過去の記事を参照ください。
簡単に説明すると3角ポリゴンとして扱うために三角化モディファイアを一度設定後頂点、インデックス、法線、UVを取得していました。
この処理をマテリアルごとに行うために現在のマテリアルスロットを取得します。
material_slots = obj.material_slots
for material_slot in material_slots:
material_index = material_slots.find(material_slot.name)
# Set active material index
obj.active_material_index = material_index
マテリアルスロットはobj.material_slotsで取得することができます。
例えば4つのマテリアルをオブジェクトが持っていた場合は4が返されます。
for文を使用してマテリアルスロットの文処理を回すことができます。
次にデータが配列になるので各データを定義します。
# Get vertices and triangles
all_vertices = []
all_triangles = []
all_normals = []
all_uvs = []
これでマテリアルごとに処理を行い格納する準備が出来たのでそれぞれのデータを取得します。
material_slots = obj.material_slots
# Get vertices and triangles
all_vertices = []
all_triangles = []
all_normals = []
all_uvs = []
for material_slot in material_slots:
material_index = material_slots.find(material_slot.name)
# Set active material index
obj.active_material_index = material_index
# Get vertices, triangles, and uvs for the current material
vertices = [[v.co.x, v.co.y, v.co.z] for v in temp_mesh.vertices]
triangles = []
uvs = []
for p in temp_mesh.polygons:
if p.material_index == material_index:
triangles.extend(p.vertices)
for p in temp_mesh.polygons:
if p.material_index == material_index:
for loop_index in p.loop_indices:
uv = temp_mesh.uv_layers.active.data[loop_index].uv
uvs.extend([uv.x, uv.y])
normals = [[v.normal.x, v.normal.y, v.normal.z] for v in temp_mesh.vertices]
# Append data to the lists
all_vertices.append(vertices)
all_triangles.append(triangles)
all_uvs.append(uvs)
all_normals.append(normals)
これにより、マテリアルスロットの配列としてデータを取得できました。
本日は以上です。
〇コード
def get_mesh_data():
#Get activeObject
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()
material_slots = obj.material_slots
# Get vertices and triangles
all_vertices = []
all_triangles = []
all_normals = []
all_uvs = []
for material_slot in material_slots:
material_index = material_slots.find(material_slot.name)
# Set active material index
obj.active_material_index = material_index
# Get vertices, triangles, and uvs for the current material
vertices = [[v.co.x, v.co.y, v.co.z] for v in temp_mesh.vertices]
triangles = []
uvs = []
for p in temp_mesh.polygons:
if p.material_index == material_index:
triangles.extend(p.vertices)
for p in temp_mesh.polygons:
if p.material_index == material_index:
for loop_index in p.loop_indices:
uv = temp_mesh.uv_layers.active.data[loop_index].uv
uvs.extend([uv.x, uv.y])
normals = [[v.normal.x, v.normal.y, v.normal.z] for v in temp_mesh.vertices]
# Append data to the lists
all_vertices.append(vertices)
all_triangles.append(triangles)
all_uvs.append(uvs)
all_normals.append(normals)
# Remove Triangulate modifier
obj.modifiers.remove(triangulate_mod)
# Don't forget to remove the temporary mesh data
bpy.data.meshes.remove(temp_mesh)
print(f"Mesh data generated for {len(material_slots)} materials")
return all_vertices, all_triangles, all_normals, all_uvs