3DCG修行記 修行記

filterを使った場合分け (Blender Pythonと関数プログラミング #3)

今回はpythonのfilterという関数を使って、オブジェクトの場合分けする方法を書いてみます。この関数は予想できると思うけど、オブジェクトの作成時にも使えるけど、場合分けでオブジェクトのマテリアルを分けて登録したり、一部のフレームで一部のオブジェクトだけを動かすといったアニメーションでも使えることが可能だろうね。いまは、オブジェクトの作成での活用を見せてますが、それでfilterの強力さを知ってもらえれば十分と考えてます。

使うもの

今回は、Blender Pythonと関数プログラミング #1で示したuv_sphere.pyを改造してみます。uv_sphereでは立方体のところに球体を充填させるというものです。単純に-4から4の各軸の範囲に4×4=16の球体を埋め込む3DCGを作ってますね。

uv_sphere.pyで作ったもの

見えやすくする都合で作成する球体の半径を 1から0.8に変更していますが、プログラムとしたら下記のようなものになります。

'''
uv_spheres3.py / Copyright 2020 Yasuto Takenaka
'''
import bpy
import math

def create_objs(locs):
    '''
    create uv spheres. 
    '''
    for l in locs :
        bpy.ops.mesh.primitive_uv_sphere_add(radius= 0.8, location=l)

def object_locs(n0,n,step=2):
    '''
    create a list of each location of objects.
    n0, n1 and step depend on the rule of the function, range. 
    '''
    return [(x,y,z) for x in range(n0,n,step) for y in range(n0,n,step) for z in range(n0,n,step)]

def main():
    n0 = -4 # minimum number of locations
    n1 =  4 # maximum number of locations
    locs = object_locs(n0,n1)
    s_locs = filter(lambda el: el[0] + el[1] + el[2] == 0, locs)
    create_objs(s_locs)

main()

s_locsとfilter

今回変更してるのはs_locs変数をメインに作ってオブジェクト作成に使ってるところです。

    s_locs = filter(lambda el: el[0] + el[1] + el[2] == 0, locs)
    create_objs(s_locs)

ここにfilter関数が含まれていますね。これは1つ目の引数が無名関数(lambda el:…)となってますが、単純にlocsに含まれてる3次元座標の位置情報を足してすべてがゼロになるものを選び出すようにしています。このリスト内の要素は(x,y,z)となってるのですが、この要素の各座標の値を取り出すのは、リストの値を取り出すのと同じアプローチが取れるので、el[n] nは0-2の数字 と表現されています。判定はこれをすべて足して0と等しいものということになってるのです。

uv_sphere3.pyで作ったもの

結果として次のような3DCGになります。

みてのとおり、原点(0,0,0)の球体を含んだ正三角形になる位置取りの球体が10個になります。

    s_locs = filter(lambda el: el[0] + el[1] + el[2] <= 0, locs)
uv_sphere3.pyで作ったもの

と変更すると次のようになります。

作成された球体がこれだけ変わるんですね。作成時にx+y+z <=0 などの法則を適用させるとかんたんにこのように分けられるんですね。

filterに慣れ親しむ

上記の例を見てわかるように、リストの一部のものを選び出すことができるのがフィルターと言う関数です。色んなパターンを自身で試して慣れ親しむことをおすすめします。下記の例は0..9までのリストを作って、そこから偶数のみのbと奇数のみのcを用意しています。filterも結果はrangeやmapと同じようにfilter専用の型になってるのでそのままでは見られないためにlist関数を使ってリストに変換しています。uv_spheres3.pyでのfilterの使い方を見ても分かる通り、わざわざ変換しなくても使えることも多いけど、ここでエラーになる場合もあるのでなんでだろう?というエラーを見たときはlist変換のエラーを疑うと良いかもしれません。

In [1]: a = list(range(10))

In [2]: a
Out[2]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [3]: b = filter(lambda el: el % 2 == 0 , a)

In [4]: list(b)
Out[4]: [0, 2, 4, 6, 8]

In [5]: c = filter(lambda el: el%2 == 1, a)

In [6]: list(c)
Out[6]: [1, 3, 5, 7, 9]

こんな感じで自主的にリストを作成して慣れ親しむことは可能なので、自分で試してみてください。blenderでは文字列の選択は使わないと思うんですが、文字列での取り扱いなどもできます。それは検索して調べてみてください。

最後に

次予定してるのはひまわりの種の配列を再現しようということを見せます。フィボナッチ数列といえばひまわりというくらい法則が知られてるんですが、そこで黄金角(黄金比からきてる、ほぼ137.5度)を使って無限リストをpythonのジェネレターとイテレーションツールを使って試すというのをやってみます。

map,filter,無限リストを扱えるようになると表現の幅はかなり広がりますので、ぜひとも覚えてみてください。用語が難しそうに見えますが、習うより慣れろで見様見真似でいいから身につけてほしいです。
初期のオブジェクト作成をblenderのpythonスクリプトで行うことが自在にできるようになればいいですね。これら3つのアプローチとあとはファイル操作(既存のデータをインポートしてオブジェクトに反映させる)をできたら位置関係の扱いは十分じゃないかな。

あとはオブジェクトの作成の方法を網羅したら次は、マテリアルの使い分けを予定してますね。最後はフレームごとのアニメーションを作るための位置の移動のこともやってみたいかな。その先は人工生命分野で作られてるようなボイドモデル(鳥の群れの動き)でもできればいいかなと思う。要するにアルゴリズムを作成して3DCGに反映させるシミュレーションですね。流体シミュレーション系のものはblenderで取り入れられてるけど、それ以外のシミュレーションはPythonを扱えないと作れないでしょうからね。

オブジェクトも基本的な球体や円柱以外の複雑なものの扱いもできるんだろうし、blenderのpython apiを更に調べてみますね。一応無限リストのところは出来てるから、その先のマテリアル変更をできるようになったら、マテリアル変更のことも記事にしてみます。

もしかすると、オブジェクトの作成の第5弾も用意するかもしれません。用意するとしたら、再帰関数とフラクタル系の話ですね。たとえば、コッホ曲線の節に大きさも変更しながらオブジェクトを配置するというもの。pythonのジェネレーターも強力なものなのですが、再帰でも使います。かんたんなアルゴリズムを作成したオブジェクトの作成ですね。最初の記事から比べると難易度は高く感じるかもしれません。

CSVファイルを読み込んでオブジェクトを作成するものも記事にしたいんですが、扱い方をちゃんと理解してから作るつもりです。これは結構実用的なものだと思いますからね。既存の株価の変動データを使って、グラフィカルに扱うということに有効でしょうしね。

もしよければ、シェアやいいね!を宜しく!
Dagtap ... 語感の覚えやすさとフリック入力で打ちやすいアルファベットを選んだ名前です。それ以上の意味はありません。Twitter: @yst44 Instagram: @yasuto.takenaka が運営してるブログです。連絡先は Gmaily.takenakaです。