2014-10-30 62 views
0

我是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<float>Program::getCurrentProgram()的事情是一个静态函数返回当前程序在这种情况下drawShapeGL_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错误,尽管我没有在他们的FAQ中明确地看到任何东西。

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

此外,我想知道如果使用C++可能会失去OpenGL状态,一旦对象超出范围并调用delete

编辑:这里有被提及,我没有表现出有两件事情:

着色器初始化:

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

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

// Compile 
glCompileShader(shaderID); 

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

这是非常标准。这是一个着色器类的构造函数,shaderID是一个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); 

计划析构函数:

// 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()确实产生了一个成功的结果,这让我怀疑它的着色器有问题。

+0

好吧,来自跟踪的错误消息提示着色器初始化的问题。你还没有粘贴相关的代码。 “glAttachShader(program = 1,shader = 1)”看起来像你试图将程序附加到程序而不是着色器。为什么你在属性设置完全超出我之后调用'glLinkProgram()'。 – derhass 2014-10-31 00:01:26

+0

@derhass我已经更新了帖子,为着色器和程序进行了初始化。他们对我来说都很标准。就程序和着色器索引为1而言,我认为这可能只是一个巧合,但我会仔细研究一下。再次调用'glLinkProgram()'是我测试过的东西之一,我读过的地方提到应该在设置属性之后连接程序,或者在设置它们之后再次连接。在我看到它没有任何作用后,我忘了删除该行。 – danielunderwood 2014-10-31 00:12:26

+0

@derhass经过多次调试后,看起来着色器的ID为1和2.从我的帖子中的错误看来,程序看起来像ID也是1。 – danielunderwood 2014-10-31 01:56:04

回答

5

此外,我想知道如果使用C++可能会失去OpenGL状态的风险,一旦对象超出范围并删除被调用。

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

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

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

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

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

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

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

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

核心问题是这些C++对象无法安全地被复制。默认复制行为(成员分配)不起作用。一般来说,您需要在C++中实现复制构造函数和赋值运算符,以用于缺省实现不足的类。但是,如果你有OpenGL对象的ID号作为成员,那么真的没有好办法,除非你实现了更复杂的方案,可能涉及到共享子对象,引用计数等。

我总是会推荐的一件事是对于无法正确复制的类有私有拷贝构造函数和赋值操作符。这将确保如果您意外复制对象而不是神秘的运行时行为,则会出现编译时错误。

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

+1

谢谢,这会让我永远想到我自己!只需使用'vector '而不是'vector '。在矢量上使用智能指针会有什么好处吗?我认为''unique_ptr'在快速浏览智能指针之后可能会很有用。 – danielunderwood 2014-10-31 11:52:11