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

ゲームプログラマのためのBlender
その6 カスタムシェーダでの描画に挑戦


 前章まででBlenderの基本的な所を抑えました。ここからはゲーム制作寄りのお話に少し切り替えて行きます。ゲームで使うモデルはシェーダで描画します。それはBlenderの描画方法(描画エンジン)とは別物です。そのため、Blender上でシェーダ描画が出来ないとデザイナさんはゲーム用のモデル製作ができません。そこでBlender上でカスタムシェーダによるゲーム描画に挑戦してみましょう。結構イバラの道ですが、頑張りましょう〜(^-^;



@ カスタムシェーダ描画への道

 2014.10時点のBlenderバージョン2.72でシェーダによって描画するまでの最低限の手順を追ってみます。起動直後からスタートです:


○ Text Editorを開く

 最初にBlender内でシェーダを記述する為にText Editorを開きます。これはいくつかやり方がありますが、画面が狭くなってしまうので別のウィンドウに開いてみます。上のメニュにある[Window]→[Duplicate Window]を選択すると、Blenderのウィンドウが複製(duplicate)されて別ウィンドウで同じ物が開きます(下図左):

   

新しく開いたウィンドウの上メニューにあるInfoアイコンをクリックするとEdit Typeを選択するメニューが出てきます(上の中図)。そこにある[Text Editor]を選択すると、アイコンがText Editorになります。ただ、これだけだとまだそれっぽいウィンドウには変わりません。そこで同じメニューバーにある[View]→[Toggle Full Screen]でウィンドウ内全画面表示に変更します(上の右図)。これでウィンドウ内はこうなります:

これがText Editorです。ここで新しいテキストを追加し「スクリプト」を編集する準備をします。下にある「+ New」ボタンをクリックすると新しいテキストが追加され、編集モードになります。これから記述するのはシェーダなので、名前を「FirstShader」とでもしておきましょう。テキストの名前を設定するには下のメニューバーの「Text」と書いてある場所を編集します:

 次にシェーダスクリプトを書きます。



○ スクリプトでシェーダを書く

 シェーダスクリプトは例えばこういう感じになります:

First Shader
import bge

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

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

cont = bge.logic.getCurrentController()

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 )

参照:GLSL Programming/Blender/Minimal Shader

 スクリプト内にVertexShaderとFragmentShaderというシェーダの記述がありますね。これらは双方とも「GLSL」です。残念ながらBlenderはDirectX(HLSL)はサポートしていないようです。この辺りについては後々で多分面倒臭い事が起こりそうですが今は気にせず進みましょう。

 VertexShaderという変数に頂点シェーダの文字列が代入されています。main関数内のように書くと、オブジェクトの頂点にワールドビュー射影変換行列(gl_ModelViewProjectionMatrix)が掛け算され、gl_Position(出力用変数)にその座標が格納されます。FragmentShader(フラグメントシェーダ)のmain関数ではgl_FragColor(出力用変数)にRGBA=(1,1,0,0)、すなわち黄色が出力されています。つまり、このシェーダはオブジェクトのポリゴンをスクリーンに投影して、そこを黄色に塗りつぶすシェーダという訳です。

 その下は何か?これはこのシェーダをマテリアルに適用している部分です。細かい事は別章での説明に回すとして、ざっくりやっている事を説明すると、meshはCubeのポリゴン群で、matにはそのポリゴンに適用されているマテリアルが取得されます。mat.getShader()でそのマテリアルが持つシェーダを取得でき、シェーダがあってそのシェーダが有効でない場合にshader.setSource()で頂点シェーダとフラグメントシェーダをセットしています。この処理を行う事で、Cubeのポリゴンに適用されているマテリアルがカスタムシェーダに置き換わります。

 シェーダスクリプトが書けたので、次はこのスクリプトを動かす仕組みを作ります。



○ レンダリングロジックのカスタマイズ

 続いてCubeのレンダリングロジック(描画方法)を構築します。3D View内では多分原点に置かれているCubeが選択されていると思います。選択が外れている場合は選択状態にしておいて下さい。このCubeのレンダリングロジックを編集するには「Logic Editor」を開きます。Text Editorを開いた時と同様に、ウィンドウを複製(dupulicate)して別ウィンドウを開き、Infoアイコンをクリック、を選択します。そしてフルスクリーンにして下さい:


なんかフォントでけぇ…(^-^;。ホイールを前後するとスケールを変えられます

これがLogic Editorの画面です。画面に「Cube」とあるように、選択されているオブジェクトのレンダリングロジックを編集しようというわけです。

 続けましょう。下メニューにある[Add]→[Sensor]から[Always]を選択します:

 この「Sensor」は外部からの入力に関する情報を表しています。JoystickとかMouseという表記がありますよね。各Sensorはその入力が来ると信号を発してくれます。Alwaysは「いつも」なので、描画のタイミングが来る度にその信号が出ると言う訳です。プログラム的に言えばコールバックが呼ばれると言う感じですね。Always Sensorを選択するとLogic Editorに次のようなウィジットが出現します:

 Alwaysを通して描画タイミングの度に「何か」したいと。で、何をしたいかというと先程書いたFirstShaderスクリプトを実行したいんです。それをするにはスクリプト用の「Controller」を追加します:

[Add]→[Controller]→[Python]とするとスクリプト用のウィジットが追加されます:

 矢印で示したのがPythonウィジットです。Pythonというのは汎用スクリプトの一つで、BlenderのスクリプトはすべてPythonです。[Script]と記述されている所の右にあるアイコンをクリックすると、現在のスクリプト一覧が出てきます。今は[FirstShader]しかありませんのでそれを選択します。

 さて、Always Sensorは描画の度にレッツゴーと信号を発してくれます。Python Controllerはそれを受ける必要がありますが、上の状態ではそれを検知できません。ちゃんと線を繋いであげる必要があります。そのためには双方の間にあるちっちゃい丸をドラッグして繋げます。が出力側、が入力側です。出力側を摘まんで入力側にドラッグするとケーブルのような線が延びます。双方を繋ぐとこんな感じになります:

これで描画タイミングが来る度にFirstShaderスクリプトが実行されるようになります。さぁ、もう少しです(^-^)



○ ロジックを実行

 描画ロジックを組んでシェーダへも接続しました。このロジックを動かすにはBlenderのレンダリングエンジンを[Blender Game]モードにします。Blenderには[Blender Render]モード、[Blender Game]モードそして[Cycle Render]モードという3つのレンダリングエンジンがあります。Blender Renderモードはいわゆる通常のレイトレーシングでレンダリングするモードです。Cycle Renderモードは新しいレンダリングエンジンのようで、v2.72ではまだ開発中とのこと。そしてBlender Gameモードはシェーダを使ったレンダリングを行ってくれます。

 レンダリングエンジンをBlender Gameモードにするには、上のメニューにあるBlender Renderをクリックして切り替えます:

Blender Gameに切り替えると、右側のパネルの項目が少し変化します。そして、そこにある[Embedded Player]の[Start]、これをクリックするとBlender Gameエンジンが動きだします。先程設定したロジックはこの時に初めて動きます:

Startをクリックすると3D Viewが上の絵からこんな風に変わります:

 FirstShaderスクリプトに記述したようにオブジェクトが全部黄色で塗りつぶされました。やった〜(^-^)/

 Embedded PlayerをStartするとカーソルが消えてしまいます。これちょっと焦りますw。元に戻すには[Esc]キーを押して下さい。また、一々Startをクリックしなくても[p]キーがショートカットになっています。


 という事で、Blenderによるシェーダ(GLSL)描画が出来ました。出来ましたが、色々問題もあります。まずスクリプトがBlender内での記述になっているという事。これだと汎用性がありません。別のモデルを作る度にシェーダを全部書き直すわけにはいかないわけです。他にも、オブジェクトをFBXで出力した時に情報がちゃんと出てくるかもまだ確認できていません。これらについて解決できるかも含め、さらに調査していきましょう。(※本記事を執筆時点で解決できるかわかっていません(^-^;;)