有几个这样的问题,但我还没有真正理解。我在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背后的数学和转换到矩阵中)。 / p>
尝试的是
buildPerspProjMat(g_ProjView,FovAngle,Aspect,1.0,32768.0 );
glUseProgram(g_program);
glUniformMatrix4fv(g_programFrustum, 1, GL_FALSE, g_ProjView );
glUseProgram(0);
并使用投影matix上方缓冲区中着色器中的位置,但这根本不起作用。
所以我现在不知道的是在哪里替换它以及着色器中的内容。我不知道glMatrixMode何时发生,“何时”用一些统一的矩阵替换它(将args作为统一传递不是问题)。 我无法计算我已阅读过多少教程,但我总是对所有混合版本感到困惑。我总是对一些代码示例感到高兴,但请OpenGL 3或更高版本。
下一个将是glTexCoord2f替代纹理,但这是一个不同的故事:)
答案 0 :(得分:15)
我发现在考虑现代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感到惊讶......那是因为我使用了glLoadGen生成的opengl头,它将所有opengl API函数放在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();
}
Associated Vertex Shader:
//[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);
}
生成的图像是:
答案 1 :(得分:0)
嗯,我同意大多数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,希望可以帮助你管理一个大项目的统一变量。