【问题标题】:COLOR_ATTACHMENTn as a sampler input to fragment shader?COLOR_ATTACHMENTn 作为片段着色器的采样器输入?
【发布时间】:2014-11-15 00:59:11
【问题描述】:

我正在编写一个代码,该代码要求我将 2+ 个纹理发送到片段着色器中,然后我需要从着色器中获取 2 个 COLOR_ATTACHMETn。一旦我从我的着色器中得到COLOR_ATTACHMENT0COLOR_ATTACHMENT1,是否可以将它们作为采样器发送到着色器中以在四边形屏幕上渲染?

我需要将 COLOR_ATTACHMENT 发送到第二个着色器的原因是我在不同的监视器上渲染 COLOR_ATTACHMENT0COLOR_ATTACHMENT1COLOR_ATTACHMENT0 将出现在一个屏幕上,COLOR_ATTACHMENT1 将出现在另一个屏幕上...

我正在进行测试视力的心理实验。我的第一个着色器对我的原始纹理集进行处理,但由于两个输出纹理所需的大部分处理是相同的,我不想在不需要时运行着色器基本上两次。

我正在使用 GLFW、GLEW 和 GLM。所以任何使用这些库的解决方案都是理想的

用于传递纹理坐标和屏幕位置的基本顶点着色器

const GLchar* vertexSource =
    "#version 150 core\n"
    "in vec2 position;"
    "in vec2 texcoord;"
    "out vec2 Texcoord;"
    "void main() {"
    "   Texcoord = texcoord;"
    "   gl_Position = vec4(position, 0.0, 1.0);"
    "}";

任意片段着色器,接收两个采样器并输出两个 vec4“纹理”

const GLchar* fragmentSource =
    "#version 150 core\n"
    "in vec2 Texcoord;"
    "out vec4 outColor0;"
    "out vec4 outColor1;"
    "uniform sampler2D texLite;"
    "uniform sampler2D texDark;"
    "void main() {"
    "   outColor0 = texture(texLite, Texcoord);"
    "   outColor1 = texture(texDark, Texcoord);"
    "}";

(和以前一样)基本的顶点着色器传递纹理坐标和屏幕位置

const GLchar* vertexSourceDisp =
    "#version 150 core\n"
    "in vec2 position;"
    "in vec2 texcoord;"
    "out vec2 Texcoord;"
    "void main() {"
    "   Texcoord = texcoord;"
    "   gl_Position = vec4(position, 0.0, 1.0);"
    "}";

简单的片段着色器用于采样器并在四边形上显示

const GLchar* fragmentSourceDisp =
    "#version 150 core\n"
    "in vec2 Texcoord;"
    "out vec4 outColor;"
    "uniform sampler2D tex;"
    "void main() {"
    "   outColor = texture(tex, Texcoord);"
    "}";

当我运行 glFramebufferTexture2D 时,它会将纹理图像附加到帧缓冲区,所以当着色器运行时,我的着色器输出的 vec4 是否会存储回纹理以及颜色附件中?

完整代码

#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
#include <stdio.h>

// Simple through-put vertex shader
const GLchar* vertexSource =
    "#version 150 core\n"
    "in vec2 position;"
    "in vec2 texcoord;"
    "out vec2 Texcoord;"
    "void main() {"
    "   Texcoord = texcoord;"
    "   gl_Position = vec4(position, 0.0, 1.0);"
    "}";

// Basic fragment shader for the moment 
const GLchar* fragmentSource =
    "#version 150 core\n"
    "in vec2 Texcoord;"
    "out vec4 outColor0;"
    "out vec4 outColor1;"
    "uniform sampler2D texLite;"
    "uniform sampler2D texDark;"
    "void main() {"
    "   vec4 colLena = texture(texLite, Texcoord);"
    "   vec4 colTex7 = texture(texDark, Texcoord);"
    "   outColor0 = mix(colLena, colTex7, 0.0);"
    "   outColor1 = mix(colLena, colTex7, 1.0);"
    "}";

const GLchar* vertexSourceDisp =
    "#version 150 core\n"
    "in vec2 position;"
    "in vec2 texcoord;"
    "out vec2 Texcoord;"
    "void main() {"
    "   Texcoord = texcoord;"
    "   gl_Position = vec4(position, 0.0, 1.0);"
    "}";

const GLchar* fragmentSourceDisp =
    "#version 150 core\n"
    "in vec2 Texcoord;"
    "out vec4 outColor;"
    "uniform sampler2D tex;"
    "void main() {"
    "   outColor = texture(tex, Texcoord);"
    "}";

    void printShaderInfoLog(GLuint obj)
{
    int infologLength = 0;
    int charsWritten  = 0;
    char *infoLog;

    glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);

    if (infologLength > 0)
    {
        infoLog = (char *)malloc(infologLength);
        glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
        printf("%s\n",infoLog);
        free(infoLog);
    }
}

void printProgramInfoLog(GLuint obj)
{
    int infologLength = 0;
    int charsWritten  = 0;
    char *infoLog;

    glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);

    if (infologLength > 0)
    {
        infoLog = (char *)malloc(infologLength);
        glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
        printf("%s\n",infoLog);
        free(infoLog);
    }
}

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}

int main()
{
    if (glfwInit() != GL_TRUE)
    {
        fprintf(stderr, "Failed to initialize GLFW\n");
        return -1;
    }

    int count;
    GLFWmonitor** monitors = glfwGetMonitors(&count);

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

    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    GLFWwindow* window0;
    GLFWwindow* window1;

    window0 = glfwCreateWindow(1680, 1050, "OpenGL", monitors[2], window1); // Front Screen
    window1 = glfwCreateWindow(1280, 800, "OpenGL", monitors[1], window0); // Back Screen

    glfwMakeContextCurrent(window0);
    glfwSetKeyCallback(window0, key_callback);

    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK)
    {
        fprintf(stderr, "Failed to initialize GLEW\n");
        return -1;
    }

     // Vertex array object - Contains all vertex information
    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    // Vertex buffer object
    GLuint vbo;
    glGenBuffers(1, &vbo);

    // Vertices to use inside my shader
    GLfloat vertices[] = {
        -1.0f,  1.0f, 0.0f, 0.0f,
         1.0f,  1.0f, 1.0f, 0.0f,
         1.0f, -1.0f, 1.0f, 1.0f,
        -1.0f, -1.0f, 0.0f, 1.0f
    };

    // Attached vertices to my GPU
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // Element buffer object - allows me to reuse vertices
    GLuint ebo;
    glGenBuffers(1, &ebo);

    // Index into the rows of vertices to use different vertices more than once
    GLuint elements[] = {
        0, 1, 2,
        2, 3, 0
    };

    // Attach element array to use on GPU
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);

    // Set up shader
    // Vertex Shader
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexSource, NULL);
    glCompileShader(vertexShader);
    printShaderInfoLog(vertexShader);

    // Fragment shader
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
    glCompileShader(fragmentShader);
    printShaderInfoLog(fragmentShader);

    // Shader program
    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glBindFragDataLocation(shaderProgram, 0, "outColor0");
    glBindFragDataLocation(shaderProgram, 1, "outColor1");
    printProgramInfoLog(shaderProgram);
    glLinkProgram(shaderProgram);

    GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 4*sizeof(float), 0);

    GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
    glEnableVertexAttribArray(texAttrib);
    glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE,
                            4*sizeof(float), (void*)(2*sizeof(float)));

    cv::VideoCapture cap("movie.mov");
    cv::Mat image0;
    cv::Mat image1;
    int width = cap.get(CV_CAP_PROP_FRAME_WIDTH);
    int height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
    // float ratio = width/(float)height;

    //Set up samplers
    GLuint ldrTextures[2];
    glGenTextures(2, ldrTextures);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, ldrTextures[0]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
                    GL_BGR, GL_UNSIGNED_BYTE, NULL);

    glUniform1i(glGetUniformLocation(shaderProgram, "texLite"), 0);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, ldrTextures[1]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
                    GL_BGR, GL_UNSIGNED_BYTE, NULL);

    glUniform1i(glGetUniformLocation(shaderProgram, "texDark"), 1);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 

    //Set up framebuffer
    GLuint frameBuffer;
    glGenFramebuffers(1, &frameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);

    //Set up target textures
    GLuint dispTextures[2];
    glGenTextures(2, dispTextures);

    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, dispTextures[0]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
                    GL_BGR, GL_UNSIGNED_BYTE, NULL);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dispTextures[0], 0);  

    glActiveTexture(GL_TEXTURE3);
    glBindTexture(GL_TEXTURE_2D, dispTextures[1]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
                    GL_BGR, GL_UNSIGNED_BYTE, NULL);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, dispTextures[1], 0);

    GLenum bufs[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
    glDrawBuffers(2, bufs);

    bool success;

    //Render loop
    while(!glfwWindowShouldClose(window0) && !glfwWindowShouldClose(window1))
    {
        std::cout << "Loop" << std::endl;

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        // glClear(GL_COLOR_BUFFER_BIT);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        //Grab two frames from video
        success = cap.read(image0);

        if(!success)
        {
            std::cout << "Could not grab a frame" << std::endl;
            exit(0);
        }

        success = cap.read(image1);

        if(!success)
        {
            std::cout << "Could not grab a frame" << std::endl;
            exit(0);
        }

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, ldrTextures[0]);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
                    GL_BGR, GL_UNSIGNED_BYTE, image0.data);

        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, ldrTextures[1]);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
                    GL_BGR, GL_UNSIGNED_BYTE, image1.data);

        glfwMakeContextCurrent(window0);
        glfwSetKeyCallback(window0, key_callback);

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glUseProgram(shaderProgram);

        // glViewport(0,0,width,height);

        // glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        glActiveTexture(GL_TEXTURE2);
        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
        glActiveTexture(GL_TEXTURE3);
        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0);
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

        glfwMakeContextCurrent(window0);
        glfwSetKeyCallback(window0, key_callback);

        glViewport(0,0,width,height);

        glActiveTexture(GL_TEXTURE2);
        glBindTexture(GL_TEXTURE_2D, dispTextures[0]);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        glfwSwapBuffers(window0);
        glfwPollEvents();

        glfwMakeContextCurrent(window1);
        glfwSetKeyCallback(window1, key_callback);

        glViewport(0,0,width,height);

        glActiveTexture(GL_TEXTURE3);
        glBindTexture(GL_TEXTURE_2D, dispTextures[1]);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        glfwSwapBuffers(window1);
        glfwPollEvents();
    }

    //Clean up memory, remember good coding practices
    glDeleteTextures(1, ldrTextures);
    glDeleteTextures(1, dispTextures);

    glDeleteFramebuffers(1, &frameBuffer);

    glDeleteProgram(shaderProgram);
    glDeleteShader(fragmentShader);
    glDeleteShader(vertexShader);

    glDeleteBuffers(1, &ebo);
    glDeleteBuffers(1, &vbo);

    glDeleteVertexArrays(1, &vao);

    glfwTerminate();

}

【问题讨论】:

  • texLitetexDark 是我原来的两张图片。我正在使用 OpenCv 读取它们并将它们转换为纹理,然后在着色器中将它们用作采样器。每次调用glUseProgram 时,我都需要将outColor0outColor1 作为两个新纹理。有没有办法把我的颜色附件变成纹理?
  • @Maggic:您可以渲染到纹理,因此您的颜色附件可以是纹理。但我真的不明白这一切的意义。你到底想在这里解决什么问题?
  • 我有两个显示器(两个不同的显示器)我想运行一个处理一系列图像/纹理的着色器,然后我需要从该着色器返回两个图像/纹理/颜色附件。每个颜色附件都需要渲染到不同屏幕上的四边形上。由于某种原因,我无法在两个屏幕上渲染。但我试图看看是否可以将颜色附件重新转换为纹理并使用新的着色器在每个不同的监视器上显示每个纹理。如果有助于理解,我附上了完整的代码
  • 老实说,这听起来更像是多个渲染上下文和资源共享的问题。您是否尝试使用单独的窗口来驱动这些显示器中的每一个?默认情况下,每个窗口的渲染上下文不会共享同一组资源名称,所以这可能是您的问题。
  • 是的。但是我已经设置了两个窗口来共享资源。 GLFWwindow* window0;GLFWwindow* window1;window0 = glfwCreateWindow(1680, 1050, "OpenGL", monitors[2], window1); // Front Screenwindow1 = glfwCreateWindow(1280, 800, "OpenGL", monitors[1], window0); // Back Screen

标签: opengl glsl glfw glew


【解决方案1】:

您的示例代码仅显示了一个正在编译和链接的 GLSL 着色器程序。您应该在这里有两个不同的程序,一个用于第一遍,另一个用于第二遍(缺失)。

一旦您解决了该问题,您将需要相应地设置采样器。从您的第一个窗口 (window0) 的代码来看,它将使用采样器 tex = 2。第二个窗口 (window1) 将使用 tex = 3。现在,如果您了解 OpenGL 中的每个渲染上下文都有自己的状态机(换句话说,纹理绑定状态不会在您的两个窗口之间共享),这实际上是完全没有必要的。您可以在两个渲染上下文中将每个窗口使用的纹理绑定到 2,然后不必将 tex 采样器制服的值设置为 2 以外的任何值。

什么是必要的,真正困扰我的是,您正试图将一个渲染上下文的输出用作另一个渲染上下文的输入,而没有同步。 OpenGL 中的渲染上下文不同步,无法保证您在window0 中执行的第一遍命令在window1 尝试从其输出图像中读取时完成。最简单的解决方法是在从window0 切换到window1 之前添加对glFinish () 的调用,这将导致OpenGL 阻塞,直到所有这些命令完成。它不是最高效的解决方案(栅栏同步会更好),但它是最简单的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多