Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么glUseProgram用glUniform调用每个帧?_C++_Opengl_Fragment Shader - Fatal编程技术网

C++ 为什么glUseProgram用glUniform调用每个帧?

C++ 为什么glUseProgram用glUniform调用每个帧?,c++,opengl,fragment-shader,C++,Opengl,Fragment Shader,我遵循OpenGL v3.3教程,该教程指导我使用glUniform4f修改片段着色器中的统一属性(请参阅下面的代码)。据我所知,OpenGL是一个状态机,我们不会解除当前使用的着色器程序的绑定,而是修改附加到程序的其中一个着色器中的属性,那么为什么我们需要在每一帧上调用GluseProgramm呢 我知道OpenGL的更高版本并非如此,但我仍然想理解为什么v3.3会出现这种情况 OpenGL程序: while (!glfwWindowShouldClose(window)) { pro

我遵循OpenGL v3.3教程,该教程指导我使用glUniform4f修改片段着色器中的统一属性(请参阅下面的代码)。据我所知,OpenGL是一个状态机,我们不会解除当前使用的着色器程序的绑定,而是修改附加到程序的其中一个着色器中的属性,那么为什么我们需要在每一帧上调用GluseProgramm呢

我知道OpenGL的更高版本并非如此,但我仍然想理解为什么v3.3会出现这种情况

OpenGL程序:

while (!glfwWindowShouldClose(window))
{
    processInput(window);

    glClearColor(0.2f, 1.0f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);


    glUseProgram(shaderProgram); // the function in question

    float redValue = (sin(glfwGetTime()) / 2.0f) + 0.5f;
    int colorUniformLocation = glGetUniformLocation(shaderProgram, "ourColor");
    glUniform4f(colorUniformLocation, redValue, 0.0f, 0.0f, 1.0f);

    std::cout << colorUniformLocation << std::endl;

    glBindVertexArray(VAO[0]);
    glDrawArrays(GL_TRIANGLES, 0, 3);

    glBindVertexArray(VAO[1]);
    glDrawArrays(GL_TRIANGLES, 0, 3);

    glfwSwapBuffers(window);
    glfwPollEvents();
}

编辑:我忘了指出glUniform4f在每一帧设置一种新的颜色(以周期性的方式),代码的最终输出是两个带动画颜色的三角形,从while循环中删除glUseProgram,同时生成静态图像,这不是代码的预期目标。

在您的情况下,您可能不必在每一帧都设置它。 然而,在更大的程序中,您将使用多个着色器,因此在每次使用之前需要设置一个所需的着色器,并且很可能编写示例就是为了实现这一点。

可变全局变量(这实际上是OpenGL的状态)本质上是危险的。可变全局变量最重要的危险之一是对其当前状态做出假设,而这些假设最终被证明是错误的。这些类型的失败使得理解一段代码是否能正常工作变得异常困难,因为它的行为依赖于外部的东西。关于世界本质的假设,而不是由期望它的功能所定义的东西

代码希望发出两个使用特定着色器的绘图命令。通过在使用点绑定该着色器,该代码使我们不受任何关于当前着色器的假设的约束。启动循环时,上一个着色器是什么并不重要;您正在将其设置为需要的状态

这使得此代码与您以后可能进行的任何更改隔离。如果要渲染使用不同着色器的第三个对象,代码将继续工作:在每个循环的开始处重置着色器。如果只将着色器设置在循环之外,而没有每次重置它,则后续的着色器更改将破坏代码

是的,在这样一个小玩具程序中,这可能是一个很容易追踪和修复的问题。但是,当您处理的代码跨越数百个文件和上万行代码,并且依赖关系分散在第三方库中时,所有这些都可能修改任何特定的OpenGL状态?是的,也许最好不要对世界的性质假设太多

尽早养成好习惯是一件好事

公平地说,在程序中的每个点重新指定一组OpenGL状态也是一个坏主意。作为函数的一部分,对OpenGL上下文的性质做出假设/期望,这在先天上并不坏。如果您有一些网格渲染函数,则该函数可以假定用户已绑定了它打算使用的着色器。此函数的任务不是指定渲染需要指定的所有其他状态。事实上,如果这样做的话,它将是一个糟糕的网格类/函数,因为您将无法以不同的状态渲染相同的网格


但是在每个帧的开始,或者渲染过程的每个主要部分的开始,指定OpenGL状态的基线是完全有效的。当您循环回到一个新帧的开头时,基本上不应该假设OpenGL的状态。不是因为OpenGL不记得了,而是因为你可能错了。

正如答案和评论所示,在我问题中所述的示例中,GluseProgramm只能在while循环外编写一次,以生成预期的输出,即2个三角形,颜色定期设置动画。我产生的误解是由于learnopengl.com电子书中的以下章节所述:

更新一致性确实需要您首先使用该程序(通过调用glUseProgram),因为它会在当前活动的着色器程序上设置一致性


我认为每次我想通过glUniform更新制服时,我还必须调用glUseProgram,这是一个错误的理解。

“为什么我们需要在每一帧上调用glUseProgram?”-你不必这样做。谁说的?“据我所知,OpenGL是一个状态机,…”——你是对的。在应用程序循环之前安装一次程序就足够了(当所有内容都用同一个程序呈现时)。我编辑了我的帖子来进一步阐述这个问题。你不能删除它,你必须将它放在循环之前。明白了,在循环外编写GluseProgramm后,程序现在可以正常工作,这是有意义的。
#version 330 core
out vec4 FragColor;
uniform vec4 ourColor;
void main() 
{
 FragColor = ourColor;
}