替换 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
Posted
技术标签:
【中文标题】替换 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;【英文标题】:Replacement for gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 【发布时间】:2014-02-24 07:01:43 【问题描述】:有几个这样的问题,但我还没有真正理解。 10 多年前,我使用 OpenGL 进行编码,并注意到进入现代 OpenGL 是多么困难。 OpenGL.org 页面在示例方面是一团糟,你永远不知道它是什么版本,任何版本似乎都混杂在各种代码示例中。 好吧,我有一个旧代码至少要更新到 OpenGL >3。所以我做的第一件事就是从 glVertex3fv 继续前进,最终使用 glVertexAttribPointer 实现它(在我读到这之前,使用 glVertexPointer 的一步现在也已弃用)。这很好,但是当我尝试放置纹理时我很快就卡住了,我认为这是因为定位错误,我想摆脱 c++ 代码:
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glFrustum( -RProjZ, +RProjZ, -Aspect*RProjZ, +Aspect*RProjZ, 1.0, 32768.0 );
然后画出来
// bind vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, VertBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * size, verts, GL_STATIC_DRAW);
// enable arrays
glEnableVertexAttribArray(0);
// set pointers
glVertexAttribPointer(0,3,GL_FLOAT, GL_FALSE, sizeof(float) * floatsPerVertex, 0);
// render ComplexSurface
glDrawArrays(GL_TRIANGLE_FAN, 0, size);
glDisableVertexAttribArray(0);
在顶点着色器中
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
一切都在神奇地工作。不要误会我的意思,我是魔法的忠实粉丝,但是... 然后我发现了一些矩阵转换,它们可以用来获取一个矩阵来替换 glFrustum,但是每当我尝试替换它时,它都会失败(尽管我想我理解了 glFrustum 背后的数学和转换为矩阵)。
尝试的是类似的东西
buildPerspProjMat(g_ProjView,FovAngle,Aspect,1.0,32768.0 );
glUseProgram(g_program);
glUniformMatrix4fv(g_programFrustum, 1, GL_FALSE, g_ProjView );
glUseProgram(0);
并将上面缓冲区中着色器中的位置与投影矩阵一起使用,但这根本行不通。
所以我现在完全不知道在哪里替换它以及在着色器中用什么替换。我不知道 glMatrixMode 发生在哪一点以及“何时”用一些统一矩阵替换它(将 args 作为统一传递不是这里的问题)。 我已经数不清我已经阅读了多少教程,但我总是对所有混合版本感到困惑。我总是对一些代码示例感到满意,但请使用 OpenGL 3 或更高版本。
下一个将替代 glTexCoord2f 用于纹理,但这是另一回事 :)
【问题讨论】:
现在对此有另一条评论,其中包含相当多的信息,但几分钟前被删除,取而代之的是 -1,但我没有时间复制链接并阅读所有信息呢。我在原始问题中添加了更多信息,很遗憾它被删除了,因为我认为它不适合我的问题。 【参考方案1】:我发现在考虑现代 OpenGL 时,最好忘记 glMatrixMode
曾经存在过。
考虑到这一点,让我们回顾一下最基本的绘制操作需要什么:替换gl_ModelViewProjectionMatrix
。顾名思义,这是 3 个不同矩阵的组合:模型矩阵、视图矩阵和投影矩阵。
因此,您需要在着色器中容纳 3 个 mat4
类型的统一变量。你会像这样使用它:
uniform mat4 projMat;
uniform mat4 viewMat;
uniform mat4 modelMat;
layout (location = 0) in vec3 position;
void main()
gl_Position = projMat * viewMat * modelMat * vec4(position, 1.0);
这段着色器代码执行的功能与上面的相同。改变的是内置的 gl_ModelViewProjectionMatrix
被 3 个统一变量替换(如果您确保在传递之前在 C++ 端自己将它们相乘,则可以将它们组合为一个)。并且内置的gl_Vertex
被替换为输入变量。
在 C++ 方面,您需要做两件事。首先,您需要获取这些制服的位置:
GLuint modelMatIdx = glGetUniformLocation(shaderProgId, "modelMat");
GLuint viewMatIdx = glGetUniformLocation(shaderProgId, "viewMat");
GLuint projMatIdx = glGetUniformLocation(shaderProgId, "projMat");
有了这个,您现在可以在使用glUniformMatrix4fv
绘制之前为每个制服传递值。
glm 是一个使这变得特别容易的特定库。例如,要获得与您的示例相同的投影矩阵,您可以:
glm::mat4 projMat = glm::frustum(-RProjZ, +RProjZ, -Aspect*RProjZ, +Aspect*RProjZ, 1.0, 32768.0);
你会像这样传递它:
glUniformMatrix4fv(projMatIdx, 1, GL_FALSE, glm::value_ptr(projMat));
既然你知道怎么做,我想解决“何时”的问题。你说你不清楚矩阵模式的东西,这让我回到了我之前的“忘记它”的断言。矩阵模式在那里,以便您可以告诉 opengl 哪个内置应该受到对 OpenGL 矩阵操作(如 glTranslate、glFrustum 等)的调用的影响,但现在所有这些都消失了。您现在负责管理所涉及的(可能很多)矩阵。你所要做的就是在你画画之前把它们传进去(如我上面所示),你会没事的。在尝试修改其制服之前,请确保该程序已绑定。
这是一个工作示例(如果您对 gl::... 而不是 gl... )。
GLuint simpleProgramID;
// load the shader and make the program
GLuint modelMatIdx = gl::GetUniformLocation(simpleProgramID, "modelMat");
GLuint viewMatIdx = gl::GetUniformLocation(simpleProgramID, "viewMat");
GLuint projMatIdx = gl::GetUniformLocation(simpleProgramID, "projMat");
GLuint vaoID;
gl::GenVertexArrays(1, &vaoID);
gl::BindVertexArray(vaoID);
GLuint vertBufferID, indexBufferID;
gl::GenBuffers(1, &vertBufferID);
gl::GenBuffers(1, &indexBufferID);
struct Vec2 float x, y; ;
struct Vec3 float x, y, z; ;
struct Vert Vec3 pos; Vec2 tex; ;
std::array<Vert, 8> cubeVerts =
0.5f, 0.5f, 0.5f , 1.0f, 0.0f , 0.5f, 0.5f, -0.5f , 1.0f, 1.0f ,
0.5f, -0.5f, -0.5f , 0.0f, 1.0f , 0.5f, -0.5f, 0.5f , 0.0f, 0.0f ,
-0.5f, 0.5f, 0.5f , 0.0f, 0.0f , -0.5f, 0.5f, -0.5f , 0.0f, 1.0f ,
-0.5f, -0.5f, -0.5f , 1.0f, 1.0f , -0.5f, -0.5f, 0.5f , 1.0f, 0.0f
;
std::array<unsigned int, 36> cubeIdxs =
0, 2, 1, 0, 3, 2, // Right
4, 5, 6, 4, 6, 7, // Left
0, 7, 3, 0, 4, 7, // Top
1, 6, 2, 1, 5, 6, // Bottom
0, 5, 1, 0, 4, 5, // Front
3, 7, 6, 3, 6, 2 // Back
;
// Vertex buffer
gl::BindBuffer(gl::ARRAY_BUFFER, vertBufferID);
gl::BufferData(gl::ARRAY_BUFFER, sizeof(Vert) * cubeVerts.size(), cubeVerts.data(), gl::STATIC_DRAW);
gl::EnableVertexAttribArray(0); // Matches layout (location = 0)
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE_, sizeof(Vert), 0);
gl::EnableVertexAttribArray(1); // Matches layout (location = 1)
gl::VertexAttribPointer(1, 2, gl::FLOAT, gl::FALSE_, sizeof(Vert), (GLvoid*)sizeof(Vec3));
// Index buffer
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, indexBufferID);
gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * cubeIdxs.size(), cubeIdxs.data(), gl::STATIC_DRAW);
gl::BindVertexArray(0);
glm::mat4 projMat = glm::perspective(56.25f, 16.0f/9.0f, 0.1f, 100.0f);
glm::mat4 viewMat = glm::lookAt(glm::vec3(5, 5, 5), glm::vec3(0, 0, 0), glm::vec3(0, 0, 1));
glm::mat4 modelMat; // identity
while (!glfwWindowShouldClose(window))
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
gl::UseProgram(simpleProgramID);
gl::UniformMatrix4fv(projMatIdx, 1, gl::FALSE_, glm::value_ptr(projMat));
gl::UniformMatrix4fv(viewMatIdx, 1, gl::FALSE_, glm::value_ptr(viewMat));
gl::UniformMatrix4fv(modelMatIdx, 1, gl::FALSE_, glm::value_ptr(modelMat));
gl::BindVertexArray(vaoID);
gl::DrawElements(gl::TRIANGLES, 36, gl::UNSIGNED_INT, 0);
gl::BindVertexArray(0);
gl::UseProgram(0);
glfwSwapBuffers(window);
glfwPollEvents();
关联的顶点着色器:
//[VERTEX SHADER]
#version 430
uniform mat4 projMat;
uniform mat4 viewMat;
uniform mat4 modelMat;
layout (location = 0) in vec3 in_position; // matches gl::EnableVertexAttribArray(0);
layout (location = 1) in vec2 in_uv; // matches gl::EnableVertexAttribArray(1);
out vec2 uv;
void main()
gl_Position = projMat * viewMat * modelMat * vec4(in_position, 1.0);
uv = in_uv;
最后是片段着色器:
//[FRAGMENT SHADER]
#version 430
in vec2 uv;
out vec4 color;
void main()
color = vec4(uv, 0.0, 1.0);
生成的图像是:
【讨论】:
谢谢,这已经回答了很多问题。在您的示例中,我现在不确定的是: glm::mat4 modelMat; // 身份 - 我也读过一些关于 GLM 的教程,并在一些简单的测试程序中使用了它,但首先我觉得要改变一种魔法,它可以对抗另一种魔法,而另一种魔法却没有(在我的尝试中)至少摆脱 gl_ModelViewProjectionMatrix ),所以我一开始想避免使用它。我想现在我明白为什么它不起作用了。 谢谢你!我花了太多时间试图弄清楚所有这些东西。我没有意识到我曾经熟悉的 OpenGL 有多少已被弃用。我一直在试图弄清楚如何替换所有已弃用的东西时感到非常沮丧。顺便说一句,我得到的图像与您的图像相比是颠倒的……知道为什么会这样吗? OpenGL 有一个讨厌的习惯,即弃用非常好的功能,除了“自己动手”之外不提供任何替代。就像,是的,如果我需要做一些预制功能不能做的事情,我自己做也很好,但是如果预制功能已经存在并且通常有用,那么为了方便而保留它们有什么问题?向后兼容?【参考方案2】:嗯,我同意大多数 OpenGL 教程会混淆一些已弃用和未弃用的内容。为了让你找到正确的方向,让我解释一下。
gl_ModelViewProjectionMatrix
、gl_ModeView
、glMatrixMode()
和矩阵堆栈 glPushMatrix()
glPopMatrix()
已弃用。您需要将自己的矩阵定义为统一变量,然后使用glUniform*
将它们设置并传递给着色器。
gl_Vertex
也已弃用,实际上整个固定属性名称已弃用。或者,您需要定义自己的属性名称并将它们绑定到特定位置。然后,您可以使用glVertexAttribPointer
设置它们的值,方法是将属性位置传递给它(Full explanation here)。例如:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices); // for vertices
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, color); // for color
对于着色器代码
layout (location = 0) in vec4 vertex;
layout (location = 1) in vec4 color;
uniform mat4 modelview;
uniform mat4 projection;
void main()
gl_Position = projection* modelview* vertex;
对于属性位置,您可以像我一样在着色器代码中设置它们,或者使用 glBindAttribLocation 从 OpenGL API 中设置它们。
如果您习惯了旧的 OpenGL 全局变量,例如 gl_ModelView
,管理统一变量可能会有些棘手。我写了一个 article,希望可以帮助您管理大型项目的统一变量。
【讨论】:
对同一个话题有不同的看法总是好的,尤其是在理解方面,我认为你的文章以后可能对我很有用。太好了,你把它加回来了。 啊! Khronos 的人有什么问题?他们一次又一次地表明他们不理解“弃用”的含义。它应该是当你有一个更好的功能替代品时你做的事情,但他们反复使用它来让我们的事情更糟,取而代之的是用过的东西“只是工作”并将其倾倒在我们的圈子中以手动重新实施,如果这甚至可能的话。 (例如,我还没有看到GL_QUADS
的好替代品!)
@MasonWheeler GL_QUADS 已被弃用,因为 TRIANGLES 对 GPU 的绘制速度更快,我通常做的是在两个三角形上构建一个四边形抽象,当我将数据结构传递给 OpenGL 进行绘制时,我会传递它们作为三角形。是的,我猜你的意思是手动重新实现。
@concept3d:将其作为 TRIANGLES 的问题是您需要传递六个顶点来绘制一个具有四个顶点的对象。如果您要绘制数千或数万个四边形(在带有平铺地图的 2D 游戏中很可能),那么很快就会产生很大的不同!如果 GPU 绘制三角形比绘制四边形更快,这意味着有人在编写 GPU 驱动程序时搞砸了;它应该完全一样快,因为它以最佳方式在引擎盖下处理它,而不会将所有工作都交给开发人员。
@concept3d 这就是重点:三角形光栅化不应该比四边形光栅化更快,因为 GPU 可以通过简单地在两个相对顶点之间画一条线将四边形转换为三角形。 (特别是最常见的四边形、2D 图形,其中所有 4 个顶点都是共面的。)纵观计算机编程的整个历史,进步是通过改进允许开发人员在更高抽象级别上工作的框架来实现的。不过,OpenGL 的人似乎不明白这一点,因为他们一直在做完全相反的事情。以上是关于替换 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;的主要内容,如果未能解决你的问题,请参考以下文章
WebGL—gl_Position gl_FragCoord gl_PointCoord 区别
WebGL—gl_Position gl_FragCoord gl_PointCoord 区别
openGL之API学习(一八九)gl_Position gl_Vertex