从OpenGL 3.3中获取投影矩阵

3

出于兼容性原因,我必须混合使用旧和现代OpenGL代码。我希望通过使用uniform变量从OpenGL检索当前的投影和模型视图矩阵,并将其传递给着色器。

以下代码显示了我尝试仅获取投影矩阵的方法。它没有按预期工作:

float m[16];
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, aspect, 0.01f, 2.0f);
glGetFloatv(GL_PROJECTION_MATRIX, m);

在这些代码之后,矩阵m包含单位矩阵。我使用以下代码进行了检查:

printf("%f %f %f %f\n", m[0], m[4], m[8],  m[12]);
printf("%f %f %f %f\n", m[1], m[5], m[9],  m[13]);
printf("%f %f %f %f\n", m[2], m[6], m[10], m[14]);
printf("%f %f %f %f\n", m[3], m[7], m[11], m[15]);

我使用freeglut创建了上下文,并使用以下代码显式请求了OpenGL 3.3上下文:

...
glutInitContextVersion(3, 3);
glutCreateWindow(title);

当我将版本更改为OpenGL 2.0时,上述代码按预期工作。每个版本以上都会产生所描述的问题。
我正在使用Intel Corporation Broadwell-U集成图形在Xubuntu上工作。
有人可以解释这种行为吗?有人可以提供解决方案吗?

3
如果你请求3.3版本而没有指定glutInitContextProfile(GLUT_COMPATIBILITY_PROFILE),Mesa是否会实际给你提供兼容性上下文?还是会自动升级为核心上下文?在调用glGetFloatv()之前/之后,glGetError()返回什么? - genpfault
2
为什么StackOverflow上的每个OpenGL问题都被踩了呢..?这是一个完全合理的问题。 - Dan Bechard
创建上下文后,我检查了版本(感谢提供的链接)。glGetString(GL_VERSION)返回*Version: 4.3 (Core Profile) Mesa 12.1.0-devel (git-8c3ecde 2016-06-08 xenial-oibaf-ppa)*,而glGetIntegerv(GL_MAJOR_VERSION/GL_MINOR_VERSION, ...)也告诉我同样的信息。为什么当我明确请求一个3.3上下文时,会得到不同的版本? 核心上下文解释了这种行为。我使用ARB_debug_output添加了一个错误回调,而glMatrixMode是第一个被报告为已弃用的函数。 - Henkk
当我请求一个兼容性上下文时,在调用glutCreateWindow时就会得到以下错误: X Error of failed request: GLXBadFBConfig Major opcode of failed request: 154 (GLX) Minor opcode of failed request: 34 () Serial number of failed request: 36 Current serial number in output stream: 35 - Henkk
1个回答

2

OpenGL-3.3兼容性配置文件是一项可选功能,并没有实际支持的要求。大多数OpenGL实现实际上不支持兼容性配置文件。显著的例外是NVidia和AMD的专有驱动程序。因此,将OpenGL-3.3与旧版本混合使用可能无法在所有系统上可靠运行。

但是为什么要这样做呢?

float m[16];
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, aspect, 0.01f, 2.0f);
glGetFloatv(GL_PROJECTION_MATRIX, m);

完全不需要吗?首先,GLU不是OpenGL的一部分,GLU函数只是内部调用OpenGL函数的小助手。无论如何,gluPerspective函数非常简单,通过OpenGL来回调用矩阵实在是很尴尬(老实说,这触发了我的呕吐反射)。

在其核心,gluPerspective是为glFrustum确定参数:

void gluPerspective(
    double fov,
    double aspect,
    double znear, float zfar)
{
    double const height = znear * tanf(fovyInDegrees * M_PI / 360.0);
    double const width = height * aspect;
    glFrustum(-width, width, -height, height, znear, zfar);
}

这就是它的全部功能。glFrustum本身也非常简单。

void glFrustum(double l, double r, double b, double t, double n, double f)
{
    double M[4][4];
    M[0][0] = 2.f*n/(r-l);
    M[0][1] = M[0][2] = M[0][3] = 0.f;

    M[1][1] = 2.*n/(t-b);
    M[1][0] = M[1][2] = M[1][3] = 0.f;

    M[2][0] = (r+l)/(r-l);
    M[2][1] = (t+b)/(t-b);
    M[2][2] = -(f+n)/(f-n);
    M[2][3] = -1.f;

    M[3][2] = -2.f*(f*n)/(f-n);
    M[3][0] = M[3][1] = M[3][3] = 0.f;
    glMultMatrixd(&M[0][0]);
}

很容易将其重写为接受矩阵指针作为参数,然后直接传递给uniform变量。

感谢您诚实的回答。这里也有咳吐反射。您是对的,重写gluPerspective或其他投影矩阵显然很容易。我的问题有点误导人,因为我的主要目标是针对modelview-matrix进行操作。这将使我避免重写使用矩阵堆栈和glRotate、glScale和glTranslate函数的大部分代码。最好的解决方案是使用像glm这样的适当数学库。 - Henkk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接