※ Blenderのバージョンは2.81aで検証しています
※ あまりに疲れているので日本語がおかしい可能性があります
※ 既存でこの機能があったらごめんなさい。
作りました。
経緯
Blenderでビックリしたのが下の状況でして……
1.0のWeightが複数ある!!!
コレどういった挙動するんだろう、と。
一応理想的なアーマチュアの動き(ちゃんときれいに曲がる)をしていたのですが
ゲームで書き出した時に果たして正常な動作をするのか疑問に思いまして……
この状況を発生させるには
上の画像のAssign機能を使うと簡単に発生します。
MAYAでも同様の機能をよく使っていたので焦りました。
「ドロー」を使用した場合は上書き扱いとなり発生しません。
個人的には最初は上の階層から下の階層の骨にかけて
段階的にウェイト1.0をかけていきたい(最初は複数頂点で制御したくない)ので
この仕様がキツイなと思いました。
例)
一番最初に全頂点をRootで1.0にして、次に腰の頂点を選択 → 腰の骨を選択して1.0にする……といった感じです。
手順
- 骨を選択します
- 複数の頂点を選択します
- ボタンを押すと選択骨に1.0のウェイトを選択頂点に設定します。
ぶっちゃけこの記事TOPのGIF画像がそれです。
コード
情報が足りなくて四苦八苦しました。
その分コードが多い……
あと途中段階の不要コードが混じってます。
import bpy import bmesh from bpy.props import * bl_info = { "name": "Set Fixed Vertex Weight", "author": "hisamu", "version": (1, 1), "blender": (2, 80, 0), "location": "", "description": "Set Fixed Vertex Weight", "warning": "", "support": "TESTING", "wiki_url": "", "tracker_url": "", "category": "Armature" } # myClass class cVertexIndexAndWeight: def __init__(self): self.index = 0 self.weight = 0.0 # class SetFixedVertexWeight_OT_Operator(bpy.types.Operator): bl_idname = "copy.button" bl_label = "Set Fixed Vertex Weight" bl_options = {'REGISTER', 'UNDO'} #--- properties ---# m_WeightValue: FloatProperty(default=1.0, options = {'HIDDEN'}) # execute button def execute(self, context): print("start") # create variable meshObject = bpy.context.edit_object bm=bmesh.from_edit_mesh(meshObject.data) selectVertexGroupIndex = meshObject.vertex_groups.active_index mulRate = 1.0 - self.m_WeightValue selectIndexes = [] vertexDic = {} # bpy.ops.object.mode_set(mode = 'EDIT') bpy.context.edit_object.update_from_editmode() # get select vertex array for vIndex , vertex in enumerate(bm.verts): if vertex.select: selectIndexes.append(vIndex) # bpy.ops.object.mode_set(mode = 'OBJECT') meshObject.vertex_groups[selectVertexGroupIndex].remove(selectIndexes) bpy.ops.object.mode_set(mode = 'EDIT') # get delete vertex group for vIndex , vertex in enumerate(meshObject.data.vertices): if vIndex in selectIndexes: for _group in vertex.groups: # new if not _group.group in vertexDic.keys(): vertexDic[_group.group] = [] # calc value weightValue = _group.weight * mulRate # if _group.group == selectVertexGroupIndex: weightValue = self.m_WeightValue if weightValue > 0: classValue = cVertexIndexAndWeight() # setup classValue.index = vIndex classValue.weight = weightValue # set vertexDic[_group.group].append(classValue) # set fixed parameter if not selectVertexGroupIndex in vertexDic.keys(): vertexDic[selectVertexGroupIndex] = [] for vIndex in selectIndexes: classValue = cVertexIndexAndWeight() classValue.index = vIndex classValue.weight = self.m_WeightValue vertexDic[selectVertexGroupIndex].append(classValue) bpy.ops.object.mode_set(mode = 'OBJECT') # delete select vertex for _group in meshObject.vertex_groups: _group.remove(selectIndexes) # apply value for gIndex , _group in enumerate(meshObject.vertex_groups): if gIndex in vertexDic.keys(): for dic in vertexDic[gIndex]: indexes = [] indexes.append(dic.index) print(str(dic.index) + ' : ' + str(dic.weight)) _group.add(indexes,dic.weight,'REPLACE') # revert mode bpy.ops.object.mode_set(mode = 'EDIT') # normalize bpy.ops.object.vertex_group_normalize() return{'FINISHED'} # panel class SetFixedVertexWeight_PT_Panel(bpy.types.Panel): bl_label = "[Addon] Set Fixed Vertex Weight" bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "Item" def draw(self, context): layout = self.layout layout.prop(context.scene, "weightValue") op_prop = layout.operator(SetFixedVertexWeight_OT_Operator.bl_idname, text = "Execute") # ボタンを作成 op_prop.m_WeightValue = context.scene.weightValue # register or unregister classes classes = ( SetFixedVertexWeight_PT_Panel, SetFixedVertexWeight_OT_Operator ) def register(): for cls in classes: bpy.utils.register_class(cls) bpy.types.Scene.weightValue = FloatProperty(default=1.0,min=0, max=1.0) def unregister(): del bpy.types.Scene.weightValue for cls in classes: bpy.utils.unregister_class(cls) if __name__ == "__main__": register()
雑感
既に設定されているウェイトデータを残しつつ割り当てる等
もう少し高度な事もできるんですが
自分がここまでしか要らないと思ったので
ここで終わりました。
何かしらバグとかがあったらまた更新していきたいと思います。