シェーダ自動生成システムを使ってみる前章までで、シェーダの自動化と柔軟化の仕組みの根っこのような物が、まだまだ叩き台の段階ではありますが、一先ずできました。これを使ってみたいと思います。何度か使ってみれば、足りない機能や修正すべき項目などが見えてくるはずです。ディフューズ+スペキュラマップを貼ってみるテストとして、ディフューズマップとスペキュラマップを貼り付けた板ポリゴンを描画するシェーダを作ってみます。新規クラス作成まずShaderCreatorの派生クラスとしてDSShaderCreatorクラスを作ります。);};}#endif現段階で仮想メソッドは6つあります。これを一つ一つ設定していって自動生成システムを構築していきます。ディフューズマップとスペキュラマップが当然必要になるので、GlobalTextureValクラスでそれらを宣言します。そのテクスチャをサンプリングするためのサンプラ(GlobalSamplerValクラス)、そしてサンプリング関数を作成するSamplerFuncオブジェクトがテクスチャ周りで必要なクラス群です。この辺、ちょっと乱雑かもしれません。ディフューズ(拡散反射光)は目線の位置に関係なく全ての方向に等しく広がります。拡散の強さはポリゴンの面に対する光の入射角度できまります。いう事は光がどの方向から差しているか、すなわち「ライトの角度」が必要ですね。スペキュラマップ(鏡面反射光)はある方向から面を見たときにきらっと輝く効果を出します。これは光の反射光が目線に飛び込んでくるために起こります。光の入射角度はディフューズ計算でも使うため共通です。目線位置(カメラ位置)が新たに必要となります。実は直接はいりません。?カメラの位置はビュー空間において常に原点、そして方向はZ軸と定められています。この情報はすべて「ビュー行列」に含まれているわけです。いう事で、必要なグローバル変数は各種行列とライト方向(ワールド空間)です。これらをメンバとして宣言します。コンストラクタで変数の初期化コンストラクタではシェーダ内で使用されるすべての変数の初期化を行います。PixelOutputSemanticsStruct("PS_OUTPUT",SemanticsInfo::COLOR0);}各変数には初期値が必要です。セマンティクスの初期化はコンストラクタ内部で代入形式で行います(親クラスに実体があるため)。出力セマンティクスには座標の他にUV、頂点法線、そしてライトの方向が必要です(スペキュラ計算をピクセルシェーダで行うため)。この初期化方法は至って形式的な物なので、静々と行いましょう。続いて、上で定義した変数をコンバータに教える必要があります。それを担うのがregistUserValsメソッドです。specularFunc);conv.regist(lightDir);conv.regist(worldMatrix);conv.regist(viewMatrix);conv.regist(projMatrix);}親クラスにconvという変数があります。このregistメソッドを通して登録を行います。これでシェーダコードにメンバ変数を直接記述できるようになります。サンプラ関数の登録がちょっとなぁという感じです。グローバル変数の書き込みここからはシェーダコードの書き込みです。projMatrix.decl();}ここに少し改良の余地があるかなぁという感じです。サンプラの宣言を書き込む時に上のようにテクスチャを渡していますが、これはここでしなくてもコンストラクタで定義できるようにするべきですよね。頂点シェーダの欠落セマンティクスに対する初期化もしモデルがこのシェーダが要求する入力セマンティクス(座標、UV、法線)のどれかを持っていない場合、入力値を初期化しておく必要があります。"\n";}このメソッドの引数のmodelSemInfoにはモデルが持つ頂点入力セマンティクスの情報が入っています。その中にこのシェーダが必要とする座標、UV、法線セマンティクスがあるかをfindメソッドでチェックします。無い場合はそれの代替となる初期値を上のように書き込みます。$(In.pos)のように$が付いているのは予約語でして、入出力セマンティクスとregistUserValsメソッド内で登録したグローバル変数を上のように使えます。初期値は適当ですが、普通0.0かなと思います。頂点シェーダコードようやっと頂点シェーダの作成です。するべき事は「頂点の変換」、「ビュー空間でのライト方向の計算」、「ビュー空間での法線の計算」です。空間ベースにする事で目線の情報を省略できます。Out;\n\n";}ご覧頂いてわかるように、通常のシェーダとあまり変わらない形で書き込んでいけます。可読性は悪くないと思います。プログラム上でのコメントも書けます。続いてピクセルシェーダ内での処理です。モデルが必ずしもディフューズやスペキュラマップを持っているとは限りません。いう欠落テクスチャがあった場合に対処するため、テクスチャからのサンプリングはシェーダ内関数を通すようにしています。そのシェーダ内関数を書き込むのがここ(samplerFunctionsCodeメソッド)です。specularFunc);}ヘルパー関数のお陰で非常に短く書けるのですが、まず第2引数がえ〜っという感じですね。後、例えばシェーダ内にテクスチャが10枚あったとしたら、きっと10回これを書きます。それはさすがに面倒ですよね。そもそも「サンプラ」「テクスチャ」「サンプラ関数」は常に一塊なのですから、そういう塊(構造体)を作ってしまい、上の関数呼び出しを裏でやってもらえば、わざわざ派生クラスで書く必要が無くなってしまいます。これも改良箇所ですね。ピクセルシェーダコード最後はピクセルシェーダです。ここではディフューズカラーとスペキュラカラーを計算して穿つだけです。Out;\n";}スペキュラの計算はライトと目線とがなすベクトルの真ん中となる「ハーフベクトル(halfVec)」を算出し、それと法線との内積で目に飛び込んでくる強さを計算しています。さ、これで全部揃いました。シェーダの自動生成ができます(^-^)。以上の実装をベースとしたサンプルを作成してテストしてみました。コードの詳細はサンプルをご覧頂くとして、スクリーンショットはこんな感じになりました:4枚の板ポリゴンにそれぞれ別の特性を与え、それぞれに対応したシェーダを自動生成して描画しました。頂点座標のみ(テクスチャなし、UV無し)概ねうまく動いているようです。�@でちまちまと実装してきたディフューズ+スペキュラマップを適用できる自動生成シェーダですが、実装の過程で色々と改良すべき点が見えてきました。本章はこれで閉じるとしまして、その改良点については次章で検証します。改良をする事で、自動生成システムはさらに使い易くなるのですよ(^-^)。