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

最近花了一天时间重写了 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 + + 编程规范。

### 使用Eigen库进行坐标变换及创建变换矩阵 #### 创建变换矩阵Eigen库中,可以通过`Affine3f`或`Isometry3f`类来表示三维空间中的刚体变换。这些类能够处理旋转和平移操作。 对于给定的角度θ=π/2(即90度),可以构建一个绕Z轴逆时针方向的旋转变换矩阵R: \[ R=\begin{bmatrix} \cos(\theta)&-\sin(\theta)\\ \sin(\theta)&\cos(\theta) \end{bmatrix}= \begin{bmatrix} 0&-1\\ 1&0 \end{bmatrix}\] 接着定义平移向量t=(tx,ty)=(2,2),则完整的齐次变换矩阵T可由下述方式获得[^3]: ```cpp #include <iostream> #include <Eigen/Dense> using namespace Eigen; int main() { Matrix3d rotation_matrix; rotation_matrix << 0,-1, 1, 0; // Rotation by pi/2 radians around Z axis Vector2d translation_vector(2, 2); Affine2d transform = Translation2d(translation_vector)*Rotation2D<double>(M_PI / 2); std::cout << "Transform matrix:\n" << transform.matrix() << "\n"; } ``` 此代码片段展示了如何利用Eigen库构造一个二维平面内的仿射变换对象,并打印出对应的变换矩阵形式。 #### 应用变换到点上 当有一个位于frame_1下的点P其坐标为(1,0),要将其转换至全局坐标系(world frame)下,则需执行如下运算: \[ P_{world}=RP_{local}+t \] 其中\( P_{local}=[1,0]^T\) 是待变换点的位置矢量,在上述例子中已经给出具体的数值;而 \( t=[2,2]^T \) 则代表了frame_1相对世界坐标的位移分量。因此, \[ P_{world} = \begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix} \times \begin{bmatrix} 1 \\ 0 \end{bmatrix}+ \begin{bmatrix} 2 \\ 2 \end{bmatrix}= \begin{bmatrix} 2 \\ 3 \end{bmatrix}\]. 这段解释说明了怎样通过乘法和加法完成从局部坐标系到全局坐标系之间的位置映射过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值