【问题标题】:Color passed to shaders doesn't work传递给着色器的颜色不起作用
【发布时间】:2014-10-30 23:50:21
【问题描述】:

我对 OpenGL 还是很陌生,目前我正在处理一个简单的程序。

我遇到的问题是当我传递一个数组来表示点的颜色时,颜色最终变成了黑色。如果我只是在片段着色器中明确定义一种颜色,并且如果我在 VAO 中切换数据的索引,则三角形会移动到作为颜色的点。

我尝试使用 API 跟踪并得到以下结果:

6872: message: major api error 1282: GL_INVALID_OPERATION error generated. <program> is not a program object, or <shader> is not a shader object.
6872 @0 glAttachShader(program = 1, shader = 1)
6872: warning: glGetError(glAttachShader) = GL_INVALID_OPERATION
6876: message: major api error 1282: GL_INVALID_OPERATION error generated. Handle does not refer to the expected type of object (GL_SHADER_OBJECT_ARB).
6876 @0 glDeleteShader(shader = 1)
6876: warning: glGetError(glDeleteShader) = GL_INVALID_OPERATION
6878: message: major api error 1282: GL_INVALID_OPERATION error generated. Handle does not refer to the expected type of object (GL_SHADER_OBJECT_ARB).
6878 @0 glDeleteShader(shader = 1)
6878: warning: glGetError(glDeleteShader) = GL_INVALID_OPERATION
Rendered 507 frames in 8.52598 secs, average of 59.4653 fps

我所有的代码都是here,但它正在大量进行中。可能导致某种类型问题的位是下面的绘图段:

    // TODO: Use this code once per mesh
    // Make a VBO to hold points
    GLuint vbo = 0;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, points.size() * sizeof(GLfloat), &points[0], drawType);

    // VBO TO hold colors
    GLuint colorVbo = 0;
    glGenBuffers(1, &colorVbo);
    glBindBuffer(GL_ARRAY_BUFFER, colorVbo);

    float colors[] = {
            0.5, 0.0, 0.0,
            0.0, 0.5, 0.0,
            0.0, 0.0, 0.5
    };

    glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), colors, GL_STATIC_DRAW);

    // Make a VAO for the points VBO
    GLuint vao = 0;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    // Points
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);

    // Colors
    glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);

    GLint colorpos = glGetAttribLocation(Program::getCurrentProgram(), "vertColor");

    glEnableVertexAttribArray(0);   // Points
    glEnableVertexAttribArray(1);   // Colors

    glLinkProgram(Program::getCurrentProgram());

    // Draw Mesh
    glDrawArrays(drawShape, 0, points.size()/2);
}

您可能需要知道的一些事情是pointsVector&lt;float&gt;Program::getCurrentProgram() 是返回当前正在使用的程序的静态函数,而drawShape 在这种情况下是GL_TRIANGLES .

顶点着色器:

#version 400 core

layout(location=0) in vec3 vert;
layout(location=1) in vec3 vertColor;

out vec3 color;

void main()
{
    color = vertColor;
    gl_Position = vec4(vert, 1);
}

片段着色器:

#version 400 core

in vec3 color;

out vec4 finalColor;

void main()
{
    finalColor = vec4(color, 1.0);
}

如果这是一个需要花点时间研究的问题,我深表歉意。过去一天左右我环顾四周,尝试了几种不同的方法,但都没有奏效。如果需要任何其他信息以便有人不必对我的所有代码进行排序,请告诉我。

我从 apitrace 得到的信息似乎表明我可能在着色器 ID 上做错了,尽管如果我将颜色编码到片段着色器中并且颜色随后会起作用,该错误仍然会发生。

我正在使用 GLFW 来创建我的 OpenGL 上下文。我设置了一个错误回调,但我没有从中得到任何东西,我的印象是它也应该通过 OpenGL 错误,尽管我没有在他们的常见问题解答中看到任何明确说明的内容。

我也在编译着色器和链接程序时检查错误,那里也没有发生任何事情。

另外,我想知道,一旦对象超出范围并调用 delete,使用 C++ 是否可能会丢失 OpenGL 状态。

编辑:以下是我没有展示的几件事:

着色器初始化:

// Create OpenGL Shader
shaderID = glCreateShader(shaderType);

glShaderSource(shaderID, 1, &cShaderString, NULL);

// Compile
glCompileShader(shaderID);

着色器析构函数只调用glDeleteShader(shaderID);

这是相当标准的。这是在着色器类的构造函数中,shaderIDShader 的成员变量。 shaderTypeGLenum,在这种情况下是 GL_VERTEX_SHADERGL_FRAGMENT_SHADER

程序初始化: // 创建程序 程序ID = glCreateProgram();

// Iterate through Shaders
for(std::vector<Shader>::iterator shader = shaders.begin(); shader != shaders.end(); shader++)
{
    // Attach Shader
    glAttachShader(programID, shader->getShaderID());
}

// Link program
glLinkProgram(programID);

程序析构函数:

// Iterate through attached shaders
for(std::vector<Shader>::iterator shader = shaders.begin(); shader != shaders.end(); shader++)
{
    // Detach Shader
    glDetachShader(programID, shader->getShaderID());
}

// Delete program
glDeleteProgram(programID);

再一次,这看起来很标准,并且在 Program 类的构造函数中。

编辑 2: 搞砸了一些代码后,我发现了一个相当奇怪的东西。如果我移动创建和绑定缓冲区的代码并将三角形绘制到我用作表示三角形的类的构造函数中,我将位置作为颜色而不是位置。这与我切换数据上的索引(位置为 1,颜色为 0)时发生的情况相同。

编辑 3: 实际上,再看多一点后,它似乎绘制了一个与颜色完全不同的三角形。为 Triangle 类创建一个 vao 成员并将其绑定到 draw 似乎可以解决此问题。

编辑 4: 似乎 glValidateProgram() 确实产生了成功的结果,这让我怀疑它的着色器是否存在问题。

【问题讨论】:

  • 嗯,来自跟踪的错误消息暗示着色器初始化存在问题。您尚未为此粘贴相关代码。 “glAttachShader(program = 1, shader = 1)” 看起来您尝试将程序附加到程序,而不是着色器。以及为什么在你的属性设置完全超出我的能力之后你称之为glLinkProgram()
  • @derhass 我已经更新了帖子以对着色器和程序进行初始化。在我看来,他们俩都很标准。至于程序和着色器的索引都为 1,我认为这可能只是巧合,但我会稍微研究一下。再次调用glLinkProgram() 是我在某处测试过的事情之一,在我读到的某处提到该程序应在设置属性后链接,或者应在设置属性后再次链接。我只是在看到它没有效果后忘记删除该行。
  • @derhass 经过更多调试,似乎着色器的 ID 为 1 和 2。从我帖子中的错误来看,看起来程序的 ID 为 1好吧。
  • 一些平台为不同类型的对象提供不同的 ID,而另一些则没有。对于着色器和程序,您完全有可能获得 1 的 id。也就是说,该错误肯定表明 id 存在问题。
  • @RetoKoradi 我会再看一下,但看起来这些是从glCreateShader()glCreateProgram() 返回的 ID 我也有点奇怪当我编译两个着色器时,只有一个着色器出现这些错误。调用glCompileShader 时,我也没有收到任何类型的错误。用 C++ 类表示的所有东西是否有可能以某种方式破坏 OpenGL 状态?

标签: c++ opengl glfw opengl-3


【解决方案1】:

另外,我想知道一旦对象超出范围并调用 delete 时,使用 C++ 是否可能会丢失 OpenGL 状态。

是的,有。我相信这正是这里正在发生的事情。这并不意味着您不能将 OpenGL 对象包装在 C++ 类中,但您必须非常小心。

您在这里遇到的问题是您在 C++ 对象的析构函数中删除了包装的 OpenGL 对象。因此,任何时候这些对象中的任何一个超出范围,或因任何其他原因被销毁,它都会带上相应的 OpenGL 对象。

如果您复制对象,这会导致特别难看的问题。让我们看一个人为的例子:

Shader a(...);
{
    Shader b = a;
}

在此之后,您在a 的构造函数中创建的OpenGL 对象将被删除。当创建b 作为a 的副本时,默认的复制构造函数会将存储在a 中的着色器id 复制到b。然后,当b 超出范围时,其析构函数会删除着色器 ID。它仍然存储在a,但现在无效。

当然,您不会编写与上面完全相同的代码。但是,如果您将对象按值传递给函数/方法,您可能会遇到非常相似的情况,这部分发生在您的代码中。

如果将这些对象存储在std::vector 之类的容器中会发生什么,因为更难以识别,因此更危险。 vector 在添加新元素使其超出当前容量时会重新分配其内存。在重新分配期间,它会在vector(调用复制构造函数)中创建所有现有元素的副本,然后销毁原始元素。这再次与上面的示例非常相似,您最终会得到引用已删除 OpenGL 对象的对象。

这正是您的情况。您将Shader 对象推入vector,并且已经在vector 中的对象的OpenGL id 将作为vector 的一部分在您推入更多元素时被重新分配。

核心问题是不能安全地复制这些 C++ 对象。默认复制行为(按成员分配)不起作用。通常,您需要在 C++ 中为默认实现不足的类实现复制构造函数和赋值运算符。但是,如果您将 OpenGL 对象的 id 作为成员,则确实没有什么好方法可以做到这一点,除非您实施更复杂的方案,可能涉及共享子对象、引用计数等。

我始终建议的一件事是为无法正确复制的类使用私有复制构造函数和赋值运算符。如果您不小心复制对象,这将确保您得到编译时错误,而不是神秘的运行时行为。

然后,要将对象存储在容器中,最简单的方法是在容器中存储指向对象的指针,而不是对象本身。您可以使用智能指针(例如smart_ptr)来简化内存管理。

【讨论】:

  • 谢谢,这将需要我永远自己弄清楚!只需使用vector&lt;Shader*&gt; 而不是vector&lt;Shader&gt;。在向量上使用智能指针会有什么好处吗?在快速查看智能指针后,我认为unique_ptr 可能在这里有用。
猜你喜欢
  • 1970-01-01
  • 2014-06-27
  • 1970-01-01
  • 1970-01-01
  • 2014-11-02
  • 2021-12-20
  • 1970-01-01
  • 1970-01-01
  • 2021-07-17
相关资源
最近更新 更多