Wednesday, June 28, 2017

[HLSL] シェーダ内に定数を定義したつもりだが値が割り当てられない問題

HLSLでは関数の外に変数を値付きで記述ができますが、この宣言だけでは見た目に反して変数から正常に値を読み出すことができず、エラーも出ません。
float3 lightPosition = { 100, 0, 1000 }; // This makes an implicit constant buffer, but the light position never assigned!
float3 CalcLightDir(float3 myPosition)
{
return normalize(lightPosition - myPosition);
}
view raw wrong.hlsl hosted with ❤ by GitHub
C++側から値を変更するつもりが無いならstaticをつけることで定数になり、意図通り動作します。(constではないです)
static float3 lightPosition = { 100, 0, 1000 }; // 'static' needed. not 'const'!
float3 CalcLightDir(float3 myPosition)
{
return normalize(lightPosition - myPosition);
}
view raw correct.hlsl hosted with ❤ by GitHub
staticを付けなかった場合、NSIGHT等で見ると暗黙のコンスタントバッファが生成されることがわかります。ところが肝心の値が代入されず、0で埋まっています。なぜ文法的に許容されるか不可解に思えるところですが、今は非推奨となったD3DX11Effectを使うと、暗黙のコンスタントバッファに宣言通りの値を代入してくれます。(そして、D3DX11Effect::Applyを呼ぶと内部でVSSetConstantBuffers、PSSetConstantBuffers等の呼び出しまでしてくれます)

コードをモダン化するためにD3DX11Effectを取り除く作業中に分かり難いバグに遭遇したら、暗黙のコンスタントバッファがないか確認してみると良いかもしれません。