MRが楽しい

MRやVRについて学習したことを書き残す

Blenderで利用可能なpythonスクリプトを作る その29(ポーズの変更とメッシュへの反映)

本日は Blender の技術調査枠です。
Blenderで利用可能なpythonスクリプトを作ります。
bluebirdofoz.hatenablog.com

ポーズの変更

対象アーマチュアの特定ボーンを回転させます。
ボーンの回転はポーズモードで行われます。
change_pose_bone.py

# bpyインポート
import bpy
# mathインポート(角度計算のため)
import math

# 対称ボーンのポーズ角度を変更する
# 引数   arg_targetarmature:対象アーマチュア名
#        arg_targetbone:対象ボーン名
# 戻り値
def change_pose_bone(
  arg_targetarmature='Default',arg_targetbone='Default',arg_rotation=(0,0,0)):
  # 他のオブジェクトに操作を適用しないよう全てのオブジェクトを走査する
  for ob in bpy.context.scene.objects:
    # 非選択状態に設定する
    ob.select=False
  # 指定オブジェクトを取得する
  selectob=bpy.context.scene.objects[arg_targetarmature]
  # オブジェクトをアクティブにする
  bpy.context.scene.objects.active=selectob
  # 対象オブジェクトを選択状態に変更する
  selectob.select=True
  # オブジェクトがアーマチュアなら編集対象とする
  if selectob.type == 'ARMATURE':
    # ポーズモードに移行する
    bpy.ops.object.mode_set(mode='POSE')
    # 他のボーンに操作を適用しないよう全てのボーンを走査する
    for bone in selectob.data.bones:
      # 非選択状態に設定する
      bone.select=False
    # 指定ボーンを取得する
    selectbone=selectob.data.bones[arg_targetbone]
    # 対象ボーンを選択状態に変更する
    selectbone.select=True
    # 今回はポーズ変更なのでポーズ情報を取得する
    pose_bone=selectob.pose.bones[arg_targetbone]
    # 角度の変更方法を「XYZ オイラー角」に変更する
    pose_bone.rotation_mode='XYZ'
    # X軸の変更角度を設定する
    pose_bone.rotation_euler.rotate_axis('X', math.radians(arg_rotation[0]))
    # Y軸の変更角度を設定する
    pose_bone.rotation_euler.rotate_axis('Y', math.radians(arg_rotation[1]))
    # Z軸の変更角度を設定する
    pose_bone.rotation_euler.rotate_axis('Z', math.radians(arg_rotation[2]))
    # 角度の変更方法を「クォータニオン」に変更する
    pose_bone.rotation_mode='QUATERNION'
    # オブジェクトモードに移行する
    bpy.ops.object.mode_set(mode='OBJECT')
  return

# 関数の実行例
change_pose_bone(
  arg_targetarmature='metarig',arg_targetbone='chin',
  arg_rotation=(15.0,0.0,0.0))

f:id:bluebirdofoz:20190802093534j:plain
f:id:bluebirdofoz:20190802093545j:plain

ポーズのメッシュへの反映

現在のポーズをアーマチュアモディファイアを適用する事によってメッシュへ反映します。
この際、アーマチュアモディファイアを複製して適用し、その後、デフォルトポーズを反映します。
このため、メッシュへの反映後もオブジェクトにアーマチュアモディファイアが残ります。
apply_pose.py

# bpyインポート
import bpy

# 対称のアーマチュアモディファイアを複製して適用する
# 引数   arg_targetobject:対象オブジェクト名
# 戻り値
def copyaplly_modifier_object(arg_targetobject='Default'):
  # 指定オブジェクトを取得する
  selectob = bpy.data.objects[arg_targetobject]
  # 変更オブジェクトをアクティブに変更する
  bpy.context.scene.objects.active = selectob
  # オブジェクトの全てモディファイアを走査する
  # モディファイアのタイプ一覧
  # (https://docs.blender.org/api/blender_python_api_2_71_release/bpy.types.Modifier.html)
  # オブジェクトに設定中のモディファイア数を取得する
  modifier_num = len(selectob.modifiers)
  # 走査中のモディファイア位置を記録する(先頭から開始)
  check_num = 0
  # 全てのモディファイアを走査する
  while modifier_num > check_num:
    # 操作対象のモディファイアを取得する
    modifier=selectob.modifiers[check_num]
    # アーマチュアモディファイアなら処理を行う
    if modifier.type == 'ARMATURE':
      # モディファイアを複製する
      bpy.ops.object.modifier_copy(modifier=modifier.name)
      # 複製されたモディファイアの参照を取得する
      copy_modifier=selectob.modifiers[check_num + 1]
      # 複製したモディファイアを適用する
      bpy.ops.object.modifier_apply(apply_as='DATA',modifier=copy_modifier.name)
    # 走査位置を移動する
    check_num = check_num + 1
  return

# 対称のアーマチュアのポーズをデフォルトのポーズに適用する
# 引数   arg_targetarmature:対象アーマチュア名
# 戻り値
def apply_armature_object(arg_targetarmature='Default'):
  # 他のオブジェクトに操作を適用しないよう全てのオブジェクトを走査する
  for ob in bpy.context.scene.objects:
    # 非選択状態に設定する
    ob.select=False
  # 指定オブジェクトを取得する
  selectob=bpy.context.scene.objects[arg_targetarmature]
  # オブジェクトをアクティブにする
  bpy.context.scene.objects.active=selectob
  # 対象オブジェクトを選択状態に変更する
  selectob.select=True
  # オブジェクトがアーマチュアならデフォルトポーズの適用の対象とする
  if selectob.type == 'ARMATURE':
    # ポーズモードに移行する
    bpy.ops.object.mode_set(mode='POSE')
    # [デフォルトのポーズに適用]を実行
    bpy.ops.pose.armature_apply()
    # オブジェクトモードに移行する
    bpy.ops.object.mode_set(mode='OBJECT')
  return

# 関数の実行例
copyaplly_modifier_object(arg_targetobject='JointModel')
apply_armature_object(arg_targetarmature='metarig')

f:id:bluebirdofoz:20190802093602j:plain
f:id:bluebirdofoz:20190802093617j:plain