ホーム < ゲームつくろー! < ゲームプログラマのためのBlender

ゲームプログラマのためのBlender
その7 Blenderに外部のGLSLスクリプトを取り込む


 前章で、Blender内のText WindowでGLSLのテストシェーダを作り、Logic Windowで描画ロジックを差し替えてそのスクリプトを起動する事でシェーダ描画を実現しました。一応描画は出来たのですが、このままだと問題があります。記述したGLSL(Pythonスクリプト)、これ、Blenderのプロジェクトを保存しても別ファイルに出力されるというわけではありません。ではどこに行ったのか?バイナリであるBlenderプロジェクト(.blend)をテキストファイルで強引に開くとこういう記述が見えます:

 VertexShader云々などText Windowで記述した文字列が見えます。つまり、Text Windowで直書きしたGLSLスクリプトは、プロジェクトファイル内に埋め込まれてしまうわけです。これだと作ったシェーダは一点物。別のプロジェクトへ使い回せません。GLSLスクリプトを外部のテキストで記述しそれを読み込むにはどうしたら良いか?それを見て行きましょう。



@ 外部Pythonスクリプトを読み込む

 Blenderで外部のPythonスクリプトを読み込む一番簡単な方法は、Text Windowsのメニューにある[Text]→[Open Text Block]で別ファイルに書いたPythonスクリプトを読み込ませる事です:

試しに適当な場所に「myshader001.py」というスクリプトファイル(テキストファイル)を作り、下のシェーダコードを記述してみましょう:

myshader001.py
import bge

cont = bge.logic.getCurrentController()

VertexShader = """
    void main() {
        gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    }
"""

FragmentShader = """
    void main() {
        gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0);
    }
"""

mesh = cont.owner.meshes[0]
for mat in mesh.materials:
    shader = mat.getShader()
    if shader != None:
        if not shader.isValid():
            shader.setSource( VertexShader, FragmentShader, 1 )

前章のFirstShaderのフラグメントシェーダからシアン色を出力するように変更しました。、このファイルをOpen Text Blockで開いてみましょう。開くとText Windowにそのコードが反映されます。また、そのスクリプトファイルがプロジェクトに登録されます:

このようにText Windowのスクリプトの選択肢に出て来るようになりました。このスクリプトは前章で試したLogin WindowのScript Controllerにももちろん出てきます。前章のFirstShaderではなく今回のmyshader001.pyに繋ぎ換えてみましょう:

で、前章同様にレンダリングをBlender Gameモードにして[Embedded Player]の[Start]でシェーダ描画を走らせてみましょう:

はい、シアン色になりました(^-^)。これで、GLSLスクリプトを外部から読み込む手順が一つわかりました。



A 選択したオブジェクトにシェーダを適用するスクリプト

 前章ではもう一つLogicを手作業で作成していました。Always Sensorを追加して、Python Controllerを追加して、そこにシェーダスクリプトを設定して、最後にSensorとControllerとを接続しました。何か新しいモデルを作成する度にこの作業をするのは手間以外の何物でもありません。ここはスクリプト一発起動で自動化したい所です。

 試行錯誤した結果、次のようなスクリプトで選択中のモデルのLogicを前章と同じ状態にする事が出来ました:

create_logic_myshader001.py
import bpy

activeObj = bpy.context.active_object

# add sensor
bpy.ops.logic.sensor_add( type='ALWAYS')
sensor = activeObj.game.sensors['Always']

# add controller
bpy.ops.logic.controller_add( type='PYTHON', name='myshader001' )
cont = activeObj.game.controllers['myshader001']

# set script to current controller
cont.text = bpy.data.texts['myshader001.py']

# link the sensor to the controller
sensor.link( cont )

 まずimport。これはBlenderの中にある使いたいPythonライブラリを宣言する記述です。C言語で言う所の#includeです。「bpy」というのは「Blender Python」の略で、Blenderの基礎ライブラリの一つです。

 bpy.contextというのはBlenderの中にあるオブジェクトを管理している人です。色々な物を持っていますが、上のようにbpy.context.active_objectとすると現在アクティブになっている3D View内のオブジェクトを返してくれます。実際にBlenderのウィンドウの一つ「Python Console」で確認するとこうなります:

bpy.context.active_objectと打ちこんでリターンを押すと、「bpy.data.objects['Cube']ですよ」と教えてくれました。今選択してアクティブになっている物を返してくれたわけです。上のスクリプトではこれを「activeObj」という変数に保存しています。

 この選択中のオブジェクトのLoginにSensorを追加しているのが「bpy.ops.logic.sensor_add( type='ALWAYS' )」という1行。bpyには「ops」という大きなくくりがあります。これは「Operators」というBlender内の「操作」に関わるモジュールをまとめた物です。opsの中にも沢山色々あるのですが「ops.logic」にLogic Windowでの操作をする命令が格納されています。ops.logic.sensor_add関数は名前の通りSensorを追加します。Blenderの引数は引数名を指定する必要があります。typeはセンサーのタイプを文字列で指定します。これはAlwaysにしていたのでそれを表す「ALWAYS」にセットします。この1行を実行すると、Logic Window内にSensorが追加されます:

手作業でしていたのがポンっと出てくるのでちょっと感動します(^-^)。

 さて、この追加したSensorは選択されているオブジェクトに関連付いています。後で使いますのでこれをsensor変数に保存しておきましょう。それが「sensor = activeObj.game.sensors['Always']」です。Logicとして登録したものは選択オブジェクトの「game.sensors」という所に格納されているようです。これは連想配列でして名前で対象を取り出せます。上のSensorを見ると名前は「Always(灰色のテキストボックスが名前)」のようなので、配列の要素にその名前を指定すると上のSensorを取り出せます。

 続いてPython Controller(シェーダ本体)をLogicに追加します。bpy.ops.logic.controller_add( type='PYTHON', name='myshader001' )の一行です。ops.logicなのでLoginの操作系、contorller_add関数はControllerを追加する関数です。このtypeも色々ですが、今回はスクリプトを表すControllerなので「PYTHON」と指定します。またこのControllerを表す名前を「name='myshader001'」と指定しています。これでLogicにControllerが追加されます:

右側のControllerノードがそれです。ただ、まだスクリプトが指定されていませんね。次の2行がその指定になっています:

cont = activeObj.game.controllers['myshader001']
cont.text = bpy.data.texts['myshader001.py']

 1行目はもう大体わかりますよね。game.controllersがControllerの配列で先程指定した名前でそれを取り出しています。
 2行目ですが、myshader001 Controllerのスクリプトテキストは.textにあります。今は空っぽです。そこにスクリプトを指定するのが右辺側。bpy.dataというのは、今開いているBlenderプロジェクトのありとあらゆるデータを格納している親分オブジェクトです。data親分の下には沢山の子分がぶら下がっているのですが、その中の「texts」というのに現在登録されているスクリプトが配列で格納されています。上のように'myshader001.py'と指定する事で、そのスクリプトが取り出せるので、それをController.textに代入しています。これで、Controllerにスクリプトが指定されます:

 最後にSensorとControllerを接続します。これは最後の一行の「sensor.link( cont )」です。Sensorが持つlink関数は引数にControllerを取ります。引数名は省略できるみたいです。これで、SensorとControllerの間が繋がれます:

上のスクリプトを動かすと、まっさらなLogicからここまでを一気に作ってくれるわけです。大変に便利(^-^)。もちろん他のオブジェクトを3D View内に配置してこのスクリプトを再度実行すると、そのオブジェクトにもmyshader.pyが適用されます:


 と言う事で、外部にBlender用のPythonスクリプトファイルを置いておき、Text WindowでそれをOpenする事によってBlenderプロジェクト内にスクリプトを登録する事が出来ました。前章までの手作業は今や、

・ Text Windowで[Open Text Block]→[myshader001.py]を開き登録
・ Text Windowで[Open Text Block]→[create_logic_myshader001.py]を開き登録
・ myshadder001を適用したいオブジェクトを3D Viewで選択
・ create_logic_myshader001.pyを実行(Text Window内で[Alt + P]で動きます)

という作業に減りました。スクリプトコードをBlender内で直に記述していないのが大きいですよね。

 さて、こうなると次に考えたいのが「シェーダ定数」の扱いです。上のシェーダ描画を見るとどちらもシアン色に染まっています。でも、この色を自由に指定したいですよね。次はその辺りを調べてみる事にしましょう。