最近花了一天时间重写了 OpenGL O p e n G L 中矩阵变换的部分函数,主要包含五个:
glLoadIdentity() g l L o a d I d e n t i t y ( ) gluLookAt() g l u L o o k A t ( ) glScaled() g l S c a l e d ( ) glTranslated() g l T r a n s l a t e d ( ) glRotated() g l R o t a t e d ( )
重写后对应的命名是:
LoadIdentity() L o a d I d e n t i t y ( ) LookAt() L o o k A t ( ) Scaled() S c a l e d ( ) Translated() T r a n s l a t e d ( ) Rotated() R o t a t e d ( )
另外由于是写在一个类中,所以还写了一个设值一个取值函数,并且还写了两个 debug d e b u g 函数。

这里的矩阵变换函数所用到的变换矩阵都是比较简单的,网上随便搜一下或者自己推一下就好了,可能稍微难一些的是旋转矩阵,这个可以去 LearnOpenGL CN L e a r n O p e n G L   C N 入门章节中变换部分看看。主要难点是使用 Eigen E i g e n 有些生疏,初次使用,所以写起来花了一些功夫,另外需要注意的是,在 OpenGL O p e n G L 中的矩阵变换使用的不是像 C++ C + + 等语言中的数组那样的以列为主行为辅的布局,而是刚好相反,也就是说要利用这些常规的变换矩阵的转置矩阵进行操作。

一定要注意是转置矩阵!!!

opengl_transformations.h o p e n g l _ t r a n s f o r m a t i o n s . h

#ifndef OPENGL_TRANSFORMATIONS_H
#define OPENGL_TRANSFORMATIONS_H

#include <GL/glew.h>
#include <GL/gl.h>

#include <Eigen/Core>
#include <Eigen/Dense>

#include <QString>
 class OpenGLTransformations { private: Eigen::Matrix4d *matrix_; GLdouble *matrix_1x16_; const GLdouble kPi = 3.14159265359; public: OpenGLTransformations(); OpenGLTransformations(GLdouble *matrix); ~OpenGLTransformations(); void set_matrix(GLdouble *matrix); GLdouble *matrix_1x16(); void LoadIdentity(); void LookAt(Eigen::Vector3d position, Eigen::Vector3d target, Eigen::Vector3d world_up); void Scaled(Eigen::Vector3d zoom); void Translated(Eigen::Vector3d move); void Rotated(GLdouble angle, Eigen::Vector3d axis); void DebugOutputTransposeMatrix4d(Eigen::Matrix4d mat, QString s); void DebugOutputVector3d(Eigen::Vector3d vec, QString s); }; #endif // OPENGL_TRANSFORMATIONS_H

opengl_transformations.cpp o p e n g l _ t r a n s f o r m a t i o n s . c p p

#include "opengl_transformations.h"

#include <QDebug>
#include <cmath>

OpenGLTransformations::OpenGLTransformations() {
  matrix_ = new Eigen::Matrix4d();
  matrix_1x16_ = new GLdouble[16];
}

OpenGLTransformations::OpenGLTransformations(GLdouble *matrix) {
  matrix_ = new Eigen::Matrix4d();
  matrix_1x16_ = new GLdouble[16];
  set_matrix(matrix);
}

OpenGLTransformations::~OpenGLTransformations() {
  delete matrix_;
  delete matrix_1x16_;
}

// set matrix_
void OpenGLTransformations::set_matrix(GLdouble *matrix) {
  Eigen::Matrix4d &mat = *matrix_;
  for (int i = 0; i < 4; i++) {
    mat(i, 0) = matrix[i * 4];
    mat(i, 1) = matrix[i * 4 + 1];
    mat(i, 2) = matrix[i * 4 + 2];
    mat(i, 3) = matrix[i * 4 + 3];
  }
}

// get matrix_ with GLdouble[16]
GLdouble *OpenGLTransformations::matrix_1x16() {
  GLdouble *matrix = matrix_1x16_;
  Eigen::Matrix4d &mat = *matrix_;
  for (int i = 0; i < 4; i++) {
    matrix[i * 4] = mat(i, 0);
    matrix[i * 4 + 1] = mat(i, 1);
    matrix[i * 4 + 2] = mat(i, 2);
    matrix[i * 4 + 3] = mat(i, 3);
  }

  return matrix;
}

// Identity
void OpenGLTransformations::LoadIdentity() {
  qDebug() << "gl_load_identity";

  Eigen::Matrix4d &mat = *matrix_;
  mat = Eigen::Matrix4d::Identity();

  // for (int i = 0; i < 4; i++) {
   
  // for (int j = 0; j < 4; j++) {
   
  // if (i == j) {
   
  // mat(i, j) = 1;
  // } else {
   
  // mat(i, j) = 0;
  // }
  // }
  // }
}

// look at
void OpenGLTransformations::LookAt(Eigen::Vector3d position,
                                   Eigen::Vector3d target,
                                   Eigen::Vector3d world_up) {
  qDebug() << "gl_u_look_at";

  // Calculate cameraDirection
  Eigen::Vector3d z_axis = position - target;
  z_axis.normalize();
  // debug_output_vector3d(z_axis, "z_axis");

  // Get positive right axis vector
  Eigen::Vector3d x_axis = world_up;
  x_axis.normalize();
  // debug_output_vector3d(x_axis, "x_axis");
  x_axis = x_axis.cross(z_axis);
  // debug_output_vector3d(x_axis, "x_axis");
  x_axis.normalize();
  // debug_output_vector3d(x_axis, "x_axis");

  // Calculate camera up vector
  Eigen::Vector3d y_axis = z_axis;
  y_axis = y_axis.cross(x_axis);
  // debug_output_vector3d(y_axis, "y_axis");

  // Create translation matrix
  Eigen::Matrix4d translation = Eigen::Matrix4d::Identity();
  translation(3, 0) = -position(0);  // Fourth column, first row
  translation(3, 1) = -position(1);
  translation(3, 2) = -position(2);
  // debug_output_transpose_matrix4d(translation, "translation");

  // Create rotation matrix
  Eigen::Matrix4d rotation = Eigen::Matrix4d::Identity();
  rotation(0, 0) = x_axis(0);  // First column, first row
  rotation(1, 0) = x_axis(1);
  rotation(2, 0) = x_axis(2);
  rotation(0, 1) = y_axis(0);  // First column, second row
  rotation(1, 1) = y_axis(1);
  rotation(2, 1) = y_axis(2);
  rotation(0, 2) = z_axis(0);  // First column, third row
  rotation(1, 2) = z_axis(1);
  rotation(2, 2) = z_axis(2);
  // debug_output_transpose_matrix4d(rotation, "rotation");

  // Update matrix_
  Eigen::Matrix4d &mat = *matrix_;
  mat = rotation * translation * mat;
  // debug_output_transpose_matrix4d(mat, "matrix_");
}

void OpenGLTransformations::Scaled(Eigen::Vector3d zoom) {
  // Create scale matrix
  Eigen::Matrix4d scale = Eigen::Matrix4d::Identity();
  scale(0, 0) = zoom(0);
  scale(1, 1) = zoom(1);
  scale(2, 2) = zoom(2);

  // Update matrix_
  Eigen::Matrix4d &mat = *matrix_;
  mat = scale * mat;
}

void OpenGLTransformations::Translated(Eigen::Vector3d move) {
  // Create translation matrix
  Eigen::Matrix4d translation = Eigen::Matrix4d::Identity();
  translation(3, 0) = move(0);  // Fourth column, first row
  translation(3, 1) = move(1);
  translation(3, 2) = move(2);

  // Update matrix_
  Eigen::Matrix4d &mat = *matrix_;
  mat = translation * mat;
}

void OpenGLTransformations::Rotated(GLdouble angle, Eigen::Vector3d axis) {
  // Create rotation matrix
  Eigen::Matrix4d rotation = Eigen::Matrix4d::Identity();

  GLdouble radian = angle / 180 * kPi;
  GLdouble radian_sin = std::sin(radian);
  GLdouble radian_cos = std::cos(radian);
  // In Eigen we access elements as mat[col][row] due to column-major layout
  if (axis(0) > 0) {
    rotation(1, 1) = radian_cos;
    rotation(1, 2) = radian_sin;
    rotation(2, 1) = -radian_sin;
    rotation(2, 2) = radian_cos;
  } else if (axis(1) > 0) {
    rotation(0, 0) = radian_cos;
    rotation(0, 2) = -radian_sin;
    rotation(2, 0) = radian_sin;
    rotation(2, 2) = radian_cos;
  } else if (axis(2) > 0) {
    rotation(0, 0) = radian_cos;
    rotation(0, 1) = radian_sin;
    rotation(1, 0) = -radian_sin;
    rotation(1, 1) = radian_cos;
  }

  // Update matrix_
  Eigen::Matrix4d &mat = *matrix_;
  mat = rotation * mat;
}

void OpenGLTransformations::DebugOutputTransposeMatrix4d(Eigen::Matrix4d mat,
                                                         QString s) {
  qDebug() << "debug_4*4:" << s;
  for (int i = 0; i < 4; i++) {
    qDebug() << mat(0, i) << mat(1, i) << mat(2, i) << mat(3, i);
  }
  qDebug() << "debug-";
}

void OpenGLTransformations::DebugOutputVector3d(Eigen::Vector3d vec,
                                                QString s) {
  qDebug() << "debug_3*1:" << s;
  qDebug() << vec(0);
  qDebug() << vec(1);
  qDebug() << vec(2);
  qDebug() << "debug-";
}

有关于 Eigen E i g e n 或者 OpenGL O p e n G L 问题的欢迎评论区讨论,如果代码有何不足,也欢迎大佬们指点一二……这里使用的是 Google C++ G o o g l e   C + + 编程规范。