Blender Python ~オブジェクトの作成~

イントロダクション

前回は、BlenderでのPythonスクリプト画面の表示、サンプルコードの実行などを行いました。
Blenderは下のような画面で3Dモデルを作れるフリーアプリケーションです。

今回は、前回にあるメモと参考サイトを見ながら、オブジェクト(立方体や、円)の作成を行いたいと思います。

オブジェクト作成

まずは、Blenderで作品を作成するには、立方体などのオブジェクトの作成を行うと思います。
この手で行う操作を、プログラムで実行しようというところです。

使用するコマンドについて

ここでいう「コマンド」というのは、「bpy.ops.XXX」のようなスクリプトの事です。

このコマンドを実行することで、オブジェクトが作成されます。コマンドの一覧はこちら本家のサイトを見ました。

コーン(Cone)を作成する

引数に関しては、すべて使用していません。使用する引数の名前を付けて実行します。

bpy.ops.mesh.primitive_cone_add(vertices=32, end_fill_type='TRIFAN', calc_uvs=True, location=(0,0,1), rotation=(0.0, 0.0, 0.0))

具体的には「vertices=32」のように頂点=32という形で引数を渡します。

コマンドを実行すると下のように表示されます。

ここで、もう一つrotationの値を変更すると下のようになります。

実行コマンドは下のようになります。

bpy.ops.mesh.primitive_cone_add(vertices=32, end_fill_type='TRIFAN', calc_uvs=True, location=(0,0,1), rotation=(0.0, 1.0, 0.0))

X軸方向に1だけ回転しています。

同様に、locationの値を変更すれば下のようになります。

実行コマンドは下のようになります。

bpy.ops.mesh.primitive_cone_add(vertices=32, end_fill_type='TRIFAN', calc_uvs=True, location=(0,0,2), rotation=(0.0, 0.0, 0.0))
{'FINISHED'}

Z軸方向に2だけ移動しています。※もともと1移動していました。。。

連続してコーンを作成する

これに、プログラミングヨロシク、For文で縦に連続して作成してみます。
実行コードは下のようになります。

import bpy

for count in range(5):
     bpy.ops.mesh.primitive_cone_add(
        vertices=32
        , end_fill_type='TRIFAN'
        , calc_uvs=True
        , location=(0,0,count)
        , rotation=(0.0, 0.0, 0.0)
        , scale=(0.5, 0.5, 0.5))

scaleを半分にしました。つまりは「0.5」です。

次は、For文で横に連続して作成してみます。
実行コードは下のようになります。

import bpy

for count in range(5):
     bpy.ops.mesh.primitive_cone_add(
        vertices=32
        , end_fill_type='TRIFAN'
        , calc_uvs=True
, rotation=(0.0, 0.0, 0.0)
        , scale=(0.5, 0.5, 0.5))

ひと工夫してみる

  1. 横だけでなく縦にも並べる

    • ※X軸方向にも並べる処理を追加する
  2. 横人並べるた上で、それを一回転してみようというわけです。

なので、下のような出力が得られました。

実行コマンドは下のようになります。

import bpy

# change direction
for lines in range(0, 5):
    # put on line
    for count in range(0, 5):
         bpy.ops.mesh.primitive_cone_add(
            vertices=32
            , end_fill_type='NGON'
            , calc_uvs=True
            , location=(lines,count,0)
            , rotation=(0.0, 0.0, 0.0)
            , scale=(0.5, 0.5, 0.5))

ひと工夫してみる、その二

横だけでなく縦(Z軸方向)にも追加してみる

やり方は、上記のものと変わりません。ただし、X副方向ではなくZ軸方向に追加します。
実行結果

実行コマンドは下のようになります。

import bpy

# change height direction
for height in range(0,5):
    # change direction
    for lines in range(0, 5):
        # put on line
        for count in range(0, 5):
             bpy.ops.mesh.primitive_cone_add(
                vertices=32
                , end_fill_type='NGON'
                , calc_uvs=True
                , location=(lines,count,height)
                , rotation=(0.0, 0.0, 0.0)
                , scale=(0.5, 0.5, 0.5))

稀にみる3次元ループです(笑)

円状に並べてしてみる

実行結果

三角関数を使用してみました。数学嫌いだった過去が悔やまれる。。。

import bpy
import math

#for lines in range(0, 3):
for count in range(0, 11):
    rad = count * 36
    bpy.ops.mesh.primitive_cone_add(
        vertices=32
        , end_fill_type='NGON'
        , calc_uvs=True
        , location=(math.sin(rad), math.cos(rad), 0)
        , rotation=(0.0, 0.0, 0.0)
        , scale=(0.2, 0.2, 0.2))

まとめ

今回は、「コーン」で作成しましたが、これを「立方体」「モンキー(スザンヌ?)」「トーラス」と変えるだけで大して遊べると思います。

ペジェ曲線を作る(円)

、まずはサンプルコードから見ていきます。

from bpy import context, data, ops

# [1] Create a bezier circle and enter edit mode.
ops.curve.primitive_bezier_circle_add(radius=1.0,
                                      location=(0.0, 0.0, 0.0),
                                      enter_editmode=True)

# [2] Subdivide the curve by a number of cuts, giving the
# random vertex function more points to work with.
ops.curve.subdivide(number_cuts=16)

# [3] Randomize the vertices of the bezier circle.
# offset [-inf .. inf], uniform [0.0 .. 1.0],
# normal [0.0 .. 1.0], RNG seed [0 .. 10000].
ops.transform.vertex_random(offset=1.0, uniform=0.1, normal=0.0, seed=0)

# [4] Scale the curve while in edit mode.
ops.transform.resize(value=(2.0, 2.0, 3.0))

# Return to object mode.
ops.object.mode_set(mode='OBJECT')

[1]

ペジェ曲線の円を描画するbpy.ops.curve.primitive_bezier_circle_add

# Create a bezier circle and enter edit mode.
ops.curve.primitive_bezier_circle_add(radius=1.0,
                                      location=(0.0, 0.0, 0.0),
                                      enter_editmode=True)

まずはこれを作らないとはじまらない、そして、円もくねくねと曲げられるようです。
bpy.ops.curve.subdivide(number_cuts=1)

そして、これから、くねくねと曲げる処理ですが、下の部分がそれにあたります。

# Subdivide the curve by a number of cuts, giving the
# random vertex function more points to work with.
ops.curve.subdivide(number_cuts=16)

# Randomize the vertices of the bezier circle.
# offset [-inf .. inf], uniform [0.0 .. 1.0],
# normal [0.0 .. 1.0], RNG seed [0 .. 10000].
ops.transform.vertex_random(offset=1.0, uniform=0.1, normal=0.0, seed=0)

次はops.curve.subdivide(number_cuts=16)を見ていきます。

しかし、このままでは、よくわからないので、次の部分を16から8に変更します。
ちなみに、ops.transform.vertex_random(offset=1.0, uniform=0.1, normal=0.0, seed=0)の部分は
「頂点をランダム化する」処理のようです。

まとめると次のようになります。
1.4つの頂点を持つ円(ペジェ曲線)を作成: bpy.ops.curve.primitive_bezier_circle_add

  1. この4つの頂点を16回切る(細分化): bpy.ops.curve.subdivide(number_cuts=16)
    • 1回切ると頂点は4 -> 8, 2回切ると4 -> 12, 3回切ると4 -> 16
  2. これらの頂点えおランダムに移動させる: bpyops.transform.vertex_random(offset=1.0, uniform=0.1, normal=0.0, seed=0)

なので、3回切った時のオブジェクトは下のようになりました。

ペジェ曲線を作る(線)

上のコードを書き換えて実行してみます。[1]の部分を書き換えています。
ズバリprimitive_bezier_circle_add
*[primitive_bezier_curve_add](https://docs.blender.org/api/current/bpy.ops.curve.html?highlight=primitive#bpy.ops.curve.primitive_bezier_curve_add)*に書き換えるだけです

<実行したコード>

from bpy import context, data, ops

# [1] Create a bezier circle and enter edit mode.
ops.curve.primitive_bezier_curve_add(radius=1.0,
                                      location=(0.0, 0.0, 0.0),
                                      enter_editmode=True)

# [2] Subdivide the curve by a number of cuts, giving the
# random vertex function more points to work with.
ops.curve.subdivide(number_cuts=16)

# [3] Randomize the vertices of the bezier circle.
# offset [-inf .. inf], uniform [0.0 .. 1.0],
# normal [0.0 .. 1.0], RNG seed [0 .. 10000].
ops.transform.vertex_random(offset=1.0, uniform=0.1, normal=0.0, seed=0)

# [4] Scale the curve while in edit mode.
ops.transform.resize(value=(2.0, 2.0, 3.0))

# Return to object mode.
ops.object.mode_set(mode='OBJECT')

そうすると下のようなオブジェクトができました。

「なんだ、あまり変わらないではないか。。。」と感じた方、正常でございます。
自分もそう思います。

では、生成する頂点の数を減らしてみましょう。カットする回数を1回にします。

ops.curve.subdivide(number_cuts=1)

最終的な頂点の数は3つになりました。

まだまだ続きます。

でわでわ。。。

でわでわ。。。

Blender Python はじめて〜Pythonコマンド一覧

Blender Python tutorial

参考サイトはこちらです。

ショートカット一覧はこちら

Index(目次)

  1. よく使用される単語: 単語の表があります。
  2. クイックスタート: BlenderでのPythonスクリプト実行の準備とBMeshについて
  3. 円を作成する: Pythonコードと細かいPythonコマンドの説明
  4. Pythonでの描画サンプルコード
  5. ベストプラクティスで学習する
  6. Blender Python APモジュール

よく使用される単語

単語 内容
メッシュ Blenderでは、Vertex(点)、Edge(辺)、Face(面)で構成された3DオブジェクトのことをMesh(メッシュ)と呼びます。 .
ジオメトリ シェーディングポイントに関する幾何学的情報
ディゾルブ ディゾルブは、ジオメトリを削除し、周辺のジオメトリで埋めます。ジオメトリを削除するとできてしまう穴を、もう一度埋める作業の代わりに使用できます。

Pythonコマンド一覧

コマンド、内容、パラメータの順に記載していますが、パラメータは実際に入力する例として値が入っています。もちろんそのまま使用できます。

プリミティブの作成コマンド

No コマンド 内容 パラメータ(引数)
1 bpy.ops.mesh.primitive_circle_add 円メッシュを作成する 頂点= 32、半径= 1.0、fill_type = 'NOTHING' 、calc_uvs =真、enter_editmode =偽、ALIGN = 'WORLD' 、位置= (0.0、 0.0、 0.0) 、回転= (0.0、 0.0、 0.0) 、スケール= (0.0、 0.0、 0.0) )
2 bpy.ops.mesh.primitive_cone_add 円錐メッシュを作成します 頂点= 32、radius1を= 1.0、radius2 = 0.0、深さ= 2.0、end_fill_type = 'Ngonの'、calc_uvs =真、enter_editmode =偽、ALIGN = 'WORLD' 、位置= (0.0、 0.0、 0.0) 、回転= ( 0.0、 0.0、 0.0) 、規模= (0.0、 0.0、 0.0)
3 bpy.ops.mesh.primitive_cube_add 立方体メッシュを作成します サイズ= 2.0、calc_uvs =真、enter_editmode =偽、ALIGN = 'WORLD' 、位置= (0.0、 0.0、 0.0) 、回転= (0.0、 0.0、 0.0) 、規模= (0.0、 0.0、 0.0)
4 bpy.ops.mesh.primitive_cube_add_gizmo 立方体メッシュを作成します calc_uvs =真、enter_editmode =偽、ALIGN = 'WORLD' 、位置= (0.0、 0.0、 0.0) 、回転= (0.0、 0.0、 0.0) 、規模= (0.0、 0.0、 0.0) 、マトリックス= ((0.0 、 0.0、 0.0、 0.0)、 (0.0、 0.0、 0.0、 0.0)、 (0.0、 0.0、 0.0、 0.0)、 (0.0、 0.0、 0.0、 0.0)
5 bpy.ops.mesh.primitive_cylinder_add 円柱メッシュを作成します 頂点= 32、半径= 1.0、深さ= 2.0、end_fill_type = 'Ngonの'、calc_uvs =真、enter_editmode =偽、ALIGN = 'WORLD' 、位置= (0.0、 0.0、 0.0) 、回転= (0.0、 0.0、 0.0) 、規模= (0.0、 0.0、 0.0)
6 bpy.ops.mesh.primitive_grid_add グリッドメッシュを作成する x_subdivisions = 10、y_subdivisions = 10、サイズ= 2.0、calc_uvs =真、enter_editmode =偽、ALIGN = 'WORLD' 、位置= (0.0、 0.0、 0.0) 、回転= (0.0、 0.0、 0.0) 、規模= ( 0.0、 0.0、 0.0)
7 bpy.ops.mesh.primitive_ico_sphere_add Icosphereメッシュを作成します 細分= 2、半径= 1.0、calc_uvs =真、enter_editmode =偽、ALIGN = 'WORLD' 、位置= (0.0、 0.0、 0.0) 、回転= (0.0、 0.0、 0.0) 、規模= (0.0、 0.0、 0.0)
8 bpy.ops.mesh.primitive_monkey_add スザンヌメッシュを構築する サイズ= 2.0、calc_uvs =真、enter_editmode =偽、ALIGN = 'WORLD' 、位置= (0.0、 0.0、 0.0) 、回転= (0.0、 0.0、 0.0) 、規模= (0.0、 0.0、 0.0)
9 bpy.ops.mesh.primitive_plane_add 4つの頂点を持つ塗りつぶされた平面メッシュを作成します サイズ= 2.0、calc_uvs =真、enter_editmode =偽、ALIGN = 'WORLD' 、位置= (0.0、 0.0、 0.0) 、回転= (0.0、 0.0、 0.0) 、規模= (0.0、 0.0、 0.0)
10 bpy.ops.mesh.primitive_torus_add トーラスメッシュを作成します ALIGN = 'WORLD' 、位置= (0.0、 0.0、 0.0) 、回転= (0.0、 0.0、 0.0) 、major_segments = 48、minor_segments = 12、モード= 'MAJOR_MINOR' 、major_radius = 1.0、minor_radius = 0.25、abso_major_rad = 1.25、abso_minor_rad = 0.75、generate_uvs = True
11 bpy.ops.mesh.primitive_uv_sphere_add UV球メッシュを作成します セグメント= 32、ring_count = 16、半径= 1.0、calc_uvs =真、enter_editmode =偽、ALIGN = 'WORLD' 、位置= (0.0、 0.0、 0.0) 、回転= (0.0、 0.0、 0.0) 、規模= ( 0.0、 0.0、 0.0)

クイックスタート

下のような記載がありました。(日本語に翻訳)

【Blender Python APIの機能】
・ ユーザーインターフェイスで可能なデータ(シーン、メッシュ、パーティクルなど)を編集します。
・ユーザー設定、キーマップ、およびテーマを変更します。
・独自の設定でツールを実行します。
・メニュー、ヘッダー、パネルなどのユーザーインターフェイス要素を作成します。
・新しいツールを作成します。
・インタラクティブなツールを作成します。
・Blenderと統合する新しいレンダリングエンジンを作成します。
・データとそのプロパティへの変更をサブスクライブします。
・既存のBlenderデータに新しい設定を定義します。
・Pythonを使用して3Dビューポートで描画します。

始める前にやっておくと良いこと

Blender2.69使用

【設定画面を開く】
FIle -> User Preference
DeveloperExtra とPythonのツールチップを有効にします。

  • DeveloperExtra -> Blender2.69(mac版)には見つかりませんでした。。。
  • PythonTooltipsにチェックを入れる(デフォルトでチェックが入ってました)

Blender2.93使用

【スプラッシュ画面を開く】
※自動で表示されます。

ここで、言語の設定ができます。「言語」Japaneseに変更します。
そのほか、マウスのコントロールなど変更可能です。

【設定画面を開く】

インターフェース -> 表示 -> Pythonツールチップを表示

Pythonコンソールを使用する


上のキャプチャのように「default」から「Scripting」に変更します。

システムコンソールを表示する


しかしこのままだと、システムコンソールには日本語が文字ばけします。

なので、以下のようにBlenderを起動します。

Blender2.93使用


こちらも同様です。※クリックする場所が違うけど。。。

これで、pythonコードをテストするのにとても便利です。
そして、参考サイトの下の方に行くと、サンプルコードがあるので実行してみると動きがわかります。

それで物足りなければ、参考サイトの下のような部分を参照してみると良いです。

システムコンソールを開く

サンプルコード

  • Blender Python API
  • 操作オペレーションとコード(bpy.ops)
    1. オブジェクトの削除: bpy.ops.object.delete()
    2. Cubeの作成: bpy.ops.mesh.primitive_cube_add(location=(0,0,0))
      「(0,0,0)」の部分には座標が入ります。上記のは画面の中心にできます。
    3. オブジェクト選択: bpy.context.selected_objects ※配列になっている
    4. 編集モードに変換: bpy.ops.object.mode_set(mode='EDIT')
      オブジェクトモード: bpy.ops.object.mode_set(mode='OBJECT')
    5. モードの変換: bpy.ops.object.editmode_toggle(): 引数なし、編集モードとオブジェクトモードを切り替える

BMeshを使うサンプルコード

参考ページはこちらです。
bpy.bmeshモジュールは、blenderのbmeshデータへのアクセスを提供します。

BMeshとは

ジオメトリ接続データを備えたBlenderの内部メッシュ編集APIへのアクセスと、分割、分離、折りたたみ、
ディゾルブなどの編集操作へのアクセスを提供します。公開されている機能はCAPIに厳密に従っており、Blender独自のメッシュ編集ツールで使用される関数にPythonがアクセスできるようにします。

早い話が、「メッシュ」を操作するということです。

次はサンプルコードを実行してみましょう。

<サンプルコード>※参考ページにあったものです。

# This example assumes we have a mesh object selected

import bpy
import bmesh

# Get the active mesh
me = bpy.context.object.data

# Get a BMesh representation
bm = bmesh.new()   # create an empty BMesh
bm.from_mesh(me)   # fill it in from a Mesh

# Modify the BMesh, can do anything here...
for v in bm.verts:
    v.co.x += 1.0

# Finish up, write the bmesh back to the mesh
bm.to_mesh(me)
bm.free()  # free and prevent further access

Script画面を開いた状態で、下のように「新規」をクリックします。

そしたら、文字が入力できるようになるので、サンプルコードをコピペして貼り付けてみましょう。
※「コピペ」=文字を選択して「Ctrl + C」(コピー)してから「Ctrl + V」(ペースト)すること

貼り付けたら、右側にある「▶」ボタンを押してプログラムを実行します。
すると、初期表示していたCubeがX軸方向に移動します。

ちなみに、エラーメッセージなどを見るとプログラムの修正も楽です。
なので、ヘッダーメニューにある「ウィンドウ」->「システムコンソール切り替え」をクリックしてやるとよいです。

  • bmesh.types.BMesh.from_mesh: 既存のメッシュデータブロックからこのbmeshを初期化します。
    [from_mesh(メッシュ、face_normals = True、use_shape_key = False、shape_key_index = 0)]

    • パラメーター
    • mesh(Mesh)–ロードするメッシュデータ。
    • use_shape_key(boolean)–シェイプキーの場所を使用します。
    • shape_key_index(int)–使用するシェイプキーインデックス。
bm = bmesh.new()   # 空のBMeshを作成する
bm.from_mesh(me)   # 現在の編集モードから初期化する
  • bmesh.from_edit_mesh:
    me = bpy.context.object.data
    bpy.ops.object.mode_set(mode='EDIT') # エディットモードに変更
    bm = bmesh.from_edit_mesh(me)

このような形で、BMeshを取得します。そして、いろいろなコントロールを行うというわけです。

円を作成する

プログラム的には下のように処理を行うと作成することができました。

  1. データを書き込むためにプリミティブ(Cube)を作成
  2. BMeshを作成
  3. 円の作成(BMesh)
  4. 作成したBMeshをデータに書き込む -> これで画面上に表示される
  5. 作成したときにプリミティブの名前「Cube(立方体)」を変更
import bpy
import bmesh
import math
import mathutils

# 1. 立方体を作成
bpy.ops.mesh.primitive_cube_add(location=(0,0,0))
# 存在するオブジェクトのデータを取得
me = bpy.context.object.data

# 2. BMeshの作成
bm = bmesh.new()
# 3. 円の作成(BMesh)
# Add a circle XXX, should return all geometry created, not just verts.
bmesh.ops.create_circle(
    bm,
    cap_ends=False,
    radius=1.0,
    segments=8)
# 4. 作成したBMeshをデータに書き込む
bm.to_mesh(me)
bm.free()
# 5. 作成したときにプリミティブの名前「Cube(立方体)」を変更
for obj in bpy.data.objects:
    print(obj.name)
    if obj.name == 'Cube':
        print('change')
        obj.name = 'Test'

Pythonでの描画サンプルコード

ベジェ曲線のサンプルコード

. ペジェ曲線(Bezer Curv)を描く:

ops.curve.primitive_bezier_circle_add(radius=1.0,
                                      location=(0.0, 0.0, 0.0),
                                      enter_editmode=True)

参考サイト

from bpy import context, data, ops

# Create a bezier circle and enter edit mode.
ops.curve.primitive_bezier_circle_add(radius=1.0,
                                      location=(0.0, 0.0, 0.0),
                                      enter_editmode=True)

# Subdivide the curve by a number of cuts, giving the
# random vertex function more points to work with.
ops.curve.subdivide(number_cuts=16)

# Randomize the vertices of the bezier circle.
# offset [-inf .. inf], uniform [0.0 .. 1.0],
# normal [0.0 .. 1.0], RNG seed [0 .. 10000].
ops.transform.vertex_random(offset=1.0, uniform=0.1, normal=0.0, seed=0)

# Scale the curve while in edit mode.
ops.transform.resize(value=(2.0, 2.0, 3.0))

# Return to object mode.
ops.object.mode_set(mode='OBJECT')

オブジェクトの名前など一式

プログラムで、オブジェクトをコントロールするのに「名前」がわからないととても不便です。
なので、それを一覧化します。

  1. Structure
    Structure

    • Vertex: 点
    • Edge: 辺
    • Face: 面
    • Normals: 法線=何かに垂直な方向または線であり、通常は三角形またはサーフェスですが、線、曲線上の点の接線、または表面上の点の接平面を基準にすることもできます

ベストプラクティスで学習する

こちらにベストプラクティスのページがあります。

Blender Pythonはコードスタイルとして、PEP8を採用している。
大まかには下のようなところを気をつけましょう、というところでした。

  • クラス名のキャメルキャップ:MyClass
  • すべて小文字の下線で区切られたモジュール名:my_module
  • 4つのスペースのインデント(タブなし)
  • 演算子の周りのスペース:、ではありません   ◯「1 + 1」 X「1+1」
  • 明示的なインポートのみを使用します(ワイルドカードのインポートは使用しません*)
  • 1行で複数のステートメントを使用しないでください:、代わりに2行に分けてください。if val: body
  • 列挙型には一重引用符を使用し、文字列には二重引用符を使用します。
  • リストのコピーを避ける: 「新しいリストを返すよりも関数にリストを変更させる方が高速です。」

Blender Python APモジュール

  1. コンテキストアクセス(bpy.context)
  2. データアクセス
  3. メッセージパス
  4. 演算子
  5. タイプ
  6. ユーティリティ
  7. パスユーティリティ
  8. アプリケーションデータ
  9. プロパティ定義

コンテキストアクセス(bpy.context)

  • bpy.context.area
  • bpy.context.blend_data
  • bpy.types.BlendData、(読み取り専用)
  • bpy.context.collection
  • bpy.types.Collection、(読み取り専用)
  • bpy.context.engine
  • bpy.context.gizmo_group
  • bpy.types.GizmoGroup、(読み取り専用)
  • bpy.context.layer_collection
  • bpy.types.LayerCollection、(読み取り専用)
  • bpy.context.mode
    タイプ
    ['EDIT_MESH'、 'EDIT_CURVE'、 'EDIT_SURFACE'、 'EDIT_TEXT'、 'EDIT_ARMATURE'、 'EDIT_METABALL'、 'EDIT_LATTICE'、 'POSE'、 'SCULPT'、 'PAINT_WEIGHT'、 'PAINT_VERTEX'、 'PAINT_TEXTURE'の列挙型、 'PARTICLE'、 'OBJECT'、 'PAINT_GPENCIL'、 'EDIT_GPENCIL'、 'SCULPT_GPENCIL'、 'WEIGHT_GPENCIL'、 'VERTEX_GPENCIL']、デフォルト 'EDIT_MESH'、(読み取り専用)
  • bpy.context.preferences
  • bpy.types.Preferences、(読み取り専用)
  • bpy.context.region
  • bpy.types.Region、(読み取り専用)
  • bpy.context.region_data
  • bpy.types.RegionView3D、(読み取り専用)
  • bpy.context.scene
  • bpy.types.Scene、(読み取り専用)
  • bpy.context.screen
  • bpy.types.Screen、(読み取り専用)
  • bpy.context.space_data
  • bpy.types.Space、(読み取り専用)
  • bpy.context.tool_settings
  • bpy.types.ToolSettings、(読み取り専用)
  • bpy.context.view_layer
  • bpy.types.ViewLayer、(読み取り専用)
  • bpy.context.window
  • bpy.types.Window、(読み取り専用)
  • bpy.context.window_manager
  • bpy.types.WindowManager、(読み取り専用)
  • bpy.context.workspace
  • bpy.types.WorkSpace、(読み取り専用)

データアクセス(bpy.data)

Blenderの内部データへのアクセス、これはサンプルコードを参考にするようです。

import bpy

# print all objects
for obj in bpy.data.objects:
    print(obj.name)

# print all scene names in a list
print(bpy.data.scenes.keys())

# remove mesh Cube
if "Cube" in bpy.data.meshes:
    mesh = bpy.data.meshes["Cube"]
    print("removing mesh", mesh)
    bpy.data.meshes.remove(mesh)

# write images into a file next to the blend
import os
with open(os.path.splitext(bpy.data.filepath)[0] + ".txt", 'w') as fs:
    for image in bpy.data.images:
        fs.write("%s %d x %d\n" % (image.filepath, image.size[0], image.size[1]))

メッセージバス(bpy.msgbus)

BlenderデータブロックのプロパティがデータAPIを介して変更されたときに通知を受信できます。

詰まる所は、bpy.dataのオブジェクトに変更があった時、その変更されたことを受信(知ること)ができるということです。
<サンプルコード>※上記のリンク先にコードがあります。

アクティブオブジェクトの場所の変更に対するサブスクリプションの例

import bpy

# Any Python object can act as the subscription's owner.
owner = object()

subscribe_to = bpy.context.object.location

def msgbus_callback(*args):
    # This will print:
    # Something changed! (1, 2, 3)
    print("Something changed!", args)

bpy.msgbus.subscribe_rna(
    key=subscribe_to,
    owner=owner,
    args=(1, 2, 3),
    notify=msgbus_callback,
)

鍵になるのは下のコードです。
bpy.msgbus.subscribe_rna(キー、所有者、引数、通知、オプション= set())
パラメーター:

  • キー(マルチプル)–サブスクライブされているデータのタイプを表します
  • 所有者(任意のタイプ。)–このサブスクリプションのハンドル(IDで比較)。
  • オプション(文字列のセット)–
    サブスクライバーの動作を変更します。
    PERSISTENT 設定すると、IDデータを再マッピングするときにサブスクライバーが保持されます。

演算子(bpy.ops)

「演算子」と翻訳されているが、オペレーター(操作オブジェクト)と解釈した方がしっくりくるかもしれない。。。

大まかな機能としては、以下のものがあるようです。

  • 演算子の呼び出し:呼び出し元の演算子へのPythonアクセスを提供します。
       {'RUNNING_MODAL', 'CANCELLED', 'FINISHED', 'PASS_THROUGH'}{'FINISHED'}{'CANCELLED'} のみ使用可能
  • キーワードと位置引数: APIドキュメントにある順番で引数を渡す必要がある
    bpy.ops.test.operator(override_context, execution_context, undo) 1: override_context 2: execution_context 3: undo
  • コンテキストのオーバーライド(以下サンプルコード)
    # remove all objects in scene rather than the selected ones
    import bpy
    override = bpy.context.copy()
    override['selected_objects'] = list(bpy.context.scene.objects)
    bpy.ops.object.delete(override)

サブモジュール

アクション演算子 Anim演算子 アーマチュア演算子 資産オペレーター ボイド演算子
ブラシ演算子 ボタン演算子 キャッシュファイル演算子 カメラマン クリップ演算子
布演算子 収集オペレーター コンソールオペレーター 制約演算子 曲線演算子
サイクル演算子 Dpaint演算子 エドオペレーター Anim演算子のエクスポート
メッシュ演算子のエクスポート シーン演算子のエクスポート ファイル演算子 流体演算子
フォント演算子 ジオメトリ演算子 ギズモグループ演算子 Gpencil演算子 グラフ演算子
画像演算子 Anim演算子のインポート 曲線演算子のインポート メッシュ演算子のインポート シーン演算子のインポート
情報演算子 ラティス演算子 マーカー演算子 マスク演算子 マテリアルオペレーター
Mballオペレーター メッシュ演算子 Nla演算子 ノード演算子 オブジェクト演算子
アウトライナー演算子 ペイントオペレーター ペイントカーブ演算子 パレット演算子 粒子演算子
ポーズ演算子 Poselib演算子 設定演算子 Ptcache演算子 レンダリング演算子
リジッドボディ演算子 安全なエリアのオペレーター シーンオペレーター 画面演算子 スクリプト演算子
スカルプト演算子 シーケンサー演算子 サウンドオペレーター スプレッドシート演算子 表面演算子
テキスト演算子 テクスチャ演算子 変換演算子 UIオペレーター 紫外線オペレーター
View2D演算子 View3D演算子 Wm演算子 ワークスペース演算子 世界のオペレーター

現状はここまでです。

でわでわ。。。

Python Mecab〜日本語を分解してみよう〜

イントロダクション

Javaの基本がわかったら今度は何か作ってみたいのが人情。。。今回は日本語を品詞分解してくれるライブラリ「Mecab」があったのでそれを使用する方法→開発環境のセットアップ方法を記載します。

Mecab本体のダウンロード

本家のホームページ

<手段1>:ブラウザにURLの部分に「https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7cENtOXlicTFaRUE」を入力してEnterキーを押下するとダウンロードできます。(tar.gz)ファイルなのでそれを解凍します。

展開したら下の様にコマンドを叩いてインストールします。(Mac & Linux)

    • 一般的なフリーソフトウェアと同じ手順でインストールできます。
       % tar zxfv mecab-X.X.tar.gz
       % cd mecab-X.X
       % ./configure 
       % make
       % make check
       % su
       # make install
      

辞書のインストール

% tar zxfv mecab-ipadic-2.7.0-XXXX.tar.gz
% mecab-ipadic-2.7.0-XXXX
% ./configure
% make
% su
# make install

Pythonから使える様にする

ダウンロードして展開したフォルダの直下に「README」ファイルがあるのでそれを開きます。自分のところにあったのは下の様に書いてありました。

MeCab python module

$Id: README,v 1.1.1.1 2005/12/03 14:18:50 taku-ku Exp $;

1. Installation

  % python setup.py build
  % su
  # python setup.py install
  
  You can change the install directory with the --prefix option. For example:

  % python setup.py install --prefix=/tmp/pybuild/foobar
  
2. How to use?

   see 'test.py' as a sample program.

このファイルがあるディレクトリ(フォルダ)と同じ場所に「setup.py」があるのでそれを叩けばオッケ!ターミナルを開いてこのディレクトリに移動します。ターミナルの細かい使用方法に関してはこちら

python setup.py

これで完了です。

ちょっと動かして見る。「python」コマンドでpythonコマンドの入力モードに入ります。ここでコードを作成して実行できます。

$python
>>> import MeCab
>>> m = MeCab.Tagger("-Ochasen")
>>> print m.parse("大好評!ハンコック KMMEESS")
大	ダイ	大	接頭詞-名詞接続		
好評	コウヒョウ	好評	名詞-一般		
!	!	!	名詞-サ変接続		
ハンコック	ハンコック	ハンコック	名詞-一般		
KMMEESS	KMMEESS	KMMEESS	名詞-固有名詞-組織		
EOS

とりあえずこんな感じでした。

MeCab インストール〜Pythonバインディングも〜

イントロダクション

前回は、楽天APIをやりました。なんとか検索〜結果の取得まで行きました。が「デザイン」で切羽詰まったのでアプローチを変更します。

動的ブログ生成

ブログを生成する様にプログラムを作成しようと思います。手順は以下の様にやろうと思っています、※できなかったら他の方法をやります。

  1. 自分で作成したカテゴリから乱数でどれかを選択する
  2. 指定されたカテゴリをキーワードにしてTwitter検索をかける
  3. 取得したツイートから初めの10件文のデータ(つぶやき)からキーワードになる値を取得する
  4. 取得したキーワードで楽天APIから商品候補を取得〜表示

この様に考えています。そして3の部分で使用するのが「Mecab」です。京都大学情報学研究科−日本電信電話株式会社コミュニケーション科学基礎研究所 共同研究ユニットプロジェクトで作成された様です。よーしいいぞ!日本!

そしてインストールして実行した結果

品詞分解してくれます。。。そしてこいつをPHPでしようしようじゃないかというわけです。

参考にしたサイトはこちら

とりあえず調べて見るとPHPでのバインディングなありませんでした。。。つまりPHPでは使用できないというわけです。。。駄菓子菓子!PHPもPythonもすでに触っているし、厄介なのは言語のナマリくらいだしPythonの方が親しみがあるのでそのまま行きます。ちなみにPHPでPythonを使用するときは以下の様にやります。

<?php 
   $command = "python XXXX.py"
   $res = exec($command);
?>

シンプルなものです。

MeCabPythonのインストール

ここからPythonバインディングをダウンロードします。ダウンロードした中にREADMEファイルがあるのでそれをみます。自分がみたものは下の様に書いてありました。

MeCab python module

$Id: README,v 1.1.1.1 2005/12/03 14:18:50 taku-ku Exp $;

1. Installation

  % python setup.py build
  % su
  # python setup.py install
  
  You can change the install directory with the --prefix option. For example:

  % python setup.py install --prefix=/tmp/pybuild/foobar
  
2. How to use?

   see 'test.py' as a sample program.

その通りにインストールします。そしてそれをサーバー上にアップロードします。あとはPHPからPythonにアクセスするだけで良い様にします。→Pythonでその様な処理を実装するという意味です。

でわでわ。。。


Python websocket client〜WebSocket送信処理を作る〜

イントロダクション(Introduction)

今まで悪戦苦闘してきましたが、ついに糸口を見つけました。(i was struggling to websocket)

人に聞いたりしてわかったこと(i found out by ask to my friends)

  1. Python2.Xは終わるらしいのでPython3.X以上を使う方が良い
  2. レンタルサーバーでやるならJS + PHPの方が早いかも?
  3. 人間諦めも必要だ

というわけで、サーバー、表示するクライアント画面はPHPで実装(i decided to use PHP)

Microbitでのシリアルデータの受信〜Webサーバーへの送信はPython3でやることにしました。

Python3.XならWebSocketクライアントを作れるので以下を参考に作成

https://websockets.readthedocs.io/en/stable/

Python WebSocket!

自分の環境では以下のモジュールが必要でした。ので下のコマンドでインストールします。(i had to install follow ing modules)

  1. asyncio
  2. websockets

ただ、上記のサイトには

pip install websockets

の様にコマンドを実行する様に記載してあったけど(i had used following command)

pip3 install websockets

の様にPython3を指定してやる必要がありました。

いざ!実装(Implementation)

<websocketSender.py>

import asyncio
import websockets
import json

async def hello():
    async with websockets.connect("ws://zenryokuservice.com:9000/demo/server.php") as websocket:
        mes = {
            'message': 'MicrobitData',
            'name': 'WebSocket.py',
            'color': '#0B4C5F'}
        await websocket.send(mes)
        print(mes)

asyncio.get_event_loop().run_until_complete(hello())

実行結果(Results)

アクセスするURLは

http://zenryokuservice.com/project/index.php

データやキャッシュを保存していないので一度画面を閉じると何も残りません。

そして、現状ではメッセージが全部「null」になっています。

修正しなくては。。。原因は送信するJSONデータがちゃんとJSONしていない様に睨んでいます。


関連ページ一覧

お手製リクエストを飛ばす〜HTTPメッセージに関して〜

イントロダクション

Socketでリクエストを飛ばす方法を探していて見つけたのでメモ

HTTPリクエストの中身

要点1:HTTPリクエストとは?

「HTTPリクエストはクライアントが送信してサーバーにアクションを起こさせるリクエストと、サーバーの回答であるレスポンスの、2 種類のメッセージがあります。」

要点2:HTTPリクエストのデータ形式

「HTTP メッセージは ASCII でエンコードされたテキスト情報で構成されており、複数の行にまたがります。」

<HTTPメッセージ>

POST / HTTP/1.1
Host: localhost:8000
Connection: keep-alive
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36
Sec-Metadata: destination=image, site=same-origin
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Referer: http://localhost:8000/
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.9,en;q=0.8

<メソッド>

・POST / HTTP/1.1
・GET /background.png HTTP/1.0

・HEAD /test.html?query=alibaba HTTP/1.1
・OPTIONS /anypage.html HTTP/1.0

ちょっと試してみる

通常HTTPヘッダなどを直接指定することはない(だいたいアプリケーション(フレームワークなど)側でやっている)ので今まで触らなかったがヘッダ情報にオリジナルのヘッダを加えてみた。

オリジナルヘッダ追加リクエスト

>>>> Testing <<<<<
127.0.0.1 - - [13/Dec/2018 14:54:35] "GET / HTTP/1.1" 200 -
Created Header!
File CLosed!
*** POST ***
Content-Length: 16
Content-Type: text/plain
Message: Hello

「Hello」は引数で与えたもので、実際に渡す値はなんでも良い(テキストであれば)



<オリジナルヘッダを入れた場合>

*** POST ***
Content-Length: 16
Content-Type: text/plain
Message: Hello

*** BODY ***
Hello

<オリジナルヘッダを入れない場合>

*** POST ***
Content-Length: 0
Content-Type: text/plain

*** BODY ***
None

 

Python HTTPServer 〜Soket送信時のエラー対処〜

イントロダクション

PythonのSocketからHTTPServerへのデータ送信後にレスポンスを返そうとするとエラーになる、ちなみにURLにブラウザでアクセスしたときは問題なく表示する。

<エラーメッセージ>

Exception happened during processing of request from ('127.0.0.1', 50519)
  ・
  ・
self._sock.sendall(view[write_offset:write_offset+buffer_size])
error: [Errno 32] Broken pipe

<HTTPServer>

class MyMinimumServerHandler(BaseHTTPRequestHandler):
    def do_PSOT(self):
        print(self.headers)
        file_path = os.getcwd() + "/first.html"
        print("*******" + file_path + "********")
        print("*******" + self.path + "********")
        try:
            self.path = os.getcwd()
            print("File Open: " + file_path)
            #file = open(file_path)
            self.send_response(200)
            self.send_header('Content-type','text-html')
            self.end_headers()
            print("Created Header!")
            self.wfile.write("Hello")
            #self.wfile.write(file.read())
            #file.close()
            print("File CLosed!")
            return
        except  IOError:
                self.send_error(400, 'File Nout Found...')

<送信側:Socket>

def sendServer(msg):
    HOST = "localhost"
    PORT = 8000
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((HOST, PORT))
    s.send("GET / HTTP/1.1\r\n\r\n")
    s.send(msg)
    data = s.recv(1024)
    print(repr(data))
    s.close()

このエラーは、上の赤い字の部分に原因がありエンコードを指定しないといけないようでした。

解決1

self.wfile.write("Hello") → self.wfile.write(message.encode('utf-8')

※「message」は変数です。出力する文字をエンコード処理すると言うことです。

エラー2

一難去ってまた一難。。。

code 501, message Unsupported method ('POST')

上のようなエラーメッセージが出ました。

解決2

メソッドの定義ミスでした。サーバー「do_PSOT」→「do_POST」が正しい

エラー3

error: [Errno 32] Broken pipe

これはこのサイトを参照しました。が解決には至らず。。。

これは、ブラウザに返信の処理を行う場合はエラーが出ず、Socket送信した時に出るエラーなのですが、よく考えてみれば表示(出力)先がないならエラーになるよなぁ。。。

結果

レスポンスを返却する時に受けるもの(ブラウザなど)がないとエラーになる!当たり前か。。。


関連ページ一覧

Python Socket Server〜Python低水準ソケット通信〜

イントロダクション

タイトルにある「低水準」を見て「しょっぱそうな。。。」と感じた方、大外れでございます。

最近の言い方だと「ローレベルAPI」に属するAPI(クラス)で低水準(ローレベル)=細かい設定がいらないと言うことです。

その代わり、高レベルAPI(クラス)と違い、便利な機能が付いていないため自分で実装する必要があります。今回使用する「socket」に関しても同様なことが言えます。

いざSocket通信

もしかしたら「pip install socket」とコマンドを打つ必要があるかもしれません。今までに色々とインストールしたもので。。。

今回は、簡単なソケット通信を行い(実装し)ます。ソケット通信は古い技術です、細かいことはPyhonドキュメントを参照されたし。

概要

ソケットサーバーとクライアントを作成して以下のことを確認します。

  1. クライアントからデータを飛ばす
  2. サーバーで受け取ったものをコンソールに表示
  3. クライアントでレスポンスを受ける

実際に実行するときは、pythonを2つ起動するのでコンソール(ターミナル)も2つ立ち上げた状態になります。※背景にワードプレスくさいのがありますが、気にしないでください。。。

<実行結果:クライアント>

<実行結果:ソケットサーバー>


これは、Pythonだけで完結することができますが今までの経緯もあり、Microbitからの入力を受け付けてソケットサーバーへ通信しました。

  1. MicrobitでHttpリクエストを飛ばすためのメモ
  2. Microbitで遊ぶ〜ボタンを押す〜
  3. Microbitで遊ぶ〜シリアル通信をする〜
  4. Microbit Python 〜シリアル通信データを受け取る〜

<クライアントサイドのPythonコード>

import serial
import time
import socket

import socketTest

def main():
    # マイクロビットからシリアル通信を受け取る処理
    ser = serial.Serial('/dev/tty.usbmodemFA132', 115200,  timeout=3)
    ser.flushInput()
    ser.flushOutput()
    while True:
        try:
            print("Send data from Micro Bit with in 3 seconds!")
            data_raw = ser.read(10)
            if (data_raw != ""):
                print(data_raw)
                # シリアル通信で受け取ったデータをソケットサーバーへ
                sendServer(data_raw)
            else:
                print("It is Time out try one more!")

        except:
            print("Error")
        else:
            print("End Program")
            ser.close()
            break

def sendServer(msg):
    HOST = "localhost"
    PORT = 8000
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((HOST, PORT))
    s.send(msg)
    # サーバーからの返信を受け取る
    data = s.recv(1024)
    print(repr(data))
    s.close()

if __name__ == '__main__':
    # 「__name__」の値がメインの時※「__name__」にはいろんな値が入ってくる
    main()

<サーバーサイドのPythonコード>

import socket
import time

def main():
    print("Exe MySocket.py")
    server = initSocket()
    #s.connect( ( "localhost", 8000 ) )
    # ソケットサーバーの受信開始処理
    con, addr = server.accept()
    print("Got connection: ")
    print(addr)
    while True:
        #クライアントからのデータ受信
        data = con.recv(1024)
        print(data)
        if not data:
            print("there is no data...")
            break
        con.send("getMessage!: " + data)

    print("Good bye!")
    con.close()

def initSocket():
    # ソケットの初期処理
    port = 8000
    sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
    sock.bind(('', port))
    sock.listen(5)
    print("start listen...")
    return sock

if __name__ == '__main__':
    main()

あとは改造して、何をやろうかな?といった感じです。

関連ページ一覧

Python Http リクエスト メモ

イントロダクション

pythonでhttpサーバを起動出来るようだ。早速試してみるがimportに失敗する。

打開策

仕様してるpythonのバージョンにより以下の2種類のクラスを使う

  1. http.server
  2. SimpleHttpServer

2.の方は直接クラスをインポートするのに対し1.はパッケージをインポートする。

作成するサーバのルートディレクトリ(フォルダ)は作成したpyファイルのあるディレクトリになるようだ。

pythonでhttpサーバを作る方法はインターネット上に結構あるので問題なさそうだ(日本語のページがある)

あとは、画面のデザインを考える必要がある…一番の難敵だな…

インポートしたもの(Python)

pip install http.server

pip install SimpleHttpServer

python socket programming

リクエストの送信方法

上記の実装を行なったが、web socketのような処理は実現出来なかった。

リクエストに対して、ハンドルを行う「do_GET」メソッドに返信用のソケットを使用するつもりだったが同じURLに複数のソケットはバインドできない。(当然だな…)ので他の方法を考える