重なっている頂点のウェイトを均す

Edge Crease を利用して切り裂いているような場合や、異なるオブジェクトを結合した場合に、重なっている頂点のウェイトを均したいことがある。

均す前

均した後

スクリプト


import bpy

bpy.ops.object.mode_set(mode='OBJECT')

obj = bpy.context.active_object
vertex_groups = obj.vertex_groups

# 選択している頂点を配列に格納する
verts = []
for v in obj.data.vertices:
    if v.select and not v.hide:
        verts.append(v.index)
print(f"verts:        {verts}")

# 選択している頂点のウェイトを正規化する
def normalize_weights():
    for v in verts:
        groups = obj.data.vertices[v].groups
        if groups:
            total_weight = sum([g.weight for g in groups])
            if total_weight > 0:
                for g in groups:
                    g.weight /= total_weight
                    vertex_groups[g.group].add([v], g.weight, 'REPLACE')
normalize_weights()

# 辞書を作成する(キーが頂点インデックス、値が頂点グループとウェイト)
verts_weight = {}
for v in verts:
    for vg in vertex_groups:
        try:
            tmpstr = vg.name + ":" + str(vg.weight(v))
            
            key = str(v)
            if key in verts_weight.keys():
                verts_weight[key] = verts_weight[key] + "," + tmpstr
            else:
                verts_weight[key] = tmpstr
                    
        except RuntimeError:
            pass
print(f"verts_weight: {verts_weight}")

# 辞書を作成する(キーが座標、値が同じ座標にある頂点インデックス達)
co_verts = {}
for v1 in verts:
    v1_co = obj.data.vertices[v1].co
    v1_co_x = round(v1_co.x, 5)
    v1_co_y = round(v1_co.y, 5)
    v1_co_z = round(v1_co.z, 5)
    key = str(v1_co_x) + "," + str(v1_co_y) + "," + str(v1_co_z)
    
    for v2 in verts:
        v2_co = obj.data.vertices[v2].co
        v2_co_x = round(v2_co.x, 5)
        v2_co_y = round(v2_co.y, 5)
        v2_co_z = round(v2_co.z, 5)
        
        if v1 != v2:
            if v1_co_x == v2_co_x and \
                v1_co_y == v2_co_y and \
                v1_co_z == v2_co_z:
                        
                if key in co_verts.keys():
                    co_verts[key] = co_verts[key] + "," + str(v2)
                else:
                    co_verts[key] = str(v2)
print(f"co_verts:     {co_verts}")

# とにかく頑張る
for value in co_verts.values():
    indices = value.split(",")
    
    tempdict = {}
    for index in indices:
        try:
            temparr1 = verts_weight[index].split(",")
            for tempele in temparr1:
                temparr2 = tempele.split(":")
                key = temparr2[0]
                value = float(temparr2[1]) / len(indices)
                
                if key in tempdict.keys():
                    tempdict[key] = tempdict[key] + value
                else:
                    tempdict[key] = value
                    
        except KeyError:
            pass
    print(tempdict)
    
    # ウェイトを設定する
    for index in indices:
        for key, value in tempdict.items():
            vg = obj.vertex_groups[key]
            vg.add([int(index)], value, 'REPLACE')
            
            
normalize_weights()

bpy.ops.object.mode_set(mode='EDIT')

所感

スクリプトをもっとシンプルに出来る気がする。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です