対して、OpenGLはちょうどDirectXの行列を転置したもので、移動が4列目に来ます。
ところが、行列をfloat型16個の配列として見てみると、両者のメモリレイアウトは全く同じです。
例えばXMMatrixLookAtRHで生成したビュー行列をgluLookAtと置き換える正常に動作します。OpenGLはcolumn major(列優先)で、DirectXはrow major(行優先)なので、数学的に1回、メモリレイアウトで1回、2回転置してメモリレイアウトが同じになったと見ることもできます。
DirectX:
この並びはシェーダーを書く時の慣習にもなっていて、多くの参考書はこの順で書かれているはずです。両者のメモリレイアウトは同じはずなので、掛け算の順番が違うということは、GLSLはcolumn major、HLSLはrow majorの並びと推測できます。
ところが、GLSLもHLSLもcolumn majorがデフォルトになっています。OpenGLはC/C++側もGLSLもcolumn majorなので良いのですが、DirectXはC/C++側がrow major、HLSLがcolumn majorと異なっています。
しかし、これはおかしいです。row majorではないと、
として正しい結果が得られないはずだからです。どうも、DirectXはシェーダに行列を渡す時点で転置させる習慣があったようで、結果としてこの順で掛け算して正しくなっていました。おそらく、DirectX9時代はD3DXあたりで勝手にやってくれたのでプログラマが気にする必要が無かったのだと思います。
しかし、DirectX11はConstant Bufferの配置までプログラマに委ねられているので、理解して使う必要があります。実は、DirectX11ではOpenGLと同じように、
の順で掛けると正しい結果になります。あるいはHLSLで行列を宣言するときにrow_majorを指定すると、
この従来の順で計算しても正しくなります。
No comments:
Post a Comment