オブジェクトをサクッと円形状に複数コピーしたい

Blenderでは「メッシュオブジェクトを円形状にコピーする」にはやや手間がかかります。一般的にはこんな感じ。

  1. オブジェクトを配置
  2. EDITモードへ
  3. 移動
  4. OBJECTモードへ
  5. 回転軸に対して任意の角度をつける
  6. Emptyオブジェクトを回転軸の中心に配置
  7. Arrayモディファイアを追加
  8. Object OffsetにEmptyを指定
  9. Countを設定

(↑Blenderを使ったことのある方には伝わるはず)

他にもCurveに沿わせてArrayモディファイアを適用するなんて方法もありますね。いずれにせよ手間がかかります。

なので、その手のアドオンがあります。

ありがたいことに、世の中にはこういうのを開発してくださっている方がたくさんいます。絵作りに集中するなら利用すればOKです。

でもね、「どーせなら自分で作ってみたいじゃん?」と思っちゃった(笑)

やりたいことはFast Carveでいう「Circle Array」の機能そのもの。

  • サイドバーに専用のPanelを作る。項目は以下。
    • 対象オブジェクト
    • 複製する中心の半径
    • 複製する個数
    • 実行ボタン
  • Panelに指定された情報をもとにArrayする。

Blender 2.8になって、Classの命名規則ができたりAPIの変更もあったりと、多くの変更点があるようです。

そこでアドオンを作る前段として、「単に円形状にコピーする」ためのPythonスクリプトを組みました。

ソースコード

(ここをクリックすると見えます)
'''
選択したオブジェクトを円形にArrayするスクリプト(30度毎、計12個複製)
'''
import bpy


# Add-on化の際、パネルから指定する予定のデータ(仮設定)
LOCATION = -5
COUNT = 12  # Array数
ROTATION_AXIS = 0  # 0:X軸/1:Y軸/2:Z軸
ANGLE = -0.523599  # 30度


def trans_object():
    try:
        # Array化するオブジェクトのコンテクストを取得する(=選択しているオブジェクト)
        ob = bpy.context.object
        if ob.select_get():
            # 移動と回転
            bpy.ops.object.mode_set(mode='EDIT')
            bpy.ops.transform.translate(
                value=(0, 0, LOCATION),
                orient_type='GLOBAL',
                orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)),
                orient_matrix_type='GLOBAL',
                constraint_axis=(False, False, True),
                mirror=True, proportional='DISABLED',
                proportional_edit_falloff='SMOOTH',
                proportional_size=1
            )
            # X軸に回転
            ob.rotation_euler[ROTATION_AXIS] = ANGLE
            bpy.ops.object.mode_set(mode='OBJECT')
        else:
            print("Plese target object")
    except AttributeError:
        print("Plese target object")


def add_array_modifier():
    # Array化するオブジェクト名を取得する(=選択しているオブジェクト)
    ob = bpy.context.object
    target_obj_name = ob.name

    # カーソル位置(原点)に配置したEmptyを起点にArray化するためのEmptyオブジェクト
    bpy.ops.object.empty_add(
        type='PLAIN_AXES',
        view_align=False,
        location=(0, 0, 0)
    )

    # Array化対象のオブジェクトをアクティブにする
    bpy.data.objects['Empty'].select_set(False)
    bpy.context.view_layer.objects.active = bpy.data.objects[target_obj_name]
    bpy.data.objects[target_obj_name].select_set(True)

    # Arrayモディファイアを追加する
    bpy.ops.object.modifier_add(type='ARRAY')
    bpy.context.object.modifiers['Array'].use_relative_offset = False
    bpy.context.object.modifiers['Array'].use_object_offset = True
    bpy.context.object.modifiers['Array'].offset_object = bpy.data.objects['Empty']
    bpy.context.object.modifiers['Array'].count = COUNT


if __name__ == "__main__":
    trans_object()
    add_array_modifier()

※エラー処理は組めてません

動作画面

苦労したところ

オブジェクトをアクティブにする方法がわからなかった

円形状に複製するためには、複製元のオブジェクトが回転軸となるEmptyオブジェクトを指定することで機能します。

しかし、Emptyの配置後は「Emptyが選択された状態(アクティブ)」になっていて、複製元のオブジェクトをアクティブにする方法がわかりませんでした。

解決策はソースコードの53行目。

bpy.data.objects['Empty'].select_set(False)
bpy.context.view_layer.objects.active = bpy.data.objects[target_obj_name]
bpy.data.objects[target_obj_name].select_set(True)
  1. Emptyの選択状態をOFF
  2. 複製元のオブジェクトをアクティブ
  3. 複製元のオブジェクトの選択状態をON

とすればOK。

アドオン化のためのToDo

(1)Emptyオブジェクトを追加する際、任意の名前を指定する方法

単純にAddするだけだと「Empty」という名前になってしまいます。アドオン化の際には任意のオブジェクト名にした方が衝突も起こりにくい。けど、任意のオブジェクト名にする方法がわかりませんでした。

(2)3D VIEWのSlidebarにPanelを作る方法

(3)そもそもアドオンを作るためのルールを知る(笑)

おわりに

sc_20190420-2

Blenderでツールチップを表示してAPIを確認したり、本家リファレンスや英語サイトのQ&Aを見ながら「こんなのやりたいぞ」まで形にできました。

楽しかった!

標準機能を使って絵を作ることも楽しいけど、拡張機能を自分でも作れるUDEが欲しいので日々精進あるのみ。

僕はPhotographerとしてだけでなく、Creator、Engineerの3本柱で楽しく行きたいからね。楽しみながらやっていきます。

参考サイト

この記事を書いた人

花村貴史|Takashi Hanamura

◆Photographer|FUJIFILM, Nikon, RICOH, SIGMA|写真でやさしい世界を伝えてゆく
◆Software Engineer|スキ:Go/C,C++/WebGL|オシゴト:SAP Analytics Cloud

写真素材note発売中

継続課金マガジンで販売しています。ブログに載せるもOK、壁紙に設定するもOK、使い方は自由です。フリー素材も良いけれど、人と被りたくないという方に人気です。

人物写真|Photo Session

お話しながらのポートレイト撮影です。「今」そして「これから」のあなたにフォーカスして撮影します。SNSやサイト用のプロフィール写真に。

イベント写真|Photo Shooting

「友達と楽しんでいる」「セミナーで講演している」「パーティーを主催している」など、皆さんが大切な時間を過ごしている瞬間をスナップします。