传递给着色器的颜色不起作用

dan*_*ood 0 c++ opengl glfw opengl-3

我是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
Run Code Online (Sandbox Code Playgroud)

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

    // 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);
}
Run Code Online (Sandbox Code Playgroud)

您可能需要知道的一些事情points是a Vector<float>,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);
}
Run Code Online (Sandbox Code Playgroud)

片段着色器:

#version 400 core

in vec3 color;

out vec4 finalColor;

void main()
{
    finalColor = vec4(color, 1.0);
}
Run Code Online (Sandbox Code Playgroud)

如果这是一个需要一些关注的问题,我道歉.我在过去的一天左右环顾四周,尝试了几种不同的东西,所有这些都没有用.如果需要任何其他信息,以便有人不必对我的所有代码进行分类,请告诉我.

我从apitrace得到的东西似乎表明我可能在使用着色器ID做错了,但是如果我将颜色编码到片段着色器中然后颜色可以正常工作,那么仍会出现错误.

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

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

此外,我想知道一旦对象超出范围并被delete调用,使用C++是否有可能失去OpenGL状态.

编辑:以下是我未提及的几件事:

着色器初始化:

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

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

// Compile
glCompileShader(shaderID);
Run Code Online (Sandbox Code Playgroud)

Shader Destructor只是打电话 glDeleteShader(shaderID);

这是非常标准的.这是着色器类的构造函数,shaderID是a的成员变量Shader.shaderTypeGLenum在这种情况下是两种GL_VERTEX_SHADERGL_FRAGMENT_SHADER.

程序初始化://创建程序programID = 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);
Run Code Online (Sandbox Code Playgroud)

程序析构函数:

// 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);
Run Code Online (Sandbox Code Playgroud)

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

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

编辑3:实际上,在看了一下之后,它似乎绘制了一个完全不同于颜色的三角形.为Triangle类创建一个vao成员并将其绑定到draw上似乎解决了这个问题.

编辑4:似乎glValidateProgram()确实产生了一个成功的结果,这让我怀疑它的着色器有问题.

Ret*_*adi 5

另外,我想知道一旦对象超出范围并且调用了delete,使用C++是否有可能失去OpenGL状态.

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

您遇到的问题是您在C++对象的析构函数中删除了包装的OpenGL对象.因此,只要其中一个对象超出范围,或者由于任何其他原因而被销毁,它就会占用相应的OpenGL对象.

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

Shader a(...);
{
    Shader b = a;
}
Run Code Online (Sandbox Code Playgroud)

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

当然,你不会像上面那样编写代码.但是,如果按值将对象传递给函数/方法,则可能会出现非常类似的情况,这部分发生在代码中.

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

这正是你的情况.您将Shader对象推入a vector,并且当您推入更多元素时,将vector删除已存在的对象的OpenGL ID vector作为重新分配的一部分.

核心问题是无法安全地复制这些C++对象.默认的复制行为(成员分配)不起作用.通常,您需要在C++中为默认实现不足的类实现复制构造函数和赋值运算符.但是如果你有OpenGL对象的id作为成员,那么实际上没有好办法,除非你实现更复杂的方案,可能涉及共享子对象,引用计数等.

我总是建议的一件事是为无法正确复制的类提供私有拷贝构造函数和赋值运算符.这将确保您在意外复制对象时出现编译时错误,而不是神秘的运行时行为.

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