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 + + 编程规范。