スポンサーリンク

gluLookAtの自前実装

以下の式をそのまま実装する。

https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluLookAt.xml

 

プログラム本体

#include <gl/GLU.h>

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

#pragma warning(disable:4996)
//! @brief IxJ行列の i,j の要素にアクセスする
 //! @param [in] i 行番号
 //! @param [in] j 列番号
 //! @param [in] I 行数
inline int matijI(const int i, const int j, const int I) {
  return i + I * j;
}
//! @brief IxJ行列 × JxK行列 の乗算関数
//https://suzulang.com/cpp-multmatrix44/
//! @param [out] C Cik 計算結果格納先
//! @param [in] A Aijの行列
//! @param [in] B Bjkの行列
//! @param [in] I Aの行列の行数
//! @param [in] J Aの行列の列数
//! @param [in] K Bの行列の列数
//! @return C
template<
  typename real_tC,
  typename real_tA,
  typename real_tB>
real_tC* mult_matrixIJK(real_tC* C, const real_tA* A, const real_tB* B, const int I, const int J, const int K) {

  for (int i = 0; i < I; i++)
    for (int k = 0; k < K; k++) {
      C[matijI(i, k, I)] = 0.0;
      for (int j = 0; j < J; j++) {
        C[matijI(i, k, I)] += A[matijI(i, j, I)] * B[matijI(j, k, J)];
      }
    }

  return C;
}
//! @brief 4x4行列の行列の積を計算する
//! @param [out] C 結果の格納先
//! @param [in] A 行列A
//! @param [in] B 行列B
//! @return Cへのポインタ
template<
  typename real_tC,
  typename real_tA,
  typename real_tB>
real_tC* mult_matrix44(
    real_tC* C,
    const real_tA* A,
    const real_tB* B){
  return mult_matrixIJK(C, A, B, 4, 4, 4);
}
//! @brief 移動行列を作成する
//! @param [out] m 結果の格納先
//! @param [in] x ベクトルのx成分
//! @param [in] y ベクトルのy成分
//! @param [in] z ベクトルのz成分
//! @return なし
template<typename real_t>
void mytranslate(
  real_t* m,
  real_t x,
  real_t y,
  real_t z
) {
  m[0] = 1.0;
  m[1] = 0.0;
  m[2] = 0.0;
  m[3] = 0.0;

  m[4] = 0.0;
  m[5] = 1.0;
  m[6] = 0.0;
  m[7] = 0.0;

  m[8] = 0.0;
  m[9] = 0.0;
  m[10] = 1.0;
  m[11] = 0.0;

  m[12] = x;
  m[13] = y;
  m[14] = z;
  m[15] = 1.0;

}
//! @brief 単位行列を作成する
//! @param [out] m 結果の格納先
//! @return なし
template<typename real_t>
inline void loadidentity3(real_t* m){
  m[0] = 1.0;
  m[1] = 0.0;
  m[2] = 0.0;
  m[3] = 0.0;

  m[4] = 0.0;
  m[5] = 1.0;
  m[6] = 0.0;
  m[7] = 0.0;

  m[8] = 0.0;
  m[9] = 0.0;
  m[10] = 1.0;
  m[11] = 0.0;

  m[12] = 0;
  m[13] = 0;
  m[14] = 0;
  m[15] = 1.0;
}
//! @brief 配列にNANが入っているか確認
//! @param [in] m 評価する配列
//! @param [in] count 行列の要素数
template<typename real_t>
bool chek_array_nan(const real_t* m, const size_t count) {
  for (size_t i = 0; i < count; i++) {
    if (isnan(m[i]) == true)
      return true;
  }
  return false;
}
template<typename real_t>
inline void Outer3(real_t* const dvec, real_t const* const svec1, real_t const* const svec2) {

  const real_t& x1 = svec1[0];
  const real_t& y1 = svec1[1];
  const real_t& z1 = svec1[2];
  const real_t& x2 = svec2[0];
  const real_t& y2 = svec2[1];
  const real_t& z2 = svec2[2];

  dvec[0] = static_cast<real_t>(y1 * z2 - z1 * y2);
  dvec[1] = static_cast<real_t>(z1 * x2 - x1 * z2);
  dvec[2] = static_cast<real_t>(x1 * y2 - y1 * x2);
}
template<typename real_t>
real_t Inner3(real_t const* const vec1, real_t const* const vec2) {
  const int X = 0;
  const int Y = 1;
  const int Z = 2;
  return ((vec1[X]) * (vec2[X]) + (vec1[Y]) * (vec2[Y]) + (vec1[Z]) * (vec2[Z]));
}
template<typename real_t>
real_t Length3(const real_t* const vec) {
  const int X = 0;
  const int Y = 1;
  const int Z = 2;
  return sqrt(vec[X] * vec[X] + vec[Y] * vec[Y] + vec[Z] * vec[Z]);
}
template<typename real_t>
bool Normalize3(real_t * const pV)
{

  const int X = 0;
  const int Y = 1;
  const int Z = 2;

  real_t len;
  real_t& x = pV[X];
  real_t& y = pV[Y];
  real_t& z = pV[Z];

  len = static_cast<real_t>(sqrt(x * x + y * y + z * z));

  if (len < static_cast<real_t>(1e-6)) return false;

  len = static_cast<real_t>(1.0) / len;
  x *= len;
  y *= len;
  z *= len;

  return true;
}

//! @brief gluLookAtの自前実装版 //! @param [out] M 結果の格納先 //! @param [out] eyeX カメラ位置 //! @param [out] eyeY カメラ位置 //! @param [out] eyeZ カメラ位置 //! @param [out] centerX //! @param [out] centerY //! @param [out] centerZ //! @param [out] upX //! @param [out] upY //! @param [out] upZ //! @return なし
void
myglulookat( GLdouble* M, GLdouble eyeX, GLdouble eyeY, GLdouble eyeZ, GLdouble centerX, GLdouble centerY, GLdouble centerZ, GLdouble upX, GLdouble upY, GLdouble upZ) { GLdouble f[3] = { centerX - eyeX, centerY - eyeY, centerZ - eyeZ }; Normalize3(f); GLdouble UP[3] = {upX,upY,upZ}; Normalize3(UP); GLdouble s[3]; Outer3(s, f, UP); Normalize3(s); GLdouble u[3]; Outer3(u, s, f); GLdouble M0[16]; M0[ 0] = s[0]; M0[ 1] = u[0]; M0[ 2] = -f[0]; M0[ 3] = 0; M0[ 4] = s[1]; M0[ 5] = u[1]; M0[ 6] = -f[1]; M0[ 7] = 0; M0[ 8] = s[2]; M0[ 9] = u[2]; M0[10] = -f[2]; M0[11] = 0; M0[12] = 0; M0[13] = 0; M0[14] = 0; M0[15] = 1; ///////////////////////////// ///////////////////////////// GLdouble E[16]; mytranslate(E, -eyeX, -eyeY, -eyeZ); mult_matrix44(M, M0, E); if (chek_array_nan(M, 16) == true) loadidentity3(M); }

テスト用コード

void test() {
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  GLdouble ex = (rand() % 1000) / 1000.0 - 0.5;
  GLdouble ey = (rand() % 1000) / 1000.0 - 0.5;
  GLdouble ez = (rand() % 1000) / 1000.0 - 0.5;
  GLdouble cx = (rand() % 1000) / 1000.0 - 0.5;
  GLdouble cy = (rand() % 1000) / 1000.0 - 0.5;
  GLdouble cz = (rand() % 1000) / 1000.0 - 0.5;
  GLdouble ux = (rand() % 1000) / 1000.0 - 0.5;
  GLdouble uy = (rand() % 1000) / 1000.0 - 0.5;
  GLdouble uz = (rand() % 1000) / 1000.0 - 0.5;
  GLdouble M0[16];
  gluLookAt(ex, ey, ez, cx, cy, cz, ux, uy, uz);
  glGetDoublev(GL_MODELVIEW_MATRIX, M0);
  GLdouble M1[16];
  myglulookat(
    M1,
    ex, ey, ez,
    cx, cy, cz,
    ux, uy, uz);
  puts("------------------------");
  for (size_t i = 0; i < 16; i++) {
    printf("[%d] %lf\n", i, M0[i] - M1[i]);
  }

}

実行結果

[0] -0.000000
[1] 0.000000
[2] -0.000000
[3] 0.000000
[4] -0.000000
[5] 0.000000
[6] -0.000000
[7] 0.000000
[8] -0.000000
[9] -0.000000
[10] 0.000000
[11] 0.000000
[12] 0.000000
[13] 0.000000
[14] -0.000000
[15] 0.000000

コメントを残す

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

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


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