我正在尝试更好地理解OpenGL的基本矩阵转换逻辑。这是从教科书复制并修改为处理3D的二维码;它“有点像”,但是当我自己进行矩阵乘法与使用glMultMatrix时,最终结果在视觉上是不同的。
标记为“XXX”的行允许在“我的乘法”和“OpenGL乘法”之间翻转。我尝试了一些显而易见的事情(例如,行与列专业,转换顺序等)
如果有人可以照亮我与OpenGL相比我做错了什么,我会很感激。
#include <iostream>
#include <math.h>
#include "glut.h"
#include "vector3.h"
typedef GLfloat Matrix4x4[4][4];
Matrix4x4 matComposite;
void matrix4x4SetIdentity(Matrix4x4 matIdent4x4){
GLint row, col;
for(row = 0; row<4; row++){
for(col = 0; col<4; col++){
matIdent4x4[row][col] = (row == col);
}
}
}
void matrix4x4PreMultiply(Matrix4x4 m1, Matrix4x4 m2){
GLint row, col;
Matrix4x4 matTemp;
for(row=0; row<4; row++){
for(col=0; col<4; col++){
matTemp[row][col] = m1[row][0] * m2[0][col] +
m1[row][1] * m2[1][col] +
m1[row][2] * m2[2][col] +
m1[row][3] * m2[3][col];
}
}
for(row=0; row<4; row++){
for(col=0; col<4; col++){
m2[row][col] = matTemp[row][col];
}
}
}
vector3 matrixMult(GLfloat x, GLfloat y, GLfloat z){
GLfloat tempX = matComposite[0][0] * x + matComposite[0][1] * y + matComposite[0][2] * z + matComposite[0][3];
GLfloat tempY = matComposite[1][0] * x + matComposite[1][1] * y + matComposite[1][2] * z + matComposite[1][3];
GLfloat tempZ = matComposite[2][0] * x + matComposite[2][1] * y + matComposite[2][2] * z + matComposite[2][3];
GLfloat tempW = matComposite[3][0] + matComposite[3][1] + matComposite[3][2] + matComposite[3][3];
// XXX return vector3(tempX/tempW, tempY/tempW, tempZ/tempW); // XXX
return vector3 (x, y, z);
}
void render() {
// my version of viewing/projection multiplication
GLfloat mvmX[4][4] = {{0.948683, 0.095346, -0.301511, 0.000000}, {0.000000, 0.953463, 0.301511, 0.000000}, {0.316228, -0.286039, 0.904534, 0.000000}, {0.000004, 0.000000, -132.664993, 1.000000}};
GLfloat pmX[4][4] = {{1.500000, 0.000000, 0.000000, 0.000000}, {0.000000, 1.500000, 0.000000, 0.000000}, {0.000000, 0.000000, -1.015113, -1.000000}, {0.000000, 0.000000, -3.022670, 0.000000}};
matrix4x4SetIdentity(matComposite);
matrix4x4PreMultiply(pmX, matComposite);
matrix4x4PreMultiply(mvmX, matComposite);
// OpenGL's version of viewing/projection multiplication
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
GLfloat mvm[] = {0.948683, 0.095346, -0.301511, 0.000000, 0.000000, 0.953463, 0.301511, 0.000000, 0.316228, -0.286039, 0.904534, 0.000000, 0.000004, 0.000000, -132.664993, 1.000000};
GLfloat pm[] = {1.500000, 0.000000, 0.000000, 0.000000, 0.000000, 1.500000, 0.000000, 0.000000, 0.000000, 0.000000, -1.015113, -1.000000, 0.000000, 0.000000, -3.022670, 0.000000};
glMultMatrixf(pm); // XXX
glMultMatrixf(mvm); // XXX
// draw a shape
glColor3f(1, 0, 0);
glBegin(GL_POLYGON);
vector3 vpt = matrixMult(0, 0, 0);
glVertex3f(vpt.x, vpt.y, vpt.z);
vpt = matrixMult(0, 50, 0);
glVertex3f(vpt.x, vpt.y, vpt.z);
vpt = matrixMult(50, 50, 0);
glVertex3f(vpt.x, vpt.y, vpt.z);
vpt = matrixMult(0, 50, 0);
glVertex3f(vpt.x, vpt.y, vpt.z);
glEnd();
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
render();
glutSwapBuffers();
}
void main(int argc, char **argv){
glutInit( &argc, argv );
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH) ;
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
int windowHandle = glutCreateWindow("Testing MVM and PM Matrices");
glutSetWindow(windowHandle);
glutDisplayFunc(display);
glutMainLoop();
}
答案 0 :(得分:1)
从此
matTemp[row][col]
我推断您使用行主存储顺序进行操作。但是,OpenGL使用column major
顺序。因此,您必须先转置矩阵,然后才能将它们与glLoadMatrix
一起使用。
此外,您的输入矩阵与您的矩阵顺序不匹配:
GLfloat pmX[4][4] = {{1.500000, 0.000000, 0.000000, 0.000000}, {0.000000, 1.500000, 0.000000, 0.000000}, {0.000000, 0.000000, -1.015113, -1.000000}, {0.000000, 0.000000, -3.022670, 0.000000}};
投影矩阵的最后一行应该是0,0,-1,0
,但代码解释矩阵的方式也会转换为,所以它会将(0, 0, -3.02267, 0)
视为最后一行。因此,您需要首先转置,应用矩阵运算,并将结果转换为OpenGL - 或者您只需更改矩阵运算以匹配OpenGL的运算并且不要转置任何内容。
请注意,使用现代GL,您可以轻松使用您喜欢的任何矩阵。设置统一矩阵的代码具有transpose
参数,该参数将告诉GL您使用的两个订单。