GLSL C++ glVertexAttribPointer & glDrawElements return GL_INVALID_OPERATION

GLSL C++ glVertexAttribPointer & glDrawElements return GL_INVALID_OPERATION

本文关键字:GL INVALID OPERATION return glDrawElements C++ glVertexAttribPointer GLSL      更新时间:2023-10-16

我得到错误GL_INVALID_OPERATION行:164和183,我不知道如何解决它。

第 164 行

GLCall(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0));

第 183 行:

GLCall(glDrawElements(GL_TRIANGLES, 6 ,GL_UNSIGNED_INT, nullptr));

我正在使用带有OpenGL版本字符串的Ubuntu 18.04:3.1 Mesa 18.3.0-devel - padoka PPA。 顺便说一下,我想画一个立方体。

主要:

#include <GL/glew.h>   
#include <GLFW/glfw3.h>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <sys/stat.h>
#define ASSERT(x) if (!(x)) std::cin.get();
#define GLCall(x) GLClearError();
x;
ASSERT(GLLogCall(#x, __FILE__, __LINE__))
static void GLClearError()
{
while(glGetError() != GL_NO_ERROR);
}
static bool GLLogCall(const char* function, const char* file, int line)
{
while(GLenum error = glGetError())
{
std::cout << "[OPENGL ERROR](" <<  error << ")" << function <<
" " << file << " line: " << line << std::endl;
return false;
}
return true;
}
struct ShaderProgramSource
{
std::string VertexSource;
std::string FragmentSource;
};
static ShaderProgramSource ParseShader(const std::string& filepath)
{
std::fstream stream (filepath);
enum ShaderType
{
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
std::string _line;
std::stringstream ss[2];
ShaderType type = ShaderType::NONE;
while(getline(stream, _line))
{
if(_line.find("#shader") != std::string::npos)
{
if(_line.find("vertex") != std::string::npos)
type = ShaderType::VERTEX;
else if (_line.find("fragment") != std::string::npos)
type = ShaderType::FRAGMENT;
}
else
{
ss[(int)type] << _line << 'n';
}
}
return { ss[0].str(), ss[1].str() };
}
static unsigned CompileShader(unsigned type, const std::string& source)
{
std::cout << "Compile Shader n";
unsigned id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
// TODO: ERROR handling
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if(!result)
{
int lenght;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &lenght);
char* message = (char*)&source[0];
glGetShaderInfoLog(id, lenght, &lenght, message);
std::cout << "Failed to compile " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " " << std::endl;
std::cout << message << std::endl;
return 0;
}
return id;
}
static unsigned CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
unsigned program = glCreateProgram();
unsigned vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
int main(void)
{
GLFWwindow* window;
/* Initialize the library*/
if(!glfwInit())
return -1;

GLCall(glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4));
GLCall(glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3));
GLCall(glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE));
GLCall(glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE));
/* Create a windowed mode window and its OpenGl context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if(!window)
{
glfwTerminate();
return -1;
}

/* Make the window's context current */
GLCall(glfwMakeContextCurrent(window));
if(glewInit() != GLEW_OK) std::cout << "Error!" << std::endl;
std::cout << glGetString(GL_VERSION) << std::endl;

float positions[] = {
-0.5f, -0.5f,   //0
0.5f, -0.5f,   //1
0.5f,  0.5f,   //2
-0.5f,  0.5f   //3
};
unsigned indices[]
{
0, 1, 2,
2, 3, 0
};
unsigned buffer;
GLCall(glGenBuffers(1, &buffer));
GLCall(glBindBuffer(GL_ARRAY_BUFFER, buffer));
GLCall(glBufferData(GL_ARRAY_BUFFER, 6*2*sizeof(float), positions, GL_STATIC_DRAW));
GLCall(glEnableVertexAttribArray(0));
GLCall(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0));
unsigned ibo;   //index buffer Object
GLCall(glGenBuffers(1, &ibo));
GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo));
GLCall(glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned), indices, GL_STATIC_DRAW));
//TODO: Relative path
ShaderProgramSource source = ParseShader("Path"); //This path leads to Shaders
unsigned shader = CreateShader(source.VertexSource, source.FragmentSource);
GLCall(glUseProgram(shader));
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
GLCall(glClear(GL_COLOR_BUFFER_BIT));
GLCall(glDrawElements(GL_TRIANGLES, 6 ,GL_UNSIGNED_INT, nullptr));
/* Swap front and back buffers */
GLCall(glfwSwapBuffers(window));
/* Poll for and process events */
GLCall(glfwPollEvents());
}
glfwTerminate();
return 0;
}

着色:

#shader vertex
#version 330 core
layout(location = 0) in vec4 position; 
void main() 
{
gl_Position = position; 
};
#shader fragment
#version 330 core
layout(location = 0) out vec4 color; 
void main() 
{
color = vec4(0.0, 1.0, 0.0, 1.0);
};

在拥有当前有效的 OpenGL 上下文之前,您不能调用任何 OpenGL 指令。
此外,glfwWindowHintglfwMakeContextCurrent不是OpenGL指令。

所以宏GLCall检查glError,比如

GLCall(glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4));
....

GLCall(glfwMakeContextCurrent(window));

无效且没有任何意义。

GLCall的第一个有效使用将在glfwMakeContextCurrent(window)之后。


由于您使用的是具有向前兼容性的核心配置文件上下文:

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

您必须创建一个绑定名为顶点数组对象。
请注意,在核心配置文件上下文中,默认顶点数组对象 (0( 无效。

在创建缓冲区对象并定义通用顶点属性数据数组之前,创建并绑定一个命名顶点数组对象就足够了。此对象取代兼容性配置文件中的默认顶点数组对象:

GLuint vao;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
unsigned buffer;
GLCall(glGenBuffers(1, &buffer));
GLCall(glBindBuffer(GL_ARRAY_BUFFER, buffer));
GLCall(glBufferData(GL_ARRAY_BUFFER, 6*2*sizeof(float), positions, GL_STATIC_DRAW));
GLCall(glEnableVertexAttribArray(0));
GLCall(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0));
unsigned ibo;   //index buffer Object
GLCall(glGenBuffers(1, &ibo));
GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo));
GLCall(glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(unsigned), indices, GL_STATIC_DRAW));

在初始化 GLEW 之前设置glewExperimental = GL_TRUE

glewExperimental = GL_TRUE;
if(glewInit() != GLEW_OK) std::cout << "Error!" << std::endl;

请参阅GLEW文档,其中说:

GLEW 从图形驱动程序获取有关支持的扩展的信息。但是,实验性或预发布驱动程序可能不会通过标准机制报告每个可用的扩展,在这种情况下,GLEW 将报告它不受支持。为了规避这种情况,可以通过在调用glewInit()之前将其设置为GL_TRUE来打开glewExperimental全局开关,从而确保所有具有有效入口点的分机都将公开。