Eigen 重写部分 OpenGL 矩阵变换函数

版权声明:听说这里让写版权声明~~~ https://blog.csdn.net/f_zyj/article/details/82226292

最近花了一天时间重写了 OpenGL 中矩阵变换的部分函数,主要包含五个:
glLoadIdentity()gluLookAt()glScaled()glTranslated()glRotated()
重写后对应的命名是:
LoadIdentity()LookAt()Scaled()Translated()Rotated()
另外由于是写在一个类中,所以还写了一个设值一个取值函数,并且还写了两个 debug 函数。

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

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

opengl_transformations.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

#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 或者 OpenGL 问题的欢迎评论区讨论,如果代码有何不足,也欢迎大佬们指点一二……这里使用的是 Google C++ 编程规范。

阅读更多

扫码向博主提问

f_zyj

弱校 ACM 竞赛拓荒者,从零到区域赛银
  • 擅长领域:
  • ACM
  • 挑战程序设计
  • C/C++
去开通我的Chat快问
换一批

没有更多推荐了,返回首页