在片段着色器中检索当前纹素的颜色

时间:2016-11-18 15:49:09

标签: c++ opengl fragment-shader fbo multisampling

我想检索片段着色器中当前纹素的颜色,这样我就可以根据它调整输出颜色。

例如:如果当前纹理元素的颜色为红色,则将颜色设置为绿色enter image description here 在上面,您可以看到有两个三角形。一个三角形部分绘制 on 另一个。您可以看到叠加部分是绿色的,就像我说的那样,我的片段着色器检测到颜色"红色"所以它将输出颜色设置为"绿色"。

如您所见,我的计划效果很好。但是,我是OpenGL的初学者,所以我不太了解我写的所有内容,而且我确定我犯了一些错误。我希望得到您的反馈。

我为实现这一目标所做的一切:

  1. 在FBO中绘制第一个三角形
  2. 将帧缓冲区复制到绘制帧缓冲区(=屏幕上)
  3. 直接在屏幕上绘制第二个三角形
  4. 起初我尝试在没有FBO的情况下直接在屏幕上绘制两个三角形但是我在片段着色器中无法使用texture2D() 获得纹理颜色。

    这是我的代码(我使用 OpenGL 3.3 GLFW 3 GLEW ):

    #include <iostream>
    #include <string>
    
    #define GLEW_STATIC
    #include <GL/glew.h>
    #include <GLFW/glfw3.h>
    
    const std::string WINDOW_TITLE = "Drawing color depending on current background pixel color";
    const GLuint WIDTH = 800, HEIGHT = 600;
    
    const std::string vertexShaderSource = R"(
    #version 330 core
    
    layout (location = 0) in vec3 position;
    
    void main()
    {
        gl_Position = vec4(position.x, position.y, position.z, 1.0f);
    }
    )";
    
    const std::string fragmentShaderSource = R"(
    #version 330 core
    
    layout(location = 0) out vec4 color;
    uniform sampler2D renderedTexture;
    
    void main()
    {
        vec2 size = textureSize(renderedTexture, 0);
        vec2 position = gl_FragCoord.xy / size.xy;
        vec4 inputColor = texture2D(renderedTexture, position);
    
        if (inputColor[0] == 0.0f)
        {
            color = vec4(1.0f, 0.0f, 0.0f, 1.0f);
        }
        else if (inputColor[0] == 1.0f)
        {
            color = vec4(0.1f, 1.0f, 0.0f, 1.0f);
        }
        else
        {
            color = vec4(0.8f, 0.0f, 1.0f, 1.0f);
        }
    }
    )";
    
    
    GLFWwindow *setupWindow()
    {
        GLFWwindow *window = nullptr;
        int width = 0, height = 0;
    
        glfwInit();
    
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
        glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    
        window = glfwCreateWindow(WIDTH, HEIGHT, WINDOW_TITLE.c_str(), nullptr, nullptr);
        glfwMakeContextCurrent(window);
    
        glewExperimental = GL_TRUE;
        glewInit();
    
        glfwGetFramebufferSize(window, &width, &height);
        glViewport(0, 0, width, height);
    
        return window;
    }
    
    GLuint compileShader(GLenum type, const std::string &source, std::string &errorLog)
    {
        GLuint shader = 0;
        GLint compileSuccess = 0;
        const GLchar *sourceC = source.c_str();
        const std::size_t ERROR_LOG_BUFFER_SIZE = 512;
        GLchar errorLogBuffer[ERROR_LOG_BUFFER_SIZE]{};
    
        errorLog = "";
    
        shader = glCreateShader(type);
        glShaderSource(shader, 1, &sourceC, nullptr);
        glCompileShader(shader);
    
        glGetShaderiv(shader, GL_COMPILE_STATUS, &compileSuccess);
        if (!compileSuccess)
        {
            glGetShaderInfoLog(shader, ERROR_LOG_BUFFER_SIZE, nullptr, errorLogBuffer);
            glDeleteShader(shader);
    
            errorLog = errorLogBuffer;
    
            return 0;
        }
    
        return shader;
    }
    
    GLuint compileShaderProgram(const std::string &vertexShaderSource, const std::string &fragmentShaderSource, std::string &errorLog)
    {
        GLuint vertexShader{};
        GLuint fragmentShader{};
        GLuint shaderProgram{};
        GLint linkSuccess{};
        const std::size_t ERROR_LOG_BUFFER_SIZE = 512;
        GLchar errorLogBuffer[ERROR_LOG_BUFFER_SIZE]{};
    
        errorLog = "";
    
        vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource, errorLog);
        if (vertexShader == 0)
            return 0;
    
        fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource, errorLog);
        if (fragmentShader == 0)
            return 0;
    
        shaderProgram = glCreateProgram();
        glAttachShader(shaderProgram, vertexShader);
        glAttachShader(shaderProgram, fragmentShader);
        glLinkProgram(shaderProgram);
    
        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);
    
        glGetProgramiv(shaderProgram, GL_LINK_STATUS, &linkSuccess);
        if (!linkSuccess)
        {
            glGetProgramInfoLog(shaderProgram, ERROR_LOG_BUFFER_SIZE, nullptr, errorLogBuffer);
            glDeleteProgram(shaderProgram);
    
            errorLog = errorLogBuffer;
    
            return 0;
        }
    
        return shaderProgram;
    }
    
    int main(int argc, char *argv[])
    {
        GLFWwindow *window = setupWindow();
        std::string errorLog = "";
        GLuint shaderProgram = compileShaderProgram(vertexShaderSource, fragmentShaderSource, errorLog);
        GLuint fbo = 0;
        GLuint fboTexture = 0;
        GLuint vao = 0;
        GLuint vbo = 0;
        GLenum drawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
        GLuint indicesBuffer = 0;
        GLushort indices[] = { 0,1,2, 3,4,5 };
        GLfloat vertices[] = {
            // Bottom triangle (first triangle drawn)
            -0.5f, +0.0f,
            +0.5f, +0.0f,
            +0.0f, +0.5f,
    
            // Top triangle (second triangle drawn, partially ON the first one, and slighly above it)
            -0.5f, +0.2f,
            +0.5f, +0.2f,
            +0.0f, +0.8f,
        };
    
    
        /*
        ** Setup FBO
        */
        glEnable(GL_TEXTURE_2D);
    
        glGenFramebuffers(1, &fbo);
        glGenTextures(1, &fboTexture);
    
        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
        glBindTexture(GL_TEXTURE_2D, fboTexture);
    
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    
        glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fboTexture, 0);
        glDrawBuffers(sizeof(drawBuffers) / sizeof(GLenum), drawBuffers);
    
        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
            return EXIT_FAILURE;
    
    
        /*
        ** Setup VAO and VBO
        */
        glGenVertexArrays(1, &vao);
        glGenBuffers(1, &vbo);
        glGenBuffers(1, &indicesBuffer);
    
        glBindVertexArray(vao);
    
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
    
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    
    
        /*
        ** Main loop
        */
        while (!glfwWindowShouldClose(window))
        {
            glfwPollEvents();
    
            /*
            ** Draw first triangle in FBO (not on screen)
            */
            glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    
            glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);
    
            glUseProgram(shaderProgram);
            glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
            glUseProgram(0);
    
    
            /*
            ** Copy the read framebuffer to the draw framebuffer (= on screen)
            */
            glReadBuffer(GL_COLOR_ATTACHMENT0);
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
            glViewport(0, 0, WIDTH, HEIGHT);
            glBlitFramebuffer(0, 0, WIDTH, HEIGHT, 0, 0, WIDTH, HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST);
    
    
            /*
            ** Draw the second triangle directly on screen
            */
            glUseProgram(shaderProgram);
            glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, reinterpret_cast<const void*>(3 * sizeof(GLushort)));
            glUseProgram(0);
    
    
            /*
            ** Swap buffers
            */
            glfwSwapBuffers(window);
        }
    
    
        /**
        ** Free resources
        */
        glDeleteBuffers(1, &indicesBuffer);
        glDeleteBuffers(1, &vbo);
        glDeleteVertexArrays(1, &vao);
        glDeleteProgram(shaderProgram);
    
        glfwTerminate();
    
    
        return 0;
    }
    
    • 这是一个好方法吗?
    • 是否称为&#34; 多重采样&#34;?根据我的理解,您使用具有glTexImage2DMultisample()等功能的FBO进行多重采样。但即使我使用FBO,我也会使用glTexImage2D()代替glTexImage2DMultisample()。所以?

    另外,我不太了解我的片段着色器中的uniform sampler2D renderedTexture;如何工作。我以为我需要做类似的事情:

    GLuint texID = glGetUniformLocation(shaderProgram, "renderedTexture");
    glUniform1i(texID, 0);
    

    设置统一变量,但我这样做并且它有效。的为什么吗

    最后,您可能想知道我为什么要这么做。好吧,当我刚刚开始学习OpenGL时,我将其作为一个&#34;练习&#34;解决我的真正问题:在图像上以足够对比度的颜色写入文字,以便它可以读取(例如:如果你想在白墙上写一些文字,用黑色写,不是白色,或者你不会看到它。)

0 个答案:

没有答案