gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-04 16:12:40 24 4
gpt4 key购买 nike

我是 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()是一个返回当前正在使用的程序的静态函数,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 错误,尽管我在他们的常见问题解答中没有看到任何明确说明这一点。

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

此外,我想知道使用 C++ 是否会在对象超出范围和 delete 时冒丢失 OpenGL 状态的风险被称为。

编辑:这里有一些我没有展示的提到的东西:

着色器初始化:

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

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

// Compile
glCompileShader(shaderID);

Shader Destructor 只是调用 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: 在弄乱了一些代码之后,我发现了一件相当奇怪的事情。如果我将创建和绑定(bind)缓冲区并将三角形绘制到我用作表示三角形的类的构造函数的代码移动,我得到的位置是颜色而不是位置。这与我在数据上切换索引(位置为 1,颜色为 0)时发生的事情相同。

Edit 3: 实际上,仔细看了一下,它似乎画了一个与颜色完全不同的三角形。为 Triangle 类创建一个 vao 成员并在绘制时绑定(bind)它似乎解决了这个问题。

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

最佳答案

Also, I was wondering if using C++ could risk losing OpenGL states once an object goes out of scope and delete is called.

是的,有。我相信这正是这里正在发生的事情。这并不意味着您不能将 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 作为成员,那么确实没有什么好方法可以做到这一点,除非您实现更复杂的方案,可能涉及共享子对象、引用计数等。

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

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

关于c++ - 传递给着色器的颜色不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26665382/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com