Quantcast
Channel: 気まぐれブロマガ
Viewing all articles
Browse latest Browse all 56

[Blender] PMX出力用にAスタンス化するスクリプトとPMXエクスポーター0.4.0

$
0
0

【2015/08/12追記】PMXエクスポーター0.8.0でポーズをアーマチュアのデフォルトのポーズに適用してエクスポートすることが可能になりました。したがって、拙作PMXエクスポーターを使う限り、下記のスクリプトでAスタンスの固定化をする必要はありません。


Blender上でTスタンス(腕を左右にまっすぐ伸ばした状態)の人モデルを作成した場合、これをPMXに出力するときはMMD標準ポーズとされるAスタンス(Tスタンスよりも腕をやや下げた状態)に変形する必要があるのですが、これが結構な手間です。

具体的な手順については、のののP様のブログ記事の「ポーズモードで動かした形に固定する」の項目が参考になります。

PMXに出力する度にAスタンス化の手順を繰り返すのは面倒なので、Aスタンスに変形した状態のデータを保存したくなります。が、一度Aスタンスに固定してしまうと、その後はデータの修正や再利用がやりにくくなります。Aスタンスのデータを別ファイルに保存するという方法も考えられますが、複数のファイルを管理する手間が増えます。

そこで、Aスタンス化はPMX出力の直前にスクリプトを使って一気に済ます、ということを考えました。そのためのスクリプトは次のとおりです。
# Quaternion
quats = {}

# -----------------------------------------------------#
import bpy
from mathutils import Quaternion
arm_obj = bpy.context.active_object
p_bones = arm_obj.pose.bones
for bname, quat in quats.items():
p_bones[bname].rotation_quaternion = Quaternion(quat)
bones = {x.name for x in p_bones
if x.rotation_quaternion != Quaternion((1.0, 0.0, 0.0, 0.0))}
bpy.ops.object.mode_set(mode="OBJECT")
scene_objs = bpy.context.scene.objects
objs = [(x, y.name) for x in scene_objs if x.type == "MESH" for y in x.modifiers
if y.type == "ARMATURE" and y.object == arm_obj]
stock = []
for ob, mo in objs:
if ob.data.shape_keys is not None:
continue
if len(bones & {x.name for x in ob.vertex_groups}):
scene_objs.active = ob
bpy.ops.object.modifier_apply(modifier=mo)
stock.append(ob)
scene_objs.active = arm_obj
bpy.ops.object.mode_set(mode="POSE")
bpy.ops.pose.armature_apply()
bpy.ops.object.mode_set(mode="OBJECT")
for ob in stock:
scene_objs.active = ob
bpy.ops.object.modifier_add(type="ARMATURE")
ob.modifiers[-1].object = arm_obj

このスクリプトの使い方ですが、まず、アーマチュアのポーズモードでボーンをAスタンスに変形します。そして3Dビューをポーズモードのままにして、Blenderのテキストエディターに切り替えて上記のスクリプトを実行します。スクリプトをファイルに保存しておけば、テキストエディター上で開くとテキストのリンクが生成され、リンクから簡単に再実行できるので、スクリプト実行前に.blendの保存をしておくことをおすすめします。

スクリプトの処理内容は次のようになっています。
  1. シーン内の全オブジェクトを対象に頂点グループを調べ、変形したボーンと同じ名前の頂点グループがあるオブジェクトのアーマチュアモディファイアを適用します。ただし、シェイプキーがあるオブジェクトは処理をスキップします(モディファイアを適用できないので)。
  2. アーマチュアのボーンの形状をポーズモードで変形した状態で固定します(いわゆるポーズの適用)。
  3. アーマチュアモディファイアを適用したオブジェクトに再びアーマチュアモディファイアを追加します。
ともかく、上記のスクリプトを実行した後にPMXをエクスポートすると、PMXの面とボーンもAスタンスになっているはずです。

このスクリプトはアーマチュアモディファイアを再度追加するところまでしますが、モディファイアの元の順番まで復元するものではありません。Aスタンス化したデータをあえて保存して利用する場合は、この点に留意してください。

まだ不満はあります。スクリプトを実行する前に、ボーンをAスタンスに変形する作業をしなければなりませんが、これも面倒です。一度決めたポーズは、次にスクリプトを実行する機会には、自動的に変形するようにしたいところです。

実は、上のスクリプトは、冒頭の変数quatsにAスタンス化のデータを設定すると、Aスタンスに変形する作業もやってくれます。変数にはPythonの辞書オブジェクトを設定します。Pythonのことがわからなくても、以下の具体例を見れば、なんとなく見当がつくのではないでしょうか。

■Aスタンス化した状態のボーンのトランスフォーム


Pythonの辞書は{}でくくります。その中に、ボーンの名前を""でくくり、コロン「:」に続けて、クオータニオンモードでの回転値をWXYZの順番でカンマで並べて()でくくり、さらにカンマ、これを続けます。Pythonは字下げ(インデント)に意味があるので、字下げをなくしたり、字下げ位置がバラバラにならないようにしてください。ボーンに日本語を使っていても問題ありません。Blenderのテキストエディターはutf-8でスクリプトを保存してくれます。

■ボーンのトランスフォームを変数に設定したスクリプト(冒頭部分)
# Quaternion
quats = {"shoulder.L": (1.0, -0.05, 0.0, 0.0),
"shoulder.R": (1.0, -0.05, 0.0, 0.0),
"upper_arm.L": (1.0, -0.3, 0.0, 0.0),
"upper_arm.R": (1.0, -0.3, 0.0, 0.0),
}

# -----------------------------------------------------#
import bpy
<以下略>
※具体例のモデルでは、肩と腕を下したポーズになっているため、それぞれの回転値を変数quatsに設定しています。

ここまで済ませれば、スクリプトの実行前にすることは、アーマチュアを選択してポーズモードにするだけになります。



ここからは余談です。
拙作のPMXエクスポーターに関連した話になります。

MMD用モデルを作成する場合でもAスタンスではなくTスタンスでモデリングをするというのは、拙作のPMXエクスポーターでは特に重要な意味合いがあります。

拙作のPMXエクスポーターは、7番のボーンレイヤーにボーンを配置することで、ローカル軸を設定したボーンをPMXに出力することができます。

なぜボーンのローカル軸を設定する必要があるのかというと、MMDがPMDモデルにつき腕関連の名前のついたボーンのローカル軸を、ボーンの表示先方向にX軸が、正面手前方向にZ軸が向くように自動的に調整するからです。PMXモデルもこれに準拠しないと、モデルの利用者には非常に扱いにくいモデルになってしまいます。

ローカル軸をうまく設定するには、Blender上で両腕をTスタンスにし、腕から先のボーンのローカルZ軸が、グローバルZ軸と同じ方向に向くようにする必要があります。たいていはボーンのロール値が0であればいいのですが、上半身や肩のボーンの形状によってはロール値0ではダメなときがあります。このようなときは、ロールの再計算(Ctrl+N)の「グローバル+Z軸」を実行するといいです。

■腕から先のボーンをレイヤー7に入れ、ローカルZ軸を調整した状態


Blender上でボーンのローカル軸設定を済ませておけば、出力したPMXのボーンのローカル軸も標準的なものになっているはずです。



と、ここまで書いておいてなんですが、拙作PMXエクスポーターのver0.3.0以前にはバグがあって、右腕から先のボーンのローカルZ軸が逆になっていました。これを修正したver0.4.0をお使いください(汗)。


Viewing all articles
Browse latest Browse all 56

Trending Articles