web-dev-qa-db-ja.com

行列変換のOpengl順序

青い3Dボックス(上面が赤い色)があるとしましょう。

  1. ここで、glScalef(1、10、1)を呼び出します。
  2. 次に、glRotatef(90、0、1、0)を呼び出します。
  3. 次に、キューブをレンダリングします。

私が期待したのは、赤い面が画面に向かって伸びているのを見ることです(モデルのY軸に沿って)。

しかし、私が見ているのはこれです:赤い面は(予想通り)画面に面しています。ただし、ストレッチは(モデルではなく)ビュースペースのY軸で発生しています。

Z軸に沿ってスケールを設定すると、正しい結果が得られることを私は知っています。しかし、私の混乱は、Y軸を拡大してからボックスを回転させると、正しい結果が得られると思ったことです。

何が足りないのですか?

16

OpenGLは、その行列を column major order 。その結果、後続の各操作は、事後乗算ではなく、その前のすべての演算の事前乗算になります。したがって、各OpenGL操作の後続の呼び出し(glScale、glTranslate、glRotate)はfirstオブジェクトに影響を与えるものであり、それはあなたがそれを書く方法とは逆の順序になります。

したがって、乗算の順序を変更する必要があります。

glRotatef(90, 0, 1, 0); // Notice how this is the first operation ...
// ... but will be applied after
glScalef(1, 10, 1); // This will be applied first, but is the last operation
// Zany, right?

正直なところ、プログラムを作成しているときや、コンピューターを使用して逆の順序で指定する必要があるときは、直感的ではありません。しかし、グラフィックスの神々は、OpenGLのマトリックススタックがどのように動作することを望んでいたかを決定しました(HLSL、GLSL、およびその他のシステムとともに:列の主要な順序については上記のリンクを参照してください)。

23
user1357649

次のような4x4行列を表す配列がある場合:

float mat[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };

これをOpenGLマトリックスにロードすると、OpenGLは最初の4つのフロートをマトリックスの最初の列として、2番目の4つのフロートを2番目の列として、3番目の4つのフロートをマトリックスの3番目の列として表示します。

したがって、4つのフロートごとに、OpenGLは別の列と見なします。これは、列メジャーオーダーとして知られています。データを列に格納します。列優先行列を転置する必要がある場合は、最終的に行優先行列になり、その逆も同様です。

列優先行列があるため、列ベクトルも使用する必要があります。つまり、乗算の順序はM * vになります。

これを自分で証明するには、2x1列ベクトルを持つ単純な2x2行列を取り、M * vとして乗算します。 K = transpose(M)、r =行ベクトル(1x2)とします。

次にM * v = r * K

結論として、コードで列または行のメジャー表記を使用すると、それに固執する必要があります。

0
Michael