強火で進め

このブログではプログラム関連の記事を中心に書いてます。

現在の行列の値を取得する

OpenGLではプロジェクション(射影)変換行列(GL_PROJECTION)、モデル座標変換行列(GL_MODELVIEW)など複数の行列を使います。
どの行列で検証しても良いのですがここでは主に使用する行列である、モデル座標変換行列の値を取得してみます。

プログラムの主な部分は以下の様になります。

    GLfloat m[16];
    glMatrixMode(GL_MODELVIEW);
    
    // 正規化したとき
    glLoadIdentity();
    glGetFloatv(GL_MODELVIEW_MATRIX, m);
    printf("正規化\n");
    printf("m[0]:% 7.5f m[4]:% 7.5f m[8] :% 7.5f m[12]:% 7.5f\n", m[0], m[4], m[8],  m[12]);
    printf("m[1]:% 7.5f m[5]:% 7.5f m[9] :% 7.5f m[13]:% 7.5f\n", m[1], m[5], m[9],  m[13]);
    printf("m[2]:% 7.5f m[6]:% 7.5f m[10]:% 7.5f m[14]:% 7.5f\n", m[2], m[6], m[10], m[14]);
    printf("m[3]:% 7.5f m[7]:% 7.5f m[11]:% 7.5f m[16]:% 7.5f\n", m[3], m[7], m[11], m[15]);
    // 移動
    glLoadIdentity();
    glTranslatef(2.0f, 3.0f, 5.0f);
    glGetFloatv(GL_MODELVIEW_MATRIX, m);
    printf("移動\n");
    printf("m[0]:% 7.5f m[4]:% 7.5f m[8] :% 7.5f m[12]:% 7.5f\n", m[0], m[4], m[8],  m[12]);
    printf("m[1]:% 7.5f m[5]:% 7.5f m[9] :% 7.5f m[13]:% 7.5f\n", m[1], m[5], m[9],  m[13]);
    printf("m[2]:% 7.5f m[6]:% 7.5f m[10]:% 7.5f m[14]:% 7.5f\n", m[2], m[6], m[10], m[14]);
    printf("m[3]:% 7.5f m[7]:% 7.5f m[11]:% 7.5f m[16]:% 7.5f\n", m[3], m[7], m[11], m[15]);
    // 拡大・縮小
    glLoadIdentity();
    glScalef(2.0f, 0.5f, 1.5f);
    glGetFloatv(GL_MODELVIEW_MATRIX, m);
    printf("拡大・縮小\n");
    printf("m[0]:% 7.5f m[4]:% 7.5f m[8] :% 7.5f m[12]:% 7.5f\n", m[0], m[4], m[8],  m[12]);
    printf("m[1]:% 7.5f m[5]:% 7.5f m[9] :% 7.5f m[13]:% 7.5f\n", m[1], m[5], m[9],  m[13]);
    printf("m[2]:% 7.5f m[6]:% 7.5f m[10]:% 7.5f m[14]:% 7.5f\n", m[2], m[6], m[10], m[14]);
    printf("m[3]:% 7.5f m[7]:% 7.5f m[11]:% 7.5f m[16]:% 7.5f\n", m[3], m[7], m[11], m[15]);
    // X軸回転
    glLoadIdentity();
    glRotatef(30.0f, 1.0f, 0.0f, 0.0f);
    glGetFloatv(GL_MODELVIEW_MATRIX, m);
    printf("X軸回転\n");
    printf("m[0]:% 7.5f m[4]:% 7.5f m[8] :% 7.5f m[12]:% 7.5f\n", m[0], m[4], m[8],  m[12]);
    printf("m[1]:% 7.5f m[5]:% 7.5f m[9] :% 7.5f m[13]:% 7.5f\n", m[1], m[5], m[9],  m[13]);
    printf("m[2]:% 7.5f m[6]:% 7.5f m[10]:% 7.5f m[14]:% 7.5f\n", m[2], m[6], m[10], m[14]);
    printf("m[3]:% 7.5f m[7]:% 7.5f m[11]:% 7.5f m[16]:% 7.5f\n", m[3], m[7], m[11], m[15]);
    // Y軸回転
    glLoadIdentity();
    glRotatef(30.0f, 0.0f, 1.0f, 0.0f);
    glGetFloatv(GL_MODELVIEW_MATRIX, m);
    printf("Y軸回転\n");
    printf("m[0]:% 7.5f m[4]:% 7.5f m[8] :% 7.5f m[12]:% 7.5f\n", m[0], m[4], m[8],  m[12]);
    printf("m[1]:% 7.5f m[5]:% 7.5f m[9] :% 7.5f m[13]:% 7.5f\n", m[1], m[5], m[9],  m[13]);
    printf("m[2]:% 7.5f m[6]:% 7.5f m[10]:% 7.5f m[14]:% 7.5f\n", m[2], m[6], m[10], m[14]);
    printf("m[3]:% 7.5f m[7]:% 7.5f m[11]:% 7.5f m[16]:% 7.5f\n", m[3], m[7], m[11], m[15]);
    // Z軸回転
    glLoadIdentity();
    glRotatef(30.0f, 0.0f, 0.0f, 1.0f);
    glGetFloatv(GL_MODELVIEW_MATRIX, m);
    printf("Z軸回転\n");
    printf("m[0]:% 7.5f m[4]:% 7.5f m[8] :% 7.5f m[12]:% 7.5f\n", m[0], m[4], m[8],  m[12]);
    printf("m[1]:% 7.5f m[5]:% 7.5f m[9] :% 7.5f m[13]:% 7.5f\n", m[1], m[5], m[9],  m[13]);
    printf("m[2]:% 7.5f m[6]:% 7.5f m[10]:% 7.5f m[14]:% 7.5f\n", m[2], m[6], m[10], m[14]);
    printf("m[3]:% 7.5f m[7]:% 7.5f m[11]:% 7.5f m[16]:% 7.5f\n", m[3], m[7], m[11], m[15]);
    
#define DEGREES_TO_RADIANS(__ANGLE__) ((__ANGLE__) / 180.0 * M_PI)
    printf("\n");
    printf("%f\n", sin(DEGREES_TO_RADIANS(30.0)));
    printf("%f\n", cos(DEGREES_TO_RADIANS(30.0)));

出力データの確認

正規化
m[0]: 1.00000 m[4]: 0.00000 m[8] : 0.00000 m[12]: 0.00000
m[1]: 0.00000 m[5]: 1.00000 m[9] : 0.00000 m[13]: 0.00000
m[2]: 0.00000 m[6]: 0.00000 m[10]: 1.00000 m[14]: 0.00000
m[3]: 0.00000 m[7]: 0.00000 m[11]: 0.00000 m[16]: 1.00000

きちんと正規化され、m[0]、m[5]、m[10]、m[16]が1.0、それ以外が0.0になっていることが確認できます。

移動

m[0]: 1.00000 m[4]: 0.00000 m[8] : 0.00000 m[12]: 2.00000
m[1]: 0.00000 m[5]: 1.00000 m[9] : 0.00000 m[13]: 3.00000
m[2]: 0.00000 m[6]: 0.00000 m[10]: 1.00000 m[14]: 5.00000
m[3]: 0.00000 m[7]: 0.00000 m[11]: 0.00000 m[16]: 1.00000
glTranslatef(2.0f, 3.0f, 5.0f);

glTranslatef()で指定した値が以下の位置に確認できます。
m[12] → X方向の移動量
m[13] → Y方向の移動量
m[14] → Z方向の移動量

拡大・縮小

m[0]: 2.00000 m[4]: 0.00000 m[8] : 0.00000 m[12]: 0.00000
m[1]: 0.00000 m[5]: 0.50000 m[9] : 0.00000 m[13]: 0.00000
m[2]: 0.00000 m[6]: 0.00000 m[10]: 1.50000 m[14]: 0.00000
m[3]: 0.00000 m[7]: 0.00000 m[11]: 0.00000 m[16]: 1.00000
glScalef(2.0f, 0.5f, 1.5f);

glScalef()で指定した値が以下の位置に確認できます。
m[0] → X方向の拡大・縮小
m[5] → Y方向の拡大・縮小
m[10] → Z方向の拡大・縮小

X軸回転

m[0]: 1.00000 m[4]: 0.00000 m[8] : 0.00000 m[12]: 0.00000
m[1]: 0.00000 m[5]: 0.86603 m[9] :-0.50000 m[13]: 0.00000
m[2]: 0.00000 m[6]: 0.50000 m[10]: 0.86603 m[14]: 0.00000
m[3]: 0.00000 m[7]: 0.00000 m[11]: 0.00000 m[16]: 1.00000

sin 30° → 0.500000
cos 30° → 0.866025

X軸回転する時の行列になります。
\(\array{\\{1}&{0}&{0}&{0}\\{0}&{\cos\theta}&{-\sin\theta}&{0}\\{0}&{\sin\theta}&{\cos\theta}&{0}\\{0}&{0}&{0}&{1}}\)

Y軸回転

m[0]: 0.86603 m[4]: 0.00000 m[8] : 0.50000 m[12]: 0.00000
m[1]: 0.00000 m[5]: 1.00000 m[9] : 0.00000 m[13]: 0.00000
m[2]:-0.50000 m[6]: 0.00000 m[10]: 0.86603 m[14]: 0.00000
m[3]: 0.00000 m[7]: 0.00000 m[11]: 0.00000 m[16]: 1.00000

sin 30° → 0.500000
cos 30° → 0.866025

Y軸回転する時の行列になります。
\(\array{\\{\cos\theta}&{0}&{\sin\theta}&{0}\\{0}&{1}&{0}&{0}\\{-\sin\theta}&{0}&{\cos\theta}&{0}\\{0}&{0}&{0}&{1}}\)

Z軸回転

m[0]: 0.86603 m[4]:-0.50000 m[8] : 0.00000 m[12]: 0.00000
m[1]: 0.50000 m[5]: 0.86603 m[9] : 0.00000 m[13]: 0.00000
m[2]: 0.00000 m[6]: 0.00000 m[10]: 1.00000 m[14]: 0.00000
m[3]: 0.00000 m[7]: 0.00000 m[11]: 0.00000 m[16]: 1.00000

sin 30° → 0.500000
cos 30° → 0.866025

Z軸回転する時の行列になります。
\(\array{\\{\cos\theta}&{-\sin\theta}&{0}&{0}\\{\sin\theta}&{\cos\theta}&{0}&{0}\\{0}&{0}&{1}&{0}\\{0}&{0}&{0}&{1}}\)

なお、今回説明した行列と異なる記述で移動や回転行列が記述されてることをWebや書籍で見かける場合もよく有ると思います。

これはOpenGLDirectXではベクトルと行列との計算が異なることに起因します。

そのためDirectX向けに記述された移動や回転行列はOpenGLで使う場合、互いに転置行列の関係となります。

詳しくは以下のサイトの「4−1.行列の積算順序」などを参照下さい。

OpenGL / DirectXにおける3D基礎概念の対比
http://sequoia-web.hp.infoseek.co.jp/tsudoi/tsudoi06.shtml

また、こちらの行列の解説も分かり易くておすすめです。

OpenGL勉強会用 資料のページ
http://www.is.oit.ac.jp/~whashimo/server/~whashimo/Article/OpenGL/Chapter3/index.html#Section2

OpenGLのプログラムをしているとたまに3Dモデルが正しく移動や回転をしない場合があります。
どうしても原因がみつからない場合、今回行ったような行列の表示を途中途中に差し込み、デバック行う事も可能です。