[トップページ] [星雲紀行] [MLXS] [WPGen] [自作音楽] [モデル] [vi/vim] [tips] [自己紹介]

OpenGL 行列演算

目次

  1. はじめに
  2. 行列初期化
  3. 行列コピー
  4. 行列乗算
  5. アフィン変換
  6. 平行移動
  7. スケーリング
  8. 回転
  9. 法線の生成
  10. billboard
  11. 参考文献・参考ウェブページ
  12. 履歴

はじめに

OpenGL の行列演算についてのメモを記載しています。
2 次元配列を使用せず、4x4 の要素をメモリ上に配置して使っている。

[目次]

tips

  • 現在の透視変換行列とモデルビュー変換行列を得る
    GLdouble model[16], proj[16];
    glGetDoublev(GL_MODELVIEW_MATRIX, model);
    glGetDoublev(GL_PROJECTION_MATRIX, proj);
    参考

[content]

行列初期化

void InitMatrix(float &m)
{
	for(int i=0; i<16; i++)
	{
		m[i] = 0.0f;
	}
	m[0+4*0] = 1.0f;
	m[1+4*1] = 1.0f;
	m[2+4*2] = 1.0f;
	m[3+4*3] = 1.0f;
	
	return;
}
[content]

行列コピー

void CopyMatrix(float &dst, const float &src)
{
	for(int i=0; i<16; i++)
	{
		dst[i] = src[i];
	}
	
	return;
}
[content]

行列乗算

void MultMatrix(float &dst, const float &src1, const float &src2)
{
	for(int i=0; i<16; i++)
	{
		double sum = 0.0f;
		for(int j=0; j<4; j++)
		{
			sum += src1[i%4*4 + j] * src2[j*4 + i>>2];
		}
		dst[i] = sum;
	}
	
	return;
}
[content]

アフィン変換

アフィン変換。
参考ウェブページ
アフィン変換を自前のマトリクスで実行するためには

void glMatrixMode(GLenum mode);
を使用し、マトリクスモード(OpenGL が持っている行列のスタック)を指定する。
定数 ターゲット
GL_MODELVIEW モデルビュー行列
GL_PROJECTION 射影行列
GL_TEXTURE テクスチャ行列

現在の行列を調べるには
GLfloat model_view[4][4];
glGetFloatv( GL_MODELVIEW_MATRIX, &model_view[0][0] );
現在の行列を、任意の行列に置き換えるには
void glLoadMatrixf(&model_view[0][0]);
double 精度なら
void glLoadMatrixd(&model_view_d[0][0]);
注) 以下は右から行列をかけているのでOpenGL ではなくDirect X
OpenGL は左から。
拡大縮小
	                          [ Sx  0   0  0 ]
	[X' Y' Z' W'] = [X Y Z 1] [  0  Sy  0  0 ]
	                          [  0  0   Sz 0 ]
	                          [  0  0   0  1 ]

	X' = X * Sx;
	Y' = Y * Sy;
	Z' = Z * Sz;
	
X 回転
	                          [ 1    0      0    0 ]
	[X' Y' Z' W'] = [X Y Z 1] [ 0  cosθx sinθx 0 ]
	                          [ 0 -sinθx cosθx 0 ]
	                          [ 0    0      0    1 ]

	X' = X;
	Y' = Y * cosθx - Z * sinθx;
	Z' = Y * sinθx + Z * cosθx;
	
Y 回転
	                          [ cosθy 0 -sinθy 0 ]
	[X' Y' Z' W'] = [X Y Z 1] [   0    1    0    0 ]
	                          [ sinθy 0  cosθy 0 ]
	                          [   0    0    0    1 ]

	X' =  X * cosθy + Z * sinθy;
	Y' =  Y;
	Z' = -X * sinθy + Z * cosθy;
	
Z 回転
	                           [  cosθz sinθz 0  0 ]
	[X' Y' Z' W'] =  [X Y Z 1] [ -sinθz cosθz 0  0 ]
	                           [    0      0    1  0 ]
	                           [    0      0    0  1 ]

	X' = X * cosθz - Y * sinθz;
	Y' = X * sinθz + Y * cosθz;
	Z' = Z;
	
注) 上記の回転マトリクスは通常ひとつずつは呼ばれない。
XYZ 軸それぞれのマトリクスをあらかじめ乗算したマトリクスを 使用する。
インプリ例は glRotatef() など。

以下のマトリクスはすべてfloat [16] の大きさで演算する。
[content]

平行移動

void Translate(float &m, const float x_trans, const float y_trans, const float z_trans)
{
    float m1[16];
    float m2[16];
    
    m1[0*4 + 0] = 1.0f;     m1[0*4 + 1] = 0.0f;     m1[0*4 + 2] = 0.0f;     m1[0*4 + 3] = 0.0f;
    m1[1*4 + 0] = 0.0f;     m1[1*4 + 1] = 1.0f;     m1[1*4 + 2] = 0.0f;     m1[1*4 + 3] = 0.0f;
    m1[2*4 + 0] = 0.0f;     m1[2*4 + 1] = 0.0f;     m1[2*4 + 2] = 1.0f;     m1[2*4 + 3] = 0.0f;
    m1[3*4 + 0] = x_trans;  m1[3*4 + 1] = y_trans;  m1[3*4 + 2] = z_trans;  m1[3*4 + 3] = 1.0f;

    MultMatrix(m2, m1, m);
    CopyMatrix(m, m2);

    return;
}
[content]

スケーリング

void Scale(float &m, const float x_scale, const float y_scale, const float z_scale)
{
    float m1[16];
    float m2[16];
    
    m1[0*4 + 0] = x_scale;  m1[0*4 + 1] = 0.0f;     m1[0*4 + 2] = 0.0f;     m1[0*4 + 3] = 0.0f;
    m1[1*4 + 0] = 0.0f;     m1[1*4 + 1] = y_scale;  m1[1*4 + 2] = 0.0f;     m1[1*4 + 3] = 0.0f;
    m1[2*4 + 0] = 0.0f;     m1[2*4 + 1] = 0.0f;     m1[2*4 + 2] = z_scale;  m1[2*4 + 3] = 0.0f;
    m1[3*4 + 0] = 0.0f;     m1[3*4 + 1] = 0.0f;     m1[3*4 + 2] = 0.0f;     m1[3*4 + 3] = 1.0f;

    MultMatrix(m2, m1, m);
    CopyMatrix(m, m2);

    return;
}
[content]

z 回転

void RotateZ(float &m, const float z_angle)
{
    float m1[16];
    float m2[16];
    
    double radians = 6.283185308f / (360.0f / z_angle);
    double s = sin(radians);
    double c = cos(radians);

    m1[0*4 + 0] = c;        m1[0*4 + 1] = s;        m1[0*4 + 2] = 0.0f;     m1[0*4 + 3] = 0.0f;
    m1[1*4 + 0] = -s;       m1[1*4 + 1] = c;        m1[1*4 + 2] = 0.0f;     m1[1*4 + 3] = 0.0f;
    m1[2*4 + 0] = 0.0f;     m1[2*4 + 1] = 0.0f;     m1[2*4 + 2] = 1.0f;     m1[2*4 + 3] = 0.0f;
    m1[3*4 + 0] = 0.0f;     m1[3*4 + 1] = 0.0f;     m1[3*4 + 2] = 0.0f;     m1[3*4 + 3] = 1.0f;

    MultMatrix(m2, m1, m);
    CopyMatrix(m, m2);

    return;
}
[content]

x 回転

void RotateX(float &m, const float x_angle)
{
    float m1[16];
    float m2[16];
    
    double radians = 6.283185308f / (360.0f / z_angle);
    double s = sin(radians);
    double c = cos(radians);

    m1[0*4 + 0] = 1.0f;     m1[0*4 + 1] = 0.0f;     m1[0*4 + 2] = 0.0f;     m1[0*4 + 3] = 0.0f;
    m1[1*4 + 0] = 0.0f;     m1[1*4 + 1] = c;        m1[1*4 + 2] = s;        m1[1*4 + 3] = 0.0f;
    m1[2*4 + 0] = 0.0f;     m1[2*4 + 1] = -s;       m1[2*4 + 2] = c;        m1[2*4 + 3] = 0.0f;
    m1[3*4 + 0] = 0.0f;     m1[3*4 + 1] = 0.0f;     m1[3*4 + 2] = 0.0f;     m1[3*4 + 3] = 1.0f;

    MultMatrix(m2, m1, m);
    CopyMatrix(m, m2);

    return;
}
[content]

y 回転

void RotateY(float &m, const float y_angle)
{
    float m1[16];
    float m2[16];
    
    double radians = 6.283185308f / (360.0f / y_angle);
    double s = sin(radians);
    double c = cos(radians);

    m1[0*4 + 0] = c;        m1[0*4 + 1] = 0.0f;     m1[0*4 + 2] = -s;       m1[0*4 + 3] = 0.0f;
    m1[1*4 + 0] = 0.0f;     m1[1*4 + 1] = 1.0f;     m1[1*4 + 2] = 0.0f;     m1[1*4 + 3] = 0.0f;
    m1[2*4 + 0] = s;        m1[2*4 + 1] = 0.0f;     m1[2*4 + 2] = c;        m1[2*4 + 3] = 0.0f;
    m1[3*4 + 0] = 0.0f;     m1[3*4 + 1] = 0.0f;     m1[3*4 + 2] = 0.0f;     m1[3*4 + 3] = 1.0f;

    MultMatrix(m2, m1, m);
    CopyMatrix(m, m2);

    return;
}
[content]

統合された回転

T.B.D
void Rotate(float &m, const float x_angle, const float y_angle, const float z_angle)
{
    float m1[16];
    float m2[16];
    
    double radians = 6.283185308f / (360.0f / y_angle);
    double s = sin(radians);
    double c = cos(radians);

    m1[0*4 + 0] = c;        m1[0*4 + 1] = 0.0f;     m1[0*4 + 2] = -s;       m1[0*4 + 3] = 0.0f;
    m1[1*4 + 0] = 0.0f;     m1[1*4 + 1] = 1.0f;     m1[1*4 + 2] = 0.0f;     m1[1*4 + 3] = 0.0f;
    m1[2*4 + 0] = s;        m1[2*4 + 1] = 0.0f;     m1[2*4 + 2] = c;        m1[2*4 + 3] = 0.0f;
    m1[3*4 + 0] = 0.0f;     m1[3*4 + 1] = 0.0f;     m1[3*4 + 2] = 0.0f;     m1[3*4 + 3] = 1.0f;

    MultMatrix(m2, m1, m);
    CopyMatrix(m, m2);

    return;
}
[content]

法線の生成

法線は2 ベクトルの外積で算出するのが効率的。
Triangle ポリゴンの位置情報があれば法線は算出できる。

VectorA OuterProduct VectorB = NormalVectorOfVectorAAndVectorB
参考 http://cuemol.sourceforge.jp/ja/index.php?Documents%2FSASCut
[content]

billboard

billboard 定石。
memo。

  1. プロジェクションマトリクス取得。
  2. 逆行列で持っておく。
  3. カスタム行列として行列スタックに入れる。
// 描画に使用する頂点情報
Direct3D::CustomVertex::PositionColoredTextured vertices[]
= new Direct3D::CustomVertex::PositionColoredTextured __gc [4];
Matrix matView = pDevice->Transform->View; // ビュー変換の行列を取得
matView.M41 = matView.M42 = matView.M43 = 0; // 回転成分を無効にする
matView.Invert(); // 逆行列にする
Vector4 v; // 座標変換に使用する 4 次元ベクトル
M$ 参考サイト
[目次]

参考文献・参考ウェブページ

参考文献

参考ウェブページ

[目次]

履歴

  • 2006/07/08 初版(分岐版)作成
[目次]
ご意見、ご感想、誤字、間違い等、お気づきの点がありましたら KGussan@Gmail.com まで連絡ください。
このウェブページの注意・免責事項 Copyright (C) 2004-2012 KGussan. [トップページ]
[PR:元国税局勤務の起業家向け、遺産相続の相談なら植村洋税理士事務所:一時間無料税理士相談。お気軽に。]