「 シェーダー 」一覧

GLSLのシェーダーリフレクション (2)


OpenGL (GLSL) のユニフォームブロックでのシェーダーリフレクションを試してみました。
ここで使った vertexShader, fragment shaderは以下のようなものです。

これらのシェーダーについて情報を出してみるとこのような感じになりました。
まずはシェーダーユニフォームの一覧.

ユニフォームブロックの中身のメンバには、ロケーションIDは振られていないことが確認できます。ユニフォームのインデックスは振られており、情報はこちら軽油で取得できるようです。
そして、ユニフォームブロックに関して情報を取得してみます。

ユニフォームブロック内でのシェーダー定数のオフセットが取得できました。
ユニフォームブロック内に構造体を配置しても、従来のシェーダー定数の場合と変わらないような名前でオフセットやデータ型を取得できることがわかります。

std140 とかレイアウト指定をしない場合、シェーダーによって(環境によって?)定数の位置が変わりそうです。
そのため、UBOを複数のシェーダーで使い回すのは難しそうです。この場合結局定数毎に書き込む位置を見てバッファ内のデータ更新という手続きをとるので、あまりUBOによる描画効率化に繋がらないように感じます。

ユニフォームブロック内の定数であっても GL_ACTIVE_UNIFORMS にて有効なユニフォーム変数としてカウントされていることに少々驚きました。ただしユニフォームブロック内の変数名からは有効なロケーションが取得できません。ユニフォームブロック内の変数についてはロケーション=-1となっているようです。


GLSLのシェーダーリフレクション


GLSLいじりの過程で、シェーダーリフレクションっぽいことをやってみたのでその調査結果です。

OpenGLでは別に他のライブラリに依存することなく、シェーダーリフレクションの機能を持っています。普段ではuniform変数のロケーション情報を名前から取得しているかと思いますが、その延長上でいろいろな情報をとれるようになっています。

そこで次のようなシェーダープログラム(抜粋)で、どのように情報がとれてくるか試してみました。

結果はこんな感じでした。ドライバの状態によっては別の結果を返してきそうな気配も・・・。AMDやIntelで試してみたいところです。

NVIDIA 331.65 のドライバの結果。

ここからわかることは、次のような感じかと。

  • 配列の場合には [0] とか付加されて返ってくる. (NVIDIAの場合限定かも?)
  • サイズとして配列のサイズ(長さ)が返ってくる
  • 構造体メンバの場合は、構造体変数名が間に挟まっている
  • 構造体だからといって、1つのuniform location に集約されるわけではない

GLSLは構造体使えるから、お?とおもっていたのですが、実際のところは内部のメンバに対して1つずつロケーションが与えられているようです。

次回には、Uniform Blockでのリフレクションのチェックをしてみたいと思います。


最近のGLSLでは色々廃止になってる…


最近のGLSLでは結構廃止になっている部分が多い。ちょっと踏んだところをメモとして残しておきます。

varying, attribute 廃止

これは割と定番ですが、最近のGLSLでは廃止になってます。
代わりに in/out を使用して、シェーダーに対する入力、出力を記述していきます。

その割に、頂点入力としては glGetAttribLocation 使用して、頂点シェーダーの in で書かれた変数を取得するなど、APIとしてはアンバランスに感じます。

textureCUBEの廃止

キューブマップからのテクセルのサンプルで textureCUBEを使用していた部分が最近のものではコンパイルエラーとなるようです。自分の環境では以下のエラーが出力されました。

ではキューブマップからのフェッチはどうするのかというと、以下のような感じで良さそうです。

どうやらtextureCubeだけが廃止扱いではないようです。続く。

texture1D廃止

texture1D, texture1DProj, texture1DLod, texture1DProjLod が廃止になっています。代わりに texture 関数を使えとのことです。

texture2D廃止

texture2D, texture2DProj, texure2DLod, texture2DProjLod が廃止になっています。代わりに texture 関数を使えとのことです。

texture3D廃止

texture3D, texture3DProj, texture3DLod, texture3DProjLod が廃止になっています。代わりに texture 関数を使えとのことです。

shadow系の廃止

shadow1D, shadow2D, shadow1DProj, shadow2DProj, shadow1DLod, shadow2DLod, shadow1DProjLod, shadow2DProjLod が廃止になっています。

デフォルトのグローバルで使えた各変数

これらのものが廃止扱いになっています。あまり使うことはなかったかもしれませんが、たまに使われているケースがあってこのことを知らないと悩みます。
gl_FragColor もまた廃止なので注意が必要です。


OpenGL Shader subroutine を試してみた


GLSLシェーダープログラムの関数を切り替える拡張である GL_ARB_shader_subroutine を試してみました。使ってみた感想としては C言語プログラムの関数ポインタを設定して実行先を切り替える、そんなものとずいぶん近い気がします。

シェーダープログラムでは、切り替える関数の宣言、切り替えに使う変数を先に宣言しておきます。
今回はLambertとPhongのライティングを切り替えるように関数を準備してみました。

なんとなくわかるかと思いますが、先に切り替える関数そのもののプロトタイプ宣言みたいなものを行います(1行目)。そして、関数を示す変数を uniform で用意します。main関数の箇所ではこの変数を関数ポインタのようにして、実際の処理関数を呼び出します。
 切り替える関数そのものは、subroutine(プロトタイプ宣言)のような修飾を関数先頭におこなって、プログラムコードを書きます。

続いて C++ 側のコードについて説明します。uniform 変数のようにして関数ポインタもどきを用意しましたが、これは通常のuniform 変数のようにロケーションを取得できません。取得する際には、 glGetSubroutineIndex という関数を用います。また関数がどのシェーダーに実装が入っているのかを識別するためにシェーダーのタイプもまた必要になっています。

そして、このインデックスをシェーダーに対してセットすることで、処理関数が決定されます。

経過時間で関数を切り替えて描画してみたのが以下になります。

DirectXとの比較

DirectXでは、この同様の機能は、シェーダーの動的リンクというものになるのではないかと思います。DirectX11からの機能で、HLSLでインターフェースクラスを作成し、実装はその継承先でという形をとります。つまり Cスタイルで切り替えるか、C++スタイルで切り替えるかの違いでしかないようです。どちらも同じように処理自体は実現可能のように思います。


DirectX11で旧シェーダーコード(HLSL)を使う


DirectX11(DX11) は DirectX9(DX9) に対応したハードでも一応動かすことが出来ます。このとき、DX9 にのみ対応ハードで動かす場合、DX11 の機能は当然使えません。シェーダーに関しても同様で、頂点シェーダー、ピクセルシェーダーのみを使用することになります。

fxcや関連するドキュメントをみると、そういった DX9 ハード用のシェーダープロファイルとして、次のものを使用するようになっています。

  • vs_4_0_level_9_0
  • vs_4_0_level_9_1
  • vs_4_0_level_9_3
  • ps_4_0_level_9_1
  • ps_4_0_level_9_3

確かに、DirectX11 の仕様を守って新規にシェーダーファイルを作って行く場合には何の問題も無いのですが、昔からのコードを現世代で動くようにと作業している場合、これだけの指定では足りないのです。

例えば、以下のようなシェーダーファイルのコードがあったとして、これを上記のプロファイルに従い、 vs_4_0_level_9_3 でコンパイルしたとします。

これをコンパイルすると次のようにエラーが表示されます。

fxc /T vs_4_0_level_9_3 vs.hlsl

error X4541: vertex shader must minimally write all four components of SV_Position
compilation failed; no code produced

これをエラー無く、かつ、シェーダーコードを修正することなくシェーダーコンパイルを成功させるためには、/Gec オプションを指定します。

fxc /T vs_4_0_level_9_3 /Gec vs.hlsl

これで vs_4_0 系のタイプでシェーダーをコンパイルすることが出来、DirectX11 のプログラム上で使用することが可能になります。
内部的には、出力セマンティクスのPOSITION を SV_POSITION として勝手に扱ってくれるようです。コマンドラインでコンパイルした結果を見るとそんな感じに見えます。

なお、D3DX11ShaderCompileFromFile で、この “Gec” オプションに相当するものは、 D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY となるようです。

感想

意外と DirectX11 で古いシェーダーコードをそのまま使うという話はないのかな?と思いました。
調べてみても情報はほとんど出てきませんでした。
確かにDirectX11 は初心者にはちょっと手間な部分も多いですし、ある程度までなら DirectX9 を使ってしまった方が楽で、やりたいことを実現できますし。
それでもどこかで、同じように悩んだ人に、この記事が役立ってくれるといいなと思います。


D3DXでERROR_MOD_NOT_FOUND


ある環境でプログラムを動かそうとしたら、D3DXAssembleShaderFromFile 関数で ERROR_MOD_NOT_FOUND というエラーコードが返ってきた!
こんなエラーは初めてで、エラーメッセージのログも何もなくとても困った・・・。

よくよく調べてみるとこのエラーは、必要なモジュール(DLL)がロードできなくてエラーとなったことを意味しており、今回の件も、確かに強引にプログラムを動かそうとしていたことが原因となっているようでした。
DirectX の再頒布ランタイムをインストールすれば問題は解決になりそうです。

追記

さらなる調査の結果、どうやらシェーダーコンパイラである D3DCompiler_XX.dll が見つからなかったために起こった模様。
これが原因だとすると、D3DXAssembleShader系だけでなく、D3DXCompileShader系やD3DXEffect系もおそらく同じようなエラーになるだろうと推測します。


Tegra2での不具合


Tegra2でだけ特定のエラーメッセージが出てうまく動かないということに悩まされていました。調べてみても、日本じゃ該当なし、海外で報告があるけどよくわからないまま終了というやっかいな状態でした。

それが今回ようやく解決方法含めてわかったので、記事にしてみました。
戦っていたエラーメッセージは 、P1202: Texture’s gl states do not match with shader’s というものです。

エラーメッセージのタイミング

このエラーメッセージはどこで出てくるのかを調べてみると、 GL_VALIDATE_STATUS を引数に、glGetProgramiv を呼び出して、エラー時に glGetProgramInfoLog を呼び出して、その中のメッセージに格納されて表示されてくるようです。

つまり、glValidateProgram の部分がまずい!ということです。
このAPIの説明を確認すると、現在のシェーダーが正常に実行できるか検証するという意味合いのAPIとのことです。
通常は、glUseProgramした後で、 glValidateProgramで実行できるかを確認する、という使い方を想定していると思われます。決して、シェーダーのglLinkProgram後に検証というものではなさそうです。

つまり、実行するときの状態がそろった上で 検証をしなくてはなりません。
そのため、使用するテクスチャ の状態が正常か、サンプラーの状態は正しいか、などすべての条件が考慮されます。 今回引っかかってしまったのは、テクスチャを使うシェーダーで、テクスチャを設定していない(バインドしていない)状態で、glValidateProgram を呼び出してエラーとなっていました。

このメッセージで悩まされた場合には、その時の状況が何か正しくないのだと思います。設定されている各種状態を丁寧に見た方がよいと思います。
なお、Mali-400, Adreno, PowerVR あたりの ドライバではこのあたりはきちんと検証してくれないのかエラーとなることは今のところありませんでした。(故に発見がおくれた&Tegra2のバグだ!と考えてしまいました)

最後になりましたが、Javaからだとタイミングが悪くてもこれらのエラーメッセージはでないようです。


ハードウェアシャドウマップをやってみる -エラー編-


うまく行きそうで失敗

AMD RADEON 5450の環境でもハードウェアシャドウマップが使える*1というので
ちょっと試してみました。
しかしながら、DirectXのデバッグランタイムを使用すると
エラーメッセージが表示される結果となってしまい現在調査中。

同プログラムはNVIDIA製グラフィックボード使ったときには正常だったのですが。

表示されるエラーメッセージは以下のようなものです。

ちなみに、デプステクスチャは、D24S8で作成していましたが、D24X8でも同様。
D16にすると上記のメッセージは出なくなるのですが、出来ることなら24bit精度使いたいと思いますし、
いったい何が悪いのかをしばらく調査しようかと思います。

デプステクスチャ
512×512 D24S8, D24X8 エラーメッセージが出る
512×512 D16 正常

動作環境としては、Windows7(x64), Catalyst 10.7、DXSDK2009Aug を使用しています。
なお、NVIDIA環境では260.99ドライバで9800GTを用いています。

ちなみにメッセージは表示されますが、画面の描画結果は正常だったりします。エラーのメッセージさえ見られなければ、どうということは無いのかもしれません(笑

*1 : Advanced DX9 Capabilities for ATI Radeon Cards.pdfを参照してサポートの状況を確認しています。

動作チェック予定

現在の症状から、以下の変更を行ってみて症状が改善するかを試みる方針です。

  • DXSDKの更新
    • 2010Juneあたりでやってみるといいのかも
  • ドライバの更新
    • Catalyst 10.11などは安定しているという噂も(ミドルレンジはという制約ありで)
  • 動作OSの変更
    • 32bit版Win7
    • Vista, XP
    • これらの環境ではどうなのだろうか

SoftImageとリアルタイムシェーダー


はじめに

Autodesk SoftImage ModTool 7.5とリアルタイムシェーダーについて、
正常動作にはいろいろと条件がありそうなため、調べてみました。

DirectX 2006Dec以降がインストールされていることが必要です。
そのため、以下の環境は DirectX SDK 2009Augustを用いてチェックしています。
このバージョンを選択している理由は以下の環境すべてで正しく動作すると
考えられている最低バージョンのためです。

検証結果

以下の表に、DirectXランタイムとOSごとの組み合わせで、
動作状況はどうであったかをまとめてみました。

環境 ビデオボード ドライバ DX9ランタイム 動作可否
XP SP3 (x86) Geforce9800GT 260.99 Retail 正常動作
Vista Ultimate SP2 (x86) Geforce9800GT 260.99 Retail 正常動作
Vista Ultimate SP2 (x64) Geforce9800GT 258.96 Retail 正常動作
Windows7 Ultimate (x86) Geforce9800GT 260.99 Retail 正常動作
Windows7 Ultimate (x64) Geforce9800GT 260.99 Retail 正常動作
XP SP3 (x86) Geforce9800GT 260.99 Debug 動作しない
Vista Ultimate SP2 (x86) Geforce9800GT 260.99 Debug 動作しない.
Vista Ultimate SP2 (x64) Geforce9800GT 258.96 Debug 動作しない.
Windows7 Ultimate (x86) Geforce9800GT 260.99 Debug 正常動作
Windows7 Ultimate (x64) Geforce9800GT 260.99 Debug 正常動作
環境 ビデオボード ドライバ DX9ランタイム 動作可否
XP SP3 (x86) RADEON HD5450 10.11 Retail 正常動作
Vista Ultimate SP2 (x86) RADEON HD5450 10.11 Retail 正常動作
Vista Ultimate SP2 (x64) RADEON HD5450 10.11 Retail 正常動作
Windows7 Ultimate (x86) RADEON HD5450 10.11 Retail 正常動作
Windows7 Ultimate (x64) RADEON HD5450 10.11 Retail 正常動作
XP SP3 (x86) RADEON HD5450 10.11 Debug 動作しない.
Vista Ultimate SP2 (x86) RADEON HD5450 10.11 Debug 動作しない.
Vista Ultimate SP2 (x64) RADEON HD5450 10.11 Debug 動作しない.
Windows7 Ultimate (x86) RADEON HD5450 10.11 Debug 正常動作.
Windows7 Ultimate (x64) RADEON HD5450 10.11 Debug 正常動作

動作しない = ビューポートに何も表示されない状況を示します。

切り替え方法

DirectX SDKインストールすると出来るスタートメニューグループで、
“DirectX Utilities”→”DirectX Control Panel” を選択します。
そして、以下の項目のどちらかにラジオボタンで選択して、OKを押します。

  • “Use Debug Version of Direct3D9”
  • “Use Retail Version of Direct3D9”

これでDirectXランタイムが切り替わります。

なお、通常であればアプリケーションの再起動が必要なのですが、
SoftImage ModToolの場合、ビューポートの設定を切り替えるだけで、
このランタイム切り替えの効果を得ることが出来ました。

”ワイヤーフレーム” ←→ “リアルタイム/DirectX9”

の切り替えで反映させることが出来ました。

補足

64bit環境の場合には、ほんのちょっとだけ注意が必要です。
SoftImage ModToolは32bitアプリケーションなので、
使用するDirectX Control Panelも32bit版である必要があります。

まとめ

以上の結果から、まとめてみたいと思います。
RetailのDirectXランタイムを使っている状況では、
SoftImage ModTool 7.5のリアルタイムシェーダーを使うことに問題はありません。
ただし、DirectXのデバッグランタイムを使っている場合には、
環境に大きく依存するということが言えそうです。
Windows7であれば、どちらのランタイムでも動くようですが、
それ以前の環境ではDebugランタイムでの使用は壊滅的だといえます。

アーティストさんの使用する環境ではDirectX SDKがインストールされていることは稀である、と考えられているのかもしれません。
確かにプログラマ以外DirectX SDKは不要だとも思いますけど。
アーティストさんとやりとりするプログラマの人々は、
こういった挙動に対して、いろいろと知っておかなくてはならないだろうし、
大変だなぁと思いました。

余談

Vista以降でディスプレイドライバモデルが変更されました。
そのため、VistaであればDebug/Retailも関係なく動くのでは?と思っていたのですが予想を裏切られました。
Vista->Windows7は、WDDM1.1とマイナーバージョンアップとなっていますが、
仕様としてはまぁまぁの規模で変更があるので、
そのあたり対応する過程で、うまく動くようになってるのかなと考えています。


GLSLのデバッグ


GLSLをデバッグするのによいツールはないかと探してみたところ、
次のソフトウェアが見つかりました。

  • glslDevil
  • shader maker

これらについて書いてみます.

glslDevil

見た感じは、これが本命となりそうです。
手元で試してみたところ、OpenGLのAPIのトレースは行ってくれるのですが、
シェーダーのデバッグというのが行えませんでした。

最初 RADEON搭載機だから?と思い、Geforce 9800GTを搭載しているPCで試してみましたが、
こちらでも状況は変わりませんでした。(glslDevilは1.1.5を使用)

どちらの環境もNV_transform_feedbackをサポートしているので、
動作はしてくれると思ったのですが、どうにもこうにも動かずでした。

OpenGL APIを呼び出し後にInvalid Operationとなるようなものをキャッチしてくれたりするので、これ目的ではとりあえず使えそうです。
glslDevilのサイトでは、実装概念となる論文も掲載されていますし、
これを元に自作することも可能なのかなと思います。

Shader Maker

昔のDirectXのサンプルにあったEffectEditっぽい感じがします。
テキストエリアにシェーダーコードを入力して、ビルド。
そして、ビューの部分で結果を確認という感じです。

パラメータを設定する部分もGUIから出来ますし、
表示されるモデルもまた任意のものに入れ替え可能みたいなので、
シェーダーを作る、という点においてはこれでも何とかなるのかなと思います。

デバッガではないために、値を見るという部分は手作業で、カラーとして画面に出して確認、というような方法をやっていく必要があります。