首页 > 解决方案 > glUniform4fv 导致 GL_INVALID_OPERATION

问题描述

嘿,我有一个抽象所有与着色器相关的类,称为Shader.cpp

#include "Shader.h"
#include "Renderer.h"

#include <iostream>
#include <fstream>

Shader::Shader()
{
    GLCALL(m_RenderedID = glCreateProgram());
}


Shader::~Shader()
{
    GLCALL(glDeleteProgram(m_RenderedID));
}

void Shader::Bind() const
{
    GLCALL(glUseProgram(m_RenderedID));
}

void Shader::Unbind() const
{
    GLCALL(glUseProgram(0));
}

std::string ParseShader(const std::string& path)
{
    std::ifstream ifs(path);
    return std::string((std::istreambuf_iterator<char>(ifs)),
        (std::istreambuf_iterator<char>()));
}

static unsigned int CompileShader(unsigned int type, const std::string& source)
{
    GLCALL(unsigned int id = glCreateShader(type));
    const char* src = source.c_str();
    GLCALL(glShaderSource(id, 1, &src, nullptr));
    GLCALL(glCompileShader(id));

    int result;
    GLCALL(glGetShaderiv(id, GL_COMPILE_STATUS, &result));

    if (result == GL_FALSE)
    {
        int length;
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
        char* message = (char*)alloca(length * sizeof(char));
        GLCALL(glGetShaderInfoLog(id, length, &length, message));
        std::cout << "Failed to compile shader!" << std::endl;
        std::cout << message << std::endl;
        glDeleteShader(id);
        return 0;
    }
    return id;
}

void Shader::Attach(const unsigned int type, const std::string& path)
{
    unsigned int id = CompileShader(type, ParseShader(path));
    if (m_ShaderFiles.find(id) == m_ShaderFiles.end())
        m_ShaderFiles[id] = ShaderFile({ type, path });
    GLCALL(glAttachShader(m_RenderedID, id));
}

void Shader::Link()
{
    int result;

    GLCALL(glLinkProgram(m_RenderedID));
    GLCALL(glGetProgramiv(m_RenderedID, GL_LINK_STATUS, &result));

    if (result == GL_FALSE)
    {
        std::cout << "Failed to link shader!" << std::endl;
        return;
    }

    GLCALL(glValidateProgram(m_RenderedID));
    GLCALL(glGetProgramiv(m_RenderedID, GL_VALIDATE_STATUS, &result));

    if (result == GL_FALSE)
    {
        std::cout << "Failed to validate shader!" << std::endl;
        return;
    }

    for (const auto& shaderFile : m_ShaderFiles) {
        GLCALL(glDeleteShader(shaderFile.first));
    }
}

// this part is taken from Shader.h because it's templated
template<typename T, unsigned int S>
void SetUniform(Uniform<T, S>& uniform)
{
    Bind();
    uniform.Set(GetUniformLocation(uniform.GetName()));
}

int Shader::GetUniformLocation(const std::string& name)
{
    if (m_UniformLocationCache.find(name) != m_UniformLocationCache.end())
        return m_UniformLocationCache[name];

    GLCALL(int location = glGetUniformLocation(m_RenderedID, name.c_str()));
    m_UniformLocationCache[name] = location;
    return location;
}

这是我app.cpp使用 Shader 类:

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <iostream>
#include <fstream>
#include <string>

#include "core/renderer/Shader.h"
#include "core/renderer/uniform/Uniform4f.cpp"
#include "core/renderer/VertexArray.h"
#include "core/renderer/VertexBufferLayout.h"
#include "core/renderer/VertexBuffer.h"
#include "core/renderer/IndexBuffer.h"

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    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 */
    glfwMakeContextCurrent(window);

    glfwSwapInterval(1);

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

    std::cout << glGetString(GL_VERSION) << std::endl;

    float vertices[] = {
        -0.5f, -0.5f,
        0.5f, -0.5f,
        0.5f, 0.5f,
        -0.5f, 0.5f
    };

    unsigned int indices[] = {
        0, 1, 2,
        2, 3, 0
    };

    VertexArray va;
    VertexBufferLayout layout;
    layout.Push({ GL_FLOAT, 2, sizeof(float) * 2, GL_FALSE });

    VertexBuffer vb(vertices, sizeof(vertices), layout);

    IndexBuffer ib(indices, 6);

    va.AddVertexBuffer(vb);

    Shader shader;
    shader.Attach(GL_VERTEX_SHADER, "res/shaders/basic_vs.shader");
    shader.Attach(GL_FRAGMENT_SHADER, "res/shaders/basic_fs.shader");
    shader.Link();
    shader.Bind();

    Uniform4f colorUniform("u_Color");

    float r = 0.00f;
    float increment = 0.05f;
    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        colorUniform.SetValues({ r, 0.5f, 0.9f, 1.0f });
        shader.SetUniform(colorUniform);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);

        if (r > 1.0f)
            increment = -0.05f;
        else if (r < 0.0f)
            increment = 0.05f;

        r += increment;

        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
#include <iostream>

这是Uniform4f.cpp我要设置的:

#include "Uniform.h"
#include "../Renderer.h"

#include <iostream>

class Uniform4f : public Uniform<float, 4>
{
public:
    Uniform4f(const std::string& name, const std::array<float, 4>& values = {})
        : Uniform(name, values)
    {

    }

    virtual void Set(int location)
    {
        GLCALL(glUniform4fv(location, m_Values.size(), reinterpret_cast<const GLfloat*>(m_Values.data())));
    }
};

现在我正在GL_INVALID_OPERATION调用.glUniform4fv(location, m_Values.size(), reinterpret_cast<const GLfloat*>(m_Values.data()))shader.SetUniform(colorUniform);app.cpp

文档指出它可能是以下问题之一:

我真的无法确定哪个错误可能导致它,以上似乎都不正确。在调试时,我看到传递给的统一值、大小和位置glUniform4fv都是正确的,我的着色器程序在Binded 中被Linked之后app.cpp,所以我不确定是什么原因造成的。

我会很感激能在这方面得到任何帮助。

标签: c++openglglslshader

解决方案


好的,我想通了。文档说:

count
对于向量 (glUniform*v) 命令,指定要修改的元素的数量。如果目标统一变量不是数组,则该值应为 1,如果它是数组,则应为 1 或更多。

这有点令人困惑,但我的错误是目标统一变量只有1 vec4而不是数组,vec4这就是所count代表的。


推荐阅读