スポンサーリンク

glRotatefを自前実装する

glRotatefが作成する行列

C/C++の配列にした場合

C++で実装

ソースコード

#include <cmath>

namespace nu {

  typedef float real_t;

  inline real_t to_radian(real_t degree) {
    return degree * (real_t)3.14159265358979 / (real_t)180.0;
  }

  //! @brief 回転行列作成
  //! @param [out] m 結果を格納する要素数16の配列
  //! @param [in] angle_degree 回転角を度で指定
  //! @param [in] x 回転軸のX成分
  //! @param [in] y 回転軸のY成分
  //! @param [in] z 回転軸のZ成分
  //! @return なし
  void myrotate(
    real_t* m,
    real_t angle_degree,
    real_t x,
    real_t y,
    real_t z) {

    //len(x y z) != 0ならnormalizeする
    real_t len = sqrt(x * x + y * y + z * z);
    if (abs(1.0 - len) > 0.000001) {
      x = x / len;
      y = y / len;
      z = z / len;
    }


    real_t angle_rad = to_radian(angle_degree);

    real_t c = std::cos(angle_rad);
    real_t s = std::sin(angle_rad);

    m[0] = x * x * (1 - c) + c;
    m[1] = y * x * (1 - c) + z * s;
    m[2] = x * z * (1 - c) - y * s;
    m[3] = 0.0;

    m[4] = x * y * (1 - c) - z * s;
    m[5] = y * y * (1 - c) + c;
    m[6] = y * z * (1 - c) + x * s;
    m[7] = 0.0;


    m[8] = x * z * (1 - c) + y * s;
    m[9] = y * z * (1 - c) - x * s;
    m[10] = z * z * (1 - c) + c;
    m[11] = 0.0;


    m[12] = 0.0;
    m[13] = 0.0;
    m[14] = 0.0;
    m[15] = 1.0;

  }

}

テスト用コード

#include <windows.h>
#include <gl/GLU.h>
#include <gl/freeglut.h>
#include <cstdio>

//検証用
#include <cassert>

//自前実装版glRotate
#include "myrotate.h"

#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"glu32.lib")
#pragma comment(lib,"freeglut.lib")

void display(void)
{
  
  GLfloat glrmat[16]; //gl関数で生成
  GLfloat myrmat[16]; //自分関数で生成

  //glRotate,myrotateへの入力の値を色々変える
  static int i = 0;
  i++;

  GLfloat x = 1.0+i;
  GLfloat y = 1.0 * (i * 0.1);
  GLfloat z = 1.0 * (i / 0.2);
  GLfloat angle=i+25;


  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  //openglで計算
  glRotatef(angle, x, y, z);
  glGetFloatv(GL_MODELVIEW_MATRIX, glrmat);

  //自前計算
  nu::myrotate(myrmat,angle,x,y,z);

  puts("----------------------------------------------");
  printf("** %d :: %lf %lf %lf %lf\n", i,angle,x,y,z);
  for (int k = 0; k < 16; k++) {
    //比較
    printf("m[%2d] %+5.10lf %+5.10lf \n", k, glrmat[k], myrmat[k]);

    //自前計算とglRotate計算の値があまりにかけ離れていたらassertで落ちる
    assert(abs(glrmat[k] - myrmat[k]) < 0.0001);

  }
  puts("----------------------------------------------");

}
void mouse(int button, int state, int x, int y) {
  display();
}

int main(int argc, char* argv[])
{

  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGBA);
  glutCreateWindow(argv[0]);
  glutInitWindowPosition(0, 0);
  glutInitWindowSize(100,100);
  glutDisplayFunc(display);
  glutMouseFunc(mouse);
  glutMainLoop();

  return 0;

}

テスト結果

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: