前回、リギングがひとまず終わりまして、微調整し終わったらテクスチャ描き&2.9への移行へイクゾ―…と、思ったのですが。
私は左半分のみのモデルを作ってひたすらモデリング&リギングし、仕上げ工程で左右化しています(左右化)。
…が、ふと思った訳ですよ。左右化した後で問題が見つかったらどうするのか?と。
最後に片面で編集していたファイルまで戻ってやり直すというのが素直な手だとは思うのですが、流石に面倒過ぎる。
というわけで、左右化したオブジェクトを左片面に戻すスクリプトを書いてみた…のですが、流石に難産でした。
自分でも思い出せる気がしないので、コードを掲載すると共に解説します。
尚、2.7 2.8の両方で動作を確認していますが、2.8以降の collection の概念が入っていないので、後々不具合が出るかもしれません。
これらが
こうなるコード
# half cut
import bpy
import bmesh
if bpy.context.mode == 'OBJECT':
for obj_arm in bpy.context.selected_objects:
if obj_arm.type != 'ARMATURE':
continue
print(obj_arm.name)
# all object loop
for obj in bpy.data.objects:
if obj.type != 'MESH':
continue
# vg use check
bEfected = False
for modifier in obj.modifiers:
if modifier.type != 'ARMATURE':
continue
if not(modifier.use_vertex_groups):
continue
if obj_arm.name != modifier.object.name:
continue
bEfected = True
break
if not(bEfected):
continue
# remove right vg
for vg in obj.vertex_groups:
name = vg.name
if name[len(name)-2:] == '.R':
obj.vertex_groups.remove(vg)
# reset seams
for vertex in obj.data.vertices:
if vertex.co.x == 0:
for group in vertex.groups:
vg = obj.vertex_groups[group.group]
name = vg.name
if name[len(name)-2:] == '.L':
weight = vg.weight(vertex.index)
vg.add([vertex.index],weight*2,'REPLACE')
# remove vertex
me = obj.data
bm = bmesh.new()
bm.from_mesh(me)
for v in bm.verts:
if v.co.x < 0:
bm.verts.remove(v)
bm.to_mesh(me)
bm.free()
# remove right side bone & rename left side bone
bpy.ops.object.mode_set(mode='EDIT')
arm = obj_arm.data
for bone in arm.bones:
name = bone.name
if name[len(name)-2:] == '.R':
remove_bone = arm.edit_bones[name]
arm.edit_bones.remove(remove_bone)
elif name[len(name)-2:] == '.L':
bone.name = name[0:len(name)-2]
bpy.ops.object.mode_set(mode='OBJECT')
使用方法は「リギングに使用したアーマチュアをオブジェクトモードで選択して」実行。
まずしょっぱなですが、アーマチュアの検索ループが入ります。
当初、リギングされたメッシュオブジェクト主体で作っていたのですが、1アーマチュアに複数オブジェクトという可能性がある訳ですよ。
これまで体だけ作ってきましたが、コレに服などを着せる場合、別オブジェクトで作る可能性があるわけですからね。
- all object loop
と、いうわけで、アーマチュア選択ループの中に全オブジェクト検索ループが入ります。
ひとまずメッシュオブジェクト以外は省きます。
- vg use check
リギングを行ったメッシュオブジェクトか?の判別です。
使用モディファイアの内、アーマチュア属性のものを拾います。
その後、頂点グループを使用しているか?影響を与えているアーマチュアの名前が一致するか?を判定していきます。
- remove right vg
「右側」を意味する、語尾が .R の頂点グループをひたすら削除します。
- reset seams
ミラーモディファイアで左右化したモデルは合わせ目で左右の頂点グループの影響度(~.R ~.L に左右化した頂点グループ)を半々で受けます。
右側の影響度に関しては、一つ前の処理で右側の頂点グループそのものを削除したので影響度は無いのですが、左側は倍にセットし直す必要があります。
…のですが、コレは大ハマりしました。
当初頂点グループの影響度はこんな感じのパラメータだと思っていたんですよね。
が、実際はこんな感じ。
…頂点グループの方が主体。
最初はなんでこんな面倒くさい事になってるんだと思いましたけど、冷静に考えてみると判りますね。
頂点は物体を示す最小単位な訳です、当然、立体に関わるパラメータは全て頂点にも紐づけられます。
私でも判る範囲で考えるなら、テクスチャUV、頂点法線、頂点カラー…
当初の私の予想通りだと、機能追加する度に頂点の処理を追加していく事になって頂点処理担当が忙殺される事は間違いないです。
なので、追加した機能の方で極力完結する後者のような設計になったんでしょうね。…で、そっちの設計思想は理解するのですが、もう一つ
vg.add([vertex.index],weight*2,'REPLACE')
…コレは酷い
これは頂点に対する加重値を2倍にしているのですが…
値の変更の関数は普通 set だろうに、なぜ add 関数にパラメータで REPLACE にしておけばおkとか言ういい加減な作りにしたのか。
なんでこんな不可解なネーミングを許したのかまったく理解できませんでした。
- remove vertex
オブジェクトから右側の頂点を全削除する処理なのですが…
一つ前の処理で
for vertex in obj.data.vertices:
と書いており、obj.data.vertices の中から右側の頂点だけ削除すれば良いじゃないかと当初は思っていました。
が、コレは動作しません。
obj.data の内容を一旦 BMesh に書き写してから BMesh 上で右側の頂点を削除して書き戻す必要があります。
正直、どうしてこんな処理になっているのかは解りませんが、作法だと思う事にしました。
- remove right side bone & rename left side bone
最後は右サイドのボーンを削除し、左サイドのボーンをリネーム(~.L から .L の無い名前に変更)する処理。
特筆する部分もあまり無いのですが、ボーンの削除は編集モードでないとできない為、処理の最初に編集モードにセットし、最後にオブジェクトモードに戻しています。
尚、左側のボーンを変名した為、関連して頂点グループ名の ~.L だったものも変名されます。
この為、ボーン変名の前に影響を受ける全メッシュオブジェクトの処理を終えておく必要があります。
いや、難産でしたし、どうしてこんなに面倒くさい作りになってるんだろう?と何度も悩みましたが…
最初にスクリプトを書いたときはコードを書いていて吐き気がする程でしたが、今回は設計思想や開発陣の配置など内部的な事が薄っすら見えてそれなりに楽しめました。
次のステップへの弾みになると良いのですが。
0 件のコメント:
コメントを投稿