Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What is going on with this article?
@KTakahiro1729

「数字->新名」の対応を元に、「Bone_L.数字」を「新名_L」に改名する(正規表現) (Python for Blender クックブック)

More than 1 year has passed since last update.

「数字->新名」の対応を元に、「Bone_L.数字」を「新名_L」に改名する(正規表現)

Pythonを使ってBlenderでできる事をまとめています。解説もあります。

はじめに
レシピ一覧

Pythonの難易度: ★★★★★

動機

左右対称のリグを作るとき、ボーンの名前に左右を表す_L_Rが付いていると便利です。
しかし、X-Axis Mirrorを有効にボーン編集をしても、Bone_[LかR].[三桁数字]というボーンが作られてしまいます。(「001」のように0埋めがされた数字も三桁数字と表現しています)
これをBone.[三桁数字]_[LかR]に名付け直せると便利ですね。
また、.001が付いているボーンはSholderに、.002ならArmのように、数字に基づいて改名してみましょう。

細かい仕様

  • 名称変更を施したいアーマチュアがオブジェクトモードでアクティブだとします。
  • アーマチュアのボーンの名称は「Bone_L.[三桁数字]Bone_R.[三桁数字]/その他」のいずれかが含まれています。この内、.[三桁数字]は省略されている時もありますが.000と同じとみなします。
  • ["Sholder", "Arm", ...]のような、新しいボーンの名称がリストの形式で定義されています。(以下、name
  • Bone_L.i[nameのi番目の要素]_Lに、Bone_R.i[nameのi番目の要素]_Rに改名してください。ただし、len(name) <= iiに関してはBone.i_Lのようにして下さい。
  • _L_Rの一方しかない場合も、改名してください。
  • その他のボーンは名前を変えないでください。

サンプルコード

name = ['Sholder', 'Arm', 'Hand', 'Finger']

import re
pattern = re.compile(r"Bone_(?P<lr>L|R)($|\.(?P<count>\d{3}))")

import bpy
obj = bpy.context.active_object
if obj.type != "ARMATURE":
  raise Exception("active object is not an armature")
bones = obj.data.bones
for bone in bones:
  match = re.match(pattern, bone.name)
  if match is None:
    continue
  bone_lr = match.groupdict()["lr"]
  if match.groupdict()["count"]:
    bone_count = int(match.groupdict()["count"])
  else:
    bone_count = 0
  if bone_count < len(name):
    trunk = name[bone_count]
  else:
    trunk = "Bone.{0:3d}".format(bone_count)
  bone.name = "{0}_{1}".format(trunk, bone_lr)

上記サンプルコードを、Blender内蔵のテキストエディタに貼り付けた後、Alt-Pを実行してください。

解説

正規表現

文字列があるパターン(aから始まるとか)に一致しているかを調べる方法に正規表現というのがあります。
詳細はググって欲しいですが、a+b*のように普通の文字に特殊文字を混ぜることでパターンを定義します。
たとえば、a+b*というのは「aを1個以上のあとbを0個以上含むパターン」を指します。
そのため、aaaabbb,a,aba+b*という正規表現に一致しますし、cbは一致しません。

今回、Bone_(L|R)(^|\.\d{3})という正規表現にマッチしています。(?P<lr>などは後で説明するので一旦無視してください)
Bone_(L|R)(^|\.\d{3})はどのようなパターンを指すのでしょうか?
(L|R)は「LRのどちらか」というパターンを指します。つまり、Bone_(L|R)というパターンはBone_LBone_Rのどちらかが一致します。
同様に、$は「文字列の終端」を、\.は「.という文字1」を、\dは「0~9の数字のどれか一文字」を、{3}というのは「直前の文字3文字」を指します。
したがって、Bone_(L|R)($|\.\d{3})というのは「BoneのあとにLかRがあって、そこで文字列が終了するか、.とそのあと数字を3文字」というのを指します。まさにBone_L.001などが一致しますね。

正規表現をpythonで使うにはreという標準モジュールを使います。

まず、pattern = re.compile(正規表現)で正規表現をコンパイルします。あまり気にしないでください。
match = re.match(pattern,文字列)を実行すると、matchには専用のオブジェクト(一致した場合)かNone(一致しなかった場合)が代入されます。

ここで、先ほど飛ばした?P<lr>を説明します。
これは、match.groupdict()と一緒に使うことで「一致した文字列を後から辞書型で取得」できます。

例えば、文字列がBone_L.001だった場合を考えてみましょう。
すると、match.groupdict()["lr"]Lです。
このように?P<キー>パターンを指定すると、パターンに一致した文字列を後から辞書型で取得できます。

bpy.context.active_object

PythonからBlenderを使うにはbpyというライブラリを使います。
例えば、bpy.dataにはBlender内の様々な変数(オブジェクトのインスタンス)が、bpy.contextにはBlenderの現在の状態(選択中のオブジェクトなど)が格納されています。
選択中のオブジェクトを取得するにはbpy.context.selected_objectsが使えます。

今回はアクティブなオブジェクト(最後に選択したオブジェクト)が対象なので、bpy.context.active_objectを使用します。


  1. .というのは「なにか一文字」を指します。 

1
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
KTakahiro1729
素人ゆえ自由

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
1
Help us understand the problem. What is going on with this article?