Python はモジュールによって機能を拡張することが可能なため,非常に多彩なモジュールが提供され,さまざまな目的に使用することができます.その一方で,Python 自体をアプリケーションソフトウェアに組み込むことによって,そのアプリケーションソフトウェアの機能を拡張できるようにすることも行われています.GIMP や Blender も,Python によって機能を拡張することができます.
Blender を起動します.Blender の Python スクリプトのメッセージは標準出力あるいは標準エラー出力に出力される場合があるので,今回はメニューからではなく,端末を開いて blender コマンドを実行して起動してください.

Blender の初期設定を最初に起動したときの状態に戻すBlender を使っていると,初期設定が変わってしまっていることがあります.その場合は,File メニューから Load Factory Settings を選んでください.
Blender には Python コマンドを対話モードで実行できるコンソール(端末のようなもの)やスクリプトの編集を行うことができるテキストエディタが組み込まれています.画面上部のメニューから,Blender の画面レイアウトを "Scripting" に切り替えてください.

この下側の部分が Python の対話モードのコンソールになっています.

コンソールには Blender に組み込まれた Python の情報が表示されています.この Blender の Python のバージョンは 3.2 になっています.また,bpy というモジュールが既に組み込まれています.さらにその下に ">>>" というプロンプトを表示して,Python スクリプト(プログラム)の入力を待っています.

このコンソールに Python のスクリプトを書いて [Enter] をタイプすれば,その都度実行されて,結果が出力されます.また実行した内容によっては,結果が右上のシーンに反映されます.まず,第12回と同様に,Blender に組み込まれた Python を電卓として使ってみましょう.
| Blender 内蔵の Python を対話モードで使う |
|---|
>>> 1+1[Enter]
2 |
この Python のバージョンは 3 なので,整数の割り算でも小数点以下を求めます.
| 整数の割り算は実数になる |
|---|
>>> 1/2[Enter]
0.5 |
また,文字の出力には print 文ではなく print() 関数を使います.
| 文字の出力には print() 関数を使う |
|---|
>>> print 5/3[Enter] File "<blender_console>", line 1 print 5/3 ^ SyntaxError: invalid syntax ← エラー >>> print(5/3)[Enter] 1.6666666666666667 |
Python から Blender を操作するには,bpy モジュールを使います.Blender の Python コンソールでは,起動時に import されています.また,入力の途中で Ctrl-スペース をタイプすれば,残りの部分を補完や候補の表示が行われます.
| Ctrl-スペース で候補を表示する |
|---|
>>> bpy.Ctrl-スペース app context data ops path props types utils >>> bpy.data.Ctrl-スペース actions : cameras : lamps : objects : scenes screens : worlds >>> bpy.data.screens[Enter] <bpy_collection[7], BlendDataScreens> |
この bpy.data.screens には Blender の画面レイアウトの情報が格納されています.これを list() 関数によってリスト化すれば,内容を確認することができます.
| bpy.data.screens をリスト化する |
|---|
>>> list(bpy.data.screens)[Enter]
[bpy.data.screens['Animation'], bpy.data.screens['Compositing'], bpy.data.screens['Default'],
bpy.data.screens['Game Logic'], bpy.data.screens['Scripting'], bpy.data.screens['UV Editing'],
bpy.data.screens['Video Editing']] |
従って for ~ in を使って,要素を一つずつ取り出すことができます.個々の要素の「名前」を取り出すには,要素に .name を追加します.2行目の字下げは [Tab] キーで行で行うことができます.3行目は [Enter] のみをタイプしてください.
| bpy.data.screens の要素の名前を表示する |
|---|
>>> for screen in bpy.data.screens:[Enter] ... print(screen.name)[Enter] ... [Enter] Animation Compositing Default Game Logic Scripting UV Editing Video Editing |
これは Blender の画面上部にある画面レイアウトの切り替えの内容です.
bpy.data.objects には,現在 Blender が保持するオブジェクトが格納されています.
| bpy.data.objects の内容を表示する |
|---|
>>> list(bpy.data.objects)[Enter] [bpy.data.objects['Camera'], bpy.data.objects['Cube'], bpy.data.objects['Lamp']] >>> for object in bpy.data.objects:[Enter] ... print(object.name)[Enter] ... [Enter] Camera Cube Lamp |
この時,シーンは下図のようになっています.

このシーンには左から 'Camera'(カメラ),'Cube'(立方体),それに 'Lamp'(光源)があることがわかります.それでは,この 'Cube' の位置を変更します.'Cube' の x 座標値 bpy.data.objects['Cube'].location.x に値を代入します.
| 'Cube' の位置を変更する |
|---|
>>> bpy.data.objects['Cube'].location.x = 1[Enter] |
'Cube' の位置が X 方向(手前方向)に 1(マス目一つ分)移動しました.

これで,右上に表示されているシーン中の立方体の位置が変わります.しかし,これではちょっと長いので,bpy.data.objects['Cube'] への参照を別の変数に代入しておきます.代入する変数を cube とします.
| 'Cube' のオブジェクトを cube で参照できるようにする |
|---|
>>> cube = bpy.data.objects['Cube'][Enter] |
そうすると,この変数 cube を使ってオブジェクト 'Cube' を操作することができます.
| 変数 cube を使って 'Cube' のオブジェクトを操作する |
|---|
>>> cube.location.y = 2[Enter] |
'Cube' の位置がさらに y 方向(右方向)に 2(マス目二つ分)移動しました.

タプルやリストを使って,xyz 全部を一度に指定することもできます.タプル/リストのどちらを使っても同じです.
| 変数 cube を使って 'Cube' のオブジェクトを操作する |
|---|
>>> cube.location = (-2, -1, 3)[Enter] >>> cube.location = [-2, -1, 3][Enter] |
'Cube' の中心は (-2, -1, 3) の位置になります.

回転の設定方法は複数あります.cube.ro までタイプして,直後に Ctrl-スペース をタイプしてみてください.
| cube.ro に続く候補を表示する |
|---|
>>> cube.roCtrl-スペース
>>> cube.rotation_
axis_angle
euler
mode
quaternion
>>> cube.rotation_ |
現在の回転のモードを調べます.上の状態に続けて mode とタイプして(mCtrl-スペース でも可),[Enter] をタイプしてください.
| 回転のモードを調べる |
|---|
>>> cube.rotation_mode[Enter]
'XYZ' |
'XYZ' は x 軸中心の回転角,y 軸中心の回転角,z 軸中心の回転角,すなわちオイラー (Euler) 角をそれぞれ設定するモードです.この時,角度は cube.rotation_euler に (x, y, z) あるいは [x, y, z] で設定します.また回転は x 軸中心 → y 軸中心 → z 軸中心の順に適用されます.もしこれが 'YXZ' なら,回転は y 軸中心 → x 軸中心 → z 軸中心の順に適用されます.なお,回転角の単位はラジアンなので注意してください.
| x 軸中心に 0.52 radian (約 30°)回転する |
|---|
>>> cube.rotation_euler.x = 0.52[Enter] # >>> cube.rotation_euler = (0.52, 0, 0)[Enter] # どれも同じ >>> cube.rotation_euler = [0.52, 0, 0][Enter] # |
x 軸(赤い矢印)中心に 0.52 ラジアン(約 30°)回転します.

rotation_axis_angle はオブジェクトの中心を通る軸の方向ベクトルと回転角で指定する方法です.この方法で回転を設定するには,あらかじめ rotation_mode に 'AXIS_ANGLE' を設定しておきます.
| 軸と角度を指定して回転する |
|---|
>>> cube.rotation_mode = 'AXIS_ANGLE'[Enter] >>> cube.rotation_axis_angle = [1, 1, 0, 0.3][Enter] # 軸の方向ベクトルの x, y, z 成分,回転角 >>> cube.rotation_axis_angle[3] = 0.6[Enter] # 軸はそのままにして角度だけ変更 |
(1, 1, 0) を軸に 0.6 ラジアン回転します.

Python から Blender のメニューに用意されている機能(オペレータ,bpy.ops)を呼び出して,シーンを操作することができます.まず,操作の対象となるオブジェクトを選択します.これはマウスなどを使って選択することもできますが,次のようにスクリプトで選択することも可能です.
| 'Lamp' を選択する |
|---|
>>> bpy.data.objects['Lamp'].select = True[Enter] |
既に 'Cube' が選択されていれば,これで 'Cube' と 'Lamp' が両方選択されます.

選択を解除するには select に False を代入します.
| 選択を解除する |
|---|
>>> bpy.data.objects['Lamp'].select = False[Enter] >>> cube.select = False[Enter] |
'Cube' と 'Lamp' の選択が解除されます.

選択したオブジェクトを削除できます.まず,'Cube' を選択します.それから bpy.ops.object.delete() で選択中のオブジェクト(複数可)を削除します.
| 選択したオブジェクトを削除する |
|---|
>>> cube.select = True[Enter] >>> bpy.ops.object.delete()[Enter] {'FINISHED'} |
'Cube' が削除されました.

Blender の Python スクリプトも通常のテキストエディタを使って作成できますが,Blender 自体にも Python スクリプトを作成するためのテキストエディタが装備されています.今回はこれを使います.Blender の画面の左側中央にある "New" のところをクリックしてください.

これでテキストファイルが新規作成されます.

ここにスクリプトをタイプします.日本語は入力できません.
#!BPY import bpy
通常のスクリプトでは,1行目で #! に続けてそのスクリプトを解釈するコマンドを指定しますが,Blender の Python スクリプトでは,解釈は Blender 内蔵の Python によって行われるので,この行は意味ありません.したがって,無くても問題ありませんが,第7回で解説した magic(マジックナンバー)により内容を判断できるように,一応付けておきます.また import bpy によって,Python から Blender を制御するための bpy モジュールを導入します.これは,Blender のコンソールでは自動的に導入されていますが,スクリプトファイルでは明示的に導入する必要があります.
このスクリプトを実行するには,右クリックで現れるメニューから "Run Script" を選ぶか Alt-P ([Alt] キーを押しながら P)をタイプすれば,スクリプトが実行されます.

出力はテキストエディタの上部にあるウィンドウに表示されます.エラーもここに表示されます.ただし,この部分を スクロールしないと現れない場合があります.あと,エラーの詳細が端末の方に出ていることもあります.

それでは,このスクリプトに現在のシーンからすべての 'MESH' オブジェクト(立方体や球など)および材質データを削除する処理を追加します.こうしないとこのスクリプトを繰り返し実行したときに,オブジェクトやメッシュ,材質がどんどん増えてしまいます.そこで,スクリプトの最初でシーンに既に存在しているデータを削除します.3行目以降に次の内容を追加してください.なお,この処理はこの講義を進めるために行うもので,本来は必要ありません(この講義でも,無くてもメモリが足らなくなったりとかの弊害は出ないと思いますが).
#!BPY import bpy for item in bpy.context.scene.objects: if item.type == 'MESH': bpy.context.scene.objects.unlink(item) for item in bpy.data.objects: if item.type == 'MESH': bpy.data.objects.remove(item) for item in bpy.data.meshes: bpy.data.meshes.remove(item) for item in bpy.data.materials: bpy.data.materials.remove(item)
シーンから MESH オブジェクトを削除する
- 現在のシーンに結合されているオブジェクト bpy.context.scene.objects の個々の要素 item のうち,種類 item.type が 'MESH' のものをシーンから bpy.context.scene.objects.unlink(item) によって切り離します.
- その後 bpy.data.objects の個々の要素 item のうち,同様に種類 item.type が 'MESH' のものを bpy.data.objects.remove(item) によって削除します.
- そして,それらのオブジェクトのもとのメッシュをすべて削除します.
- bpy.data.material の個々の要素 item 削除します.

これを実行すると,カメラと光源以外何もなくなってしまいます.そこで,これに球 'Isosphere' を一つ追加します.'Icosphere' は ポリゴンの集まり 'MESH' で表された球の基本形状 (Primitives) です.この球の属性は,分割レベル subdivisions = 3,半径 size = 0.5 とします.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5)
これを実行すると,球が一個現れます.

追加する球の位置を指定するには,引数 location に座標を指定します.座標は (0, 1, 0) とします.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5, location = (0, 1, 0))

もう一つ球を追加します.この球は (0, -1, 0) の位置に配置します.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5, location = (0, 1, 0))
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5, location = (0, -1, 0))
実行すると球が二個現れます.

もし同じ図形をたくさん並べたいなら,どうすればよいでしょうか?一つ一つ,手で配置するでしょうか.スクリプト(プログラム)が使えるなら,そこで繰り返しの出番です.
プログラマについてプログラマは,もしかしたら,とても面倒くさがり屋の人に向いている職業かも知れません.面倒くさがり屋だから,面倒な仕事を与えられた時に,それを楽にやるにはどうすればいいかを考えてしまいます.そして,そのままやると1時間はかかってしまう仕事に対して,それを自動化するプログラムを3時間かけて作るのが,プログラマの習性なのかもしれません.(冗談だからね)
例えば,球を下図のように5個並べるとします.球の位置の y と z はともに 0 だとします.球の番号 i は 0 ~ 4 とし,それぞれの位置の x は -2 ~ 2 にします.

一定回数の繰り返しは for ~ in と(Python のバージョン 3 では xrange() ではなく)range() を使って,次のように書くことができます.
for i in range(5):
# ここに繰り返す内容を書く
したがって,ここでシーンに図形(球)を追加する処理を行えば,シーンに複数の球を追加することができます.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
for i in range(5):
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5)
しかし,このままではすべての球が原点 (0, 0, 0) に重なって配置されてしまいます.球ごとに異なる位置に配置するためには,繰り返しごとに異なる位置を指定する必要があります.
反復子 (iterator) の range(5) は [0, 1, 2, 3, 4] を返しますから,i には 0 ~ 4 の値が入ります.球の番号 i と位置 x との関係は x = 2i - 4 ですから,次のように書けば i 番目の球の x を指定することができます.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
for i in range(5):
x = 2 * i - 4
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5, location = (x, 0, 0))
これを実行すると,次のように五個の球が現れると思います.

なお,range() は range(初期値,上限値,増分) のように指定することもできるので,range(-4, 5, 2) とすれば上の x のような値の組 [-4, -2, 0, 2, 4] を直接生成することができます.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
for x in range(-4, 5, 2):
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5, location = (x, 0, 0))
下図のように図形を二次元(縦横)に配置する場合は,繰り返しを二重にします(二重ループ).

各列は先ほど作った球を一列に配置するスクリプトで作成することができますから,これをさらに y = [-3, -1, 1, 3] について繰り返します.これは for y in range(-3, 4, 2): で実行できます.これを for x in range(-4, 5, 2): の前に挿入し,for x in range(-4, 5, 2): 以降にインデント(字下げ)を追加します.また,球の位置 location を (x, y, 0) に変更します.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
for y in range(-3, 4, 2):
for x in range(-4, 5, 2):
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5, location = (x, y, 0))
これを実行すると,次のように球が配置されます.

今度は,下図のように球を円形に配置してみましょう.

ここでは三角関数 sin,cos を使用します.三角関数のような数学関数を使用する場合には,math モジュールを導入します. また,配置する球の数を n,配置する円の半径を r とします.とりあえず n = 12,r = 4 にしておきます.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
import math
n = 12
r = 4
この場合も for ~ in と range() を使って n 個の球をシーンに追加します.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
import math
n = 12
r = 4
for i in range(n):
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5)
変数 i を使って角度 t を求めます.i は 0 ~ n - 1 の値を持ちます.n = 12 なら 0 ~ 11 です.そうすると,i 番目の球の角度 t は,t = 2πi / n になります.円周率π は,math モジュールでは math.pi に入っています.また三角関数 sin,cos は math.sin(),math.cos() で呼び出すことができます.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
import math
n = 12
r = 4
for i in range(n):
t = 2.0 * math.pi * i / n
x = r * math.cos(t)
y = r * math.sin(t)
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5, location = (x, y, 0))
このスクリプトを実行すると,球が円形に配置されます.

図形に色を付けるには,材質 (material) のデータを作成し,それを図形に設定します.材質のデータ作成は bpy.data.materials.new(name) で行います.name はこの材質に付ける名前の文字列です.作成されたデータに色などのパラメータを設定し,data.materials.append(材質) によってオブジェクトデータに追加します.直前に bpy.ops.mesh.primitive_ico_sphere_add() で作られたオブジェクトデータは,bpy.context.object で得られます.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
import math
n = 12
r = 4
material = bpy.data.materials.new('Red')
material.diffuse_color = (1, 0, 0)
for i in range(n):
t = 2.0 * math.pi * i / n
x = r * math.cos(t)
y = r * math.sin(t)
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5, location = (x, y, 0))
bpy.context.object.data.materials.append(material)
色のデータはタプル (r, g, b) やリスト [r, g, b] で指定します.r, g, b はそれぞれ光の三原色の赤,緑,青の反射率で,それぞれの値の範囲は 0~1 です.このスクリプトを実行すると,次のようなレンダリング結果が得られます.

図形ごとに色を変えるには,色ごとに材質を作成します.下の例では変数 material をリストにして,その六つの要素にそれぞれ異なる色を登録しています.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
import math
n = 12
r = 4
materials = []
for i in range(1, 7):
materials.append(bpy.data.materials.new('Color' + str(i)))
materials[-1].diffuse_color = ((i >> 2) & 1, (i >> 1) & 1, i & 1)
for i in range(n):
t = 2.0 * math.pi * i / n
x = r * math.cos(t)
y = r * math.sin(t)
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5, location = (x, y, 0))
bpy.context.object.data.materials.append(materials[i % 6])
プログラミング言語の演算子プログラミング言語には,四則演算(加減乗除)を表す +, -, *, / の演算子の他に,さまざまな演算子が用意されています.以下の Python の演算子は,C 言語を由来としています.したがって,((i >> 2) & 1, (i >> 1) & 1, i & 1) は i = 0 → (0, 0, 0),i = 1 → (0, 0, 1),i = 2 → (0, 1, 0),i = 3 → (0, 1, 1),i = 4 → (1, 0, 0),i = 5 → (1, 0, 1),i = 6 → (1, 1, 0),i = 7 → (1, 1, 1) になります.
- >>
- ビットシフト演算子.たとえば,整数の 5 は二進数では 101 になります.これを |0|1|0|1| と表したとします.>> の右側が 1 のとき,左側の整数の各桁(ビット)を右に 1 ケタずらします.その際,右からあふれた桁は捨てられます.この結果は |0|0|1|0| になりますので,二進数で 10,十進数で 2 になります.これは整数を 2 で割って余りを捨てるのと同じです.同様に << という演算子もあります.これは各桁を左にずらします.5 << 1 は |0|1|0|1| を |1|0|1|0| にしますから,これは十進数の 10 になります.二倍するのと同じです.
- &
- ビット論理積演算子.これは整数を二進数で表したときの各桁の論理積を求めます.5 & 2 は |0|1|0|1| と |0|0|1|0| の両方の対応する桁が 1 の時その桁が 1 になりますので,結果は |0|0|0|0| すなわち 0 になります.5 & 1 は |0|1|0|1| と |0|0|0|1| ですから結果は |0|0|0|1| すなわち 1 になります.& の右側が 1 のとき,左側の整数の二進数表記における最下位桁を取り出します.したがって,左側が偶数なら 0,奇数なら 1 になります.このような演算子には,他に |(ビット論理和),^(ビット排他的論理和),それに単項演算子(左側にしか数値を置かない)の ~(ビット論理否定・ビット反転)があります.
- %
- 整数の剰余.割り算の余りを求めます.11 % 3 は 11 ÷ 3 = 3 あまり 2 なので 2 になります.i % 6 は i がどのような値であっても 0 ~ 5 の間の整数になります.
このスクリプトを実行すると,次のようなレンダリング結果が得られます.

それでは,このシーンをレンダリングするために,まず光源の位置と方向を設定します.現在のシーン中の光源のオブジェクトデータは bpy.data.objects['Lamp'] で得ることができますから,一旦,変数 lamp に代入します.そして lamp.location に位置,lamp.rotation_euler に角度(オイラー角)を設定します.光源の種類は lamp.data.type に設定します.'POINT'(点光源),'SUN'(平行光線),'SPOT'(スポットライト),'HEMI'(半球光源),'AREA'(エリアライト)などが代入できます.lamp.data.falloff_type は光源からの距離による光の強度の減衰の設定で,デフォルトの 'INVERSE_SQUARE'(距離の二乗に反比例)では暗くなりすぎるので,'INVERSE_LINEAR' を設定しています.また,この光源によって影を発生させる場合には lamp.data.shadow_method に 'RAY_SHADOW',影を発生させないなら 'NOSHADOW' を代入します.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
import math
n = 12
r = 4
materials = []
for i in range(1, 7):
materials.append(bpy.data.materials.new('Color' + str(i)))
materials[-1].diffuse_color = ((i >> 2) & 1, (i >> 1) & 1, i & 1)
for i in range(n):
t = 2.0 * math.pi * i / n
x = r * math.cos(t)
y = r * math.sin(t)
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5, location = (x, y, 0))
bpy.context.object.data.materials.append(materials[i % 6])
lamp = bpy.data.objects['Lamp']
lamp.location = (20, 10, 10)
lamp.rotation_euler = (-0.2, -0.4, 0)
lamp.data.falloff_type = 'INVERSE_LINEAR'
lamp.data.shadow_method = 'NOSHADOW'
変更が完了したら,このスクリプトを一度実行した後 [F12] キーをタイプしてレンダリングしてみてください.元のウィンドウに戻すには [Esc] キーをタイプします.
同様に,カメラの位置と方向を設定します.これも現在のシーン中のカメラのオブジェクトデータを bpy.data.objects['Camera'] で得ることができますから,これを一旦,変数 camera に代入します.そして camera.location に位置,camera.rotation_euler に角度(オイラー角)を設定します.また camera.data.type に 'PERSP' を代入すれば透視投影 (perspective),'ORTHO' を代入すれば直交(平行)投影 (orthographic) になります.透視投影の場合,カメラの画角を設定するには camera.data.angle に角度を単位をラジアンで代入します.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
import math
n = 12
r = 4
materials = []
for i in range(1, 7):
materials.append(bpy.data.materials.new('Color' + str(i)))
materials[-1].diffuse_color = ((i >> 2) & 1, (i >> 1) & 1, i & 1)
for i in range(n):
t = 2.0 * math.pi * i / n
x = r * math.cos(t)
y = r * math.sin(t)
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5, location = (x, y, 0))
bpy.context.object.data.materials.append(materials[i % 6])
lamp = bpy.data.objects['Lamp']
lamp.location = (20, 10, 10)
lamp.rotation_euler = (-0.2, -0.4, 0)
lamp.data.falloff_type = 'INVERSE_LINEAR'
lamp.data.shadow_method = 'NOSHADOW'
camera = bpy.data.objects['Camera']
camera.location = (15, 0, 15)
camera.rotation_euler = (0, 1, 0)
camera.data.type = 'PERSP'
camera.data.angle = 1
変更が完了したら,このスクリプトを一度実行した後 [F12] キーをタイプしてレンダリングしてみてください.元のウィンドウに戻すには [Esc] キーをタイプします.
背景色は bpy.data.objects['World'] で得られる現在のワールドオブジェクトデータに設定します.これを一旦,変数 world に代入し,world.horizon_color に水平線方向の空の色,world.zenith_color に天頂方向の空の色を設定します.そして world.use_sky_blend に True を代入しておけば,背景が水平線方向から天頂方向へのグラデーションになります.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
import math
n = 12
r = 4
materials = []
for i in range(1, 7):
materials.append(bpy.data.materials.new('Color' + str(i)))
materials[-1].diffuse_color = ((i >> 2) & 1, (i >> 1) & 1, i & 1)
for i in range(n):
t = 2.0 * math.pi * i / n
x = r * math.cos(t)
y = r * math.sin(t)
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5, location = (x, y, 0))
bpy.context.object.data.materials.append(materials[i % 6])
lamp = bpy.data.objects['Lamp']
lamp.location = (20, 10, 10)
lamp.rotation_euler = (-0.2, -0.4, 0)
lamp.data.falloff_type = 'INVERSE_LINEAR'
lamp.data.shadow_method = 'NOSHADOW'
camera = bpy.data.objects['Camera']
camera.location = (15, 0, 15)
camera.rotation_euler = (0, 1, 0)
camera.data.type = 'PERSP'
camera.data.angle = 1
world = bpy.data.worlds['World']
world.horizon_color = (0.2, 0.4, 0.6)
world.zenith_color = (0.0, 0.0, 0.2)
world.use_sky_blend = True
変更が完了したら,このスクリプトを一度実行した後 [F12] キーをタイプしてレンダリングしてみてください.元のウィンドウに戻すには [Esc] キーをタイプします.
いよいよ,シーンの最終的なレンダリングを行います.シーンのレンダリング設定は,処理対象となっているシーンを bpy.context.scene から得て,それに対して行います.シーン名 'Scene' を bpy.data.scenes['Scene'] で明示的に指定して得ることもできます.シーンには多数の設定項目がありますが,ここではレンダリング画像の xy 方向の解像度 scene.resolution_x,scene.resolushon_y および実際にレンダリングする画像サイズの百分率 scene.resolution_percentage を設定します.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
import math
n = 12
r = 4
materials = []
for i in range(1, 7):
materials.append(bpy.data.materials.new('Color' + str(i)))
materials[-1].diffuse_color = ((i >> 2) & 1, (i >> 1) & 1, i & 1)
for i in range(n):
t = 2.0 * math.pi * i / n
x = r * math.cos(t)
y = r * math.sin(t)
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5, location = (x, y, 0))
bpy.context.object.data.materials.append(materials[i % 6])
lamp = bpy.data.objects['Lamp']
lamp.location = (20, 10, 10)
lamp.rotation_euler = (-0.2, -0.4, 0)
lamp.data.falloff_type = 'INVERSE_LINEAR'
lamp.data.shadow_method = 'NOSHADOW'
camera = bpy.data.objects['Camera']
camera.location = (15, 0, 15)
camera.rotation_euler = (0, 1, 0)
camera.data.type = 'PERSP'
camera.data.angle = 1
world = bpy.data.worlds['World']
world.horizon_color = (0.2, 0.4, 0.6)
world.zenith_color = (0.0, 0.0, 0.2)
world.use_sky_blend = True
scene = bpy.context.scene
scene.render.resolution_x = 640
scene.render.resolution_y = 360
scene.render.resolution_percentage = 100
変更が完了したら,このスクリプトを一度実行した後 [F12] キーをタイプしてレンダリングしてみてください.元のウィンドウに戻すには [Esc] キーをタイプします.
スクリプト内でレンダリングを実行するには,bpy.ops.render.render() を使うと便利です.ただし,この場合はレンダリング結果は画面には表示されません.レンダリング結果は bpy.data.images['Render Result'] に入っているので,この save_render() メソッドを使ってファイルに保存します.保存するファイル名は絶対パスで指定する必要があります.
そこで,ホームディレクトリの絶対パスを得るために,import os によって Python から OS(オペレーティングシステム)の機能を呼び出す os モジュールを導入します.この os.environ によって,環境変数を取得することができます.os.environ['HOME'] は環境変数 HOME の内容を得ます.これには Unix/Linux および Unix をベースにしている Mac OS X におけるホームディレクトリが設定されています.これにディレクトリの区切り文字 '/' で区切ったファイル名の文字列を連結します.なお,Windows(多分 Vista 以降)で「ドキュメント (My Documents)」に保存するには,filepath = os.environ['HOMEPATH'] + '/My Documents/image.png' とすればいいんじゃないかと思います.
#!BPY
import bpy
for item in bpy.context.scene.objects:
if item.type == 'MESH':
bpy.context.scene.objects.unlink(item)
for item in bpy.data.objects:
if item.type == 'MESH':
bpy.data.objects.remove(item)
for item in bpy.data.meshes:
bpy.data.meshes.remove(item)
for item in bpy.data.materials:
bpy.data.materials.remove(item)
import math
n = 12
r = 4
materials = []
for i in range(1, 7):
materials.append(bpy.data.materials.new('Color' + str(i)))
materials[-1].diffuse_color = ((i >> 2) & 1, (i >> 1) & 1, i & 1)
for i in range(n):
t = 2.0 * math.pi * i / n
x = r * math.cos(t)
y = r * math.sin(t)
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions = 3, size = 0.5, location = (x, y, 0))
bpy.context.object.data.materials.append(materials[i % 6])
lamp = bpy.data.objects['Lamp']
lamp.location = (20, 10, 10)
lamp.rotation_euler = (-0.2, -0.4, 0)
lamp.data.falloff_type = 'INVERSE_LINEAR'
lamp.data.shadow_method = 'NOSHADOW'
camera = bpy.data.objects['Camera']
camera.location = (15, 0, 15)
camera.rotation_euler = (0, 1, 0)
camera.data.type = 'PERSP'
camera.data.angle = 1
world = bpy.data.worlds['World']
world.horizon_color = (0.2, 0.4, 0.6)
world.zenith_color = (0.0, 0.0, 0.2)
world.use_sky_blend = True
scene = bpy.context.scene
scene.render.resolution_x = 640
scene.render.resolution_y = 360
scene.render.resolution_percentage = 100
import os
bpy.ops.render.render()
bpy.data.images['Render Result'].save_render(filepath = os.environ['HOME'] + '/image.png')
このスクリプトを実行すると,レンダリングしている間待たされた後,次のようなレンダリング結果がファイルに保存されます.

次の (1)~(2) の作業を行い,それぞれの結果と (3) の内容をメールで tokoi@sys.wakayama-u.ac.jp に送ってください.メールの件名 (Subject) は shori1-15 にしてください.期限は次週の水曜日中までです.

授業評価アンケート調査を行っています.協力をお願いします.下記のページ(リンクになっています)からアンケートのページを開いて入力してください.
| アンケートページの URL |
|---|
| http://www.sys.wakayama-u.ac.jp/enquete/ |
期間は平成25年7月10日(木)~8月8日(金)です.よろしくお願いします.