blender アドオン開発の勉強したログ

0.はじめに

UTAU技術部全然関係ないけど他にログ残すいいところがないのでここに書きます.許して.
成果物になるまでまだだいぶ時間がかかりそうなので,とりあえず技術検証した情報をまとめるものです.

1.ドキュメント

はじめてのBlenderアドオン開発
https://legacy.gitbook.com/book/nutti/introduction-to-add-on-development-in-blender/details
日本語チュートリアルです.
一通り開発方法掲載されています.

Dev:Py/Scripts
https://wiki.blender.org/index.php/Dev:Py/Scripts
サンプルコードがいろいろ見れます.

Blender Documentation Contents
https://docs.blender.org/api/blender_python_api_2_75a_release/
APIリファレンスがあります.

2.作りたい機能

必須機能イメージ:
1.オブジェクトAとオブジェクトBを指定の面で結合する.
2.結合に際してオブジェクトAは位置,向き,サイズを変更せず,オブジェクトBを変更する.
3.接合面の頂点数が異なる場合,オブジェクトA側の接合面を加工し頂点数をあわせる.

できたらつけたい機能イメージ:
1.自動操作の結合状態から,GUIを使ってオブジェクトBの位置,向き,サイズを調整可能にする.
2.オブジェクトA側の頂点数調整時のスムージングをGUIで設定できるようにする.

3.実装イメージ

初期条件:
1.オブジェクトA,オブジェクトBにはそれぞれ[key1]をマテリアルとする面が1つだけある.
2.オブジェクトBが選択状態,オブジェクトAがアクティブである.
3.key1面のサイズ,向き,位置は問わない.

アルゴリズム
1.オブジェクトAの接合面の中心座標と法線ベクトルを求める
2.オブジェクトBの接合面の中心座標と法線ベクトルを求める
3.オブジェクトBの中心座標がオブジェクトAの中心座標と一致するよう,オブジェクトBを移動する.
4.オブジェクトBの法線ベクトルとオブジェクトAの法線ベクトルの逆から,回転角度を求める.
5.オブジェクトBを3D回転する.
6.接合面の各頂点の接合面の中心座標からの角度を求める.
7.(オブジェクトA側の頂点数がオブジェクトB側の頂点数より少ない場合)
 オブジェクトBの頂点角度を基にオブジェクトAのエッジを分割する
8.オブジェクトB側の各頂点に近いオブジェクトA側の頂点座標をオブジェクトB側の頂点座標にあわせる.
9.(オブジェクトAの方が頂点座標が多い場合)残りのオブジェクトAの頂点座標を近傍のオブジェクトBの頂点座標に割り振る
10.同一座標にある頂点を結合する.

4.技術検証結果

現在のモードを取得
bpy.context.object.mode

モードの変更

bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='EDIT')

など

現在アクティブなオブジェクト
bpy.context.object

現在選択しているオブジェクトのindexのリストを取得
indexList=
for i in bpy.data.objects:
if i.select:
indexList.append(i)

オブジェクトにマテリアル名key1が含まれるかチェック
if "key1" in bpy.data.objects[index].select:

全ての頂点の選択解除
bpy.ops.mesh.select_all(action='DESELECT')

マテリアルkey1のマテリアルインデックスを取得
bpy.data.materials.keys().find("key1")

マテリアルインデックス0のマテリアルを含む頂点をすべて選択する
bpy.ops.object.material_slot_select(0)

現在アクティブなオブジェクトのうち選択している頂点のインデックスリストを取得
selectVerticesIndex=

for i in range(len(bpy.context.object.vertices)):
if bpy.context.object.vertices[i].select:
selectVerticesIndex.append(i)

頂点インデックス0の頂点のグローバル座標を取得
import bmesh
bm = bmesh.new()
bm.from_mesh(bpy.context.object.data)
list(bm.verts)[0].co.x #X座標
list(bm.verts)[0].co.y #Y座標
list(bm.verts)[0].co.z #Z座標
bm.free()

頂点インデックス0の頂点を(0,1,0)移動
import bmesh
bm = bmesh.new()
bm.from_mesh(bpy.context.object.data)
list(bm.verts)[0].co.x += 0#X座標
list(bm.verts)[0].co.y += 1 #Y座標
list(bm.verts)[0].co.z += 0#Z座標
bm.to_mesh(bpy.context.object.data) #オブジェクトモードじゃないと動かない
bm.free()

アクティブなオブジェクト全体を(0,1,0)移動
bpy.ops.transform.translate(value = (0,1,0))

オブジェクトのjoin
bpy.ops.object.join()

頂点の結合(editモード)
bpy.ops.mesh.merge(type='FIRST')

頂点インデックス0の頂点を選択
import bmesh
bm = bmesh.new()
bm.from_mesh(bpy.context.object.data)
list(bm.verts)[0].select_set(True)
bm.to_mesh(bpy.context.object.data) #オブジェクトモードじゃないと動かない
bm.free()