GLSL C ++ glVertexAttribPointer和glDrawElements返回GL_INVALID_OPERATION

时间:2018-08-26 14:46:41

标签: c++ glsl

我在行164和183中收到错误var summary = ints .AsParallel() .WithDegreeOfParallelism(5) .Aggregate( seed: ( count: 0, sum: 0, min: int.MaxValue, max: int.MinValue), updateAccumulatorFunc: (acc, x) => ( count: acc.count + 1, sum: acc.sum + x, min: Math.Min(acc.min, x), max: Math.Max(acc.max, x)), combineAccumulatorsFunc: (acc1, acc2) => ( count: acc1.count + acc2.count, sum: acc1.sum + acc2.sum, min: Math.Min(acc1.min, acc2.min), max: Math.Max(acc1.max, acc2.max)), resultSelector: acc => ( acc.count, acc.sum, acc.min, acc.max, avg: (double)acc.sum / acc.count)); ,但我不知道如何解决。

第164行

GL_INVALID_OPERATION

第183行:

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

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

主要:

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

着色器:

#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;
}

1 个答案:

答案 0 :(得分:0)

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

因此glError通过宏GLCall进行检查,就像

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);

您必须创建一个名为Vertex Array Object的绑定。
请注意,在核心配置文件上下文中,默认的顶点数组对象(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 documantation,其中指出:

  

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