夜風のMixedReality

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

BlenderPythonでマテリアルごとの頂点情報を取得する

本日はBlenderPython枠です。

今回はメッシュの構造を理解するためにBlenderスクリプトで1つのオブジェクトの持つマテリアルごとのメッシュの情報を取得していきます。

今回は以下の人体のモデルをサンプルにBlender3.5の環境で実行しています。

〇コード

まずは選択中のオブジェクトのマテリアルごとの頂点を検出します。

import bpy

def get_total_vertex_count(obj):
    # メッシュデータの取得
    mesh = obj.data
    
    # 総頂点数
    total_vertex_count = len(mesh.vertices)
    
    return total_vertex_count

def get_vertex_count_by_material(obj):
    # メッシュデータの取得
    mesh = obj.data
    
    # 選択中のオブジェクトの各マテリアルごとに頂点を格納するセット
    vertex_set_by_material = {}
    
    # メッシュの各ポリゴンごとに処理
    for poly in mesh.polygons:
        # ポリゴンのマテリアル
        material_index = poly.material_index
        
        # マテリアルごとの頂点をセットに追加
        vertex_set_by_material.setdefault(material_index, set()).update(poly.vertices)
    
    # マテリアルごとの頂点数を取得
    vertex_count_by_material = {material_index: len(vertex_set) for material_index, vertex_set in vertex_set_by_material.items()}
    
    return vertex_count_by_material

# 選択中のオブジェクトを取得
selected_objects = bpy.context.selected_objects

# 選択中の各オブジェクトに対して処理
for obj in selected_objects:
    # オブジェクトの種類がメッシュであるか確認
    if obj.type == 'MESH':
        # 総頂点数を取得
        total_vertex_count = get_total_vertex_count(obj)
        
        # 各マテリアルごとの頂点数を取得
        vertex_count_by_material = get_vertex_count_by_material(obj)
        
        # 結果を出力
        print(f"Object: {obj.name}")
        print(f"Total Vertex Count: {total_vertex_count}")
        for material_index, vertex_count in vertex_count_by_material.items():
            print(f"Material {material_index}: {vertex_count} vertices")
    else:
        print(f"Object {obj.name} is not a mesh.")

こちらのコードを実行するとマテリアル名とそのマテリアルが持つオブジェクトの頂点数が表示されます。

上記コードではすべてのポリゴンに対してマテリアルごとに頂点数を格納するようにしています。

〇マテリアルごとの頂点のトランスフォームを取得

次に頂点の持つトランスフォーム(位置情報)および法線の情報を求めていきます。

コードは次のようになります。

import bpy
import mathutils

def get_total_vertex_count(obj):
    # メッシュデータの取得
    mesh = obj.data
    
    # 総頂点数
    total_vertex_count = len(mesh.vertices)
    
    return total_vertex_count

def get_vertex_transforms(obj):
    # オブジェクトのワールド行列を取得
    world_matrix = obj.matrix_world
    
    # メッシュデータの取得
    mesh = obj.data
    
    # 各頂点のトランスフォームを格納する辞書
    vertex_transforms = {}
    
    # メッシュの各頂点ごとに処理
    for vertex in mesh.vertices:
        # 頂点の座標
        vertex_co = world_matrix @ vertex.co  # 変更点!
        
        # 頂点の法線
        vertex_normal = world_matrix @ vertex.normal  # 変更点!
        
        # 頂点ごとのトランスフォームを辞書に格納
        vertex_transforms[vertex.index] = {
            'co': vertex_co,
            'normal': vertex_normal
        }
    
    return vertex_transforms

def get_vertex_count_by_material(obj):
    # メッシュデータの取得
    mesh = obj.data
    
    # 選択中のオブジェクトの各マテリアルごとに頂点を格納するセット
    vertex_set_by_material = {}
    
    # メッシュの各ポリゴンごとに処理
    for poly in mesh.polygons:
        # ポリゴンのマテリアル
        material_index = poly.material_index
        
        # マテリアルごとの頂点をセットに追加
        vertex_set_by_material.setdefault(material_index, set()).update(poly.vertices)
    
    # マテリアルごとの頂点数を取得
    vertex_count_by_material = {material_index: len(vertex_set) for material_index, vertex_set in vertex_set_by_material.items()}
    
    return vertex_count_by_material

# 選択中のオブジェクトを取得
selected_objects = bpy.context.selected_objects

# 選択中の各オブジェクトに対して処理
for obj in selected_objects:
    # オブジェクトの種類がメッシュであるか確認
    if obj.type == 'MESH':
        # 総頂点数を取得
        total_vertex_count = get_total_vertex_count(obj)
        
        # 各頂点のトランスフォームを取得
        vertex_transforms = get_vertex_transforms(obj)
        
        # 各マテリアルごとの頂点数を取得
        vertex_count_by_material = get_vertex_count_by_material(obj)
        
        # 結果を出力
        print(f"Object: {obj.name}")
        print(f"Total Vertex Count: {total_vertex_count}")
        
        # 各頂点のトランスフォームを表示
        print("Vertex Transforms:")
        for vertex_index, transform in vertex_transforms.items():
            print(f"Vertex {vertex_index}:")
            print(f"   Position: {transform['co']}")
            print(f"   Normal: {transform['normal']}")
        
        # 各マテリアルごとの頂点数を表示
        print("Vertex Count by Material:")
        for material_index, vertex_count in vertex_count_by_material.items():
            print(f"Material {material_index}: {vertex_count} vertices")
    else:
        print(f"Object {obj.name} is not a mesh.")

このコードを実行すると頂点ごとに位置情報と法線情報(向き)が出力されます。

本日は以上です。