首页 > 解决方案 > OpenGL - 如何将帧缓冲区中的纹理用作新纹理?

问题描述

我正在尝试学习 OpenGL 语言,并且我想做一些代码,对图像进行水平模糊 (HR),然后对上一个结果进行垂直模糊 (VB)。

我为此使用了帧缓冲区,但我不确定如何将帧缓冲区中的纹理用作新纹理。

这是我的代码:

// Include standard headers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <ctime>

#include <iostream>

//#include <opencv.hpp>
#include <opencv/cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv/highgui.h>
using namespace cv;

// Include GLEW
#include <GL/glew.h> 

// Include GLFW
#include <GLFW/glfw3.h> 

#include <shader.hpp>
using namespace std;

int width = 512;// 1024;
int height = 512;// 768;

// perspective projection
bool perspective_ = false;

// shader variable pointers
GLint uniform_srcTex;
GLint uniform_srcTex1;
GLint uniform_offset_x;
GLint uniform_offset_y;

////////////////////////////////////////
// glfw callbacks for keystroke and error
void error_callback(int error, const char* description)
{
    fputs(description, stderr);
}

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

void char_callback(GLFWwindow* window, unsigned int key)
{
    if (key == 'p' || key == 'P')
        perspective_ = true;
    if (key == 'o' || key == 'O')
        perspective_ = false;
}

/////////////////////////////////////////////
// texture loading
bool loadtexture(string fileName, GLuint & texIndex, GLuint texUnit, bool isRect)
{

// texture load through OpenCV
    Mat image = cv::imread(fileName, CV_LOAD_IMAGE_UNCHANGED);   // Read the file
    if (!image.data) // Check for invalid input
    {
        cout << "Could not open or find the image\n";
        return false;
    }
    cout << "Loaded " << fileName.c_str() << " (" << image.channels() << " channels)\n";

    int colorTransform = (image.channels() == 4) ? CV_BGRA2RGBA : (image.channels() == 3) ? CV_BGR2RGB : CV_GRAY2RGB;
    //if (image[index].channels() >= 3)
    //{
        cv::cvtColor(image, image, colorTransform);
    //}

    glEnable(GL_TEXTURE_2D);
    glGenTextures(1, &texIndex);
    glActiveTexture(texUnit);
    GLenum target = GL_TEXTURE_2D;
    if (isRect)
    {
        target = GL_TEXTURE_RECTANGLE;
    }
    glBindTexture(target, texIndex);
    if (image.channels() > 3)
    {
        glTexImage2D(target, 0, GL_RGBA8, image.cols, image.rows, 0, GL_RGBA, (image.depth()<2)?GL_UNSIGNED_BYTE: ((image.depth()<4) ? GL_UNSIGNED_SHORT : GL_FLOAT), image.ptr());
    }
    else
    {
        glTexImage2D(target, 0, GL_RGB, image.cols, image.rows, 0, GL_RGB, (image.depth()<2) ? GL_UNSIGNED_BYTE : ((image.depth()<4) ? GL_UNSIGNED_SHORT : GL_FLOAT), image.ptr());
    }
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    // glGenerateMipmap(GL_TEXTURE_2D);
    return true;
    }

void consoleMessage()
{
    cout << "Renderer : " << string((char*)glGetString(GL_RENDERER)) << endl;
    cout << "OpenGL version: " << string((char*)glGetString(GL_VENDOR)) << " / " << string((char*)glGetString(GL_VERSION)) << endl;
    cout << "GLSL version: " << string((char*)glGetString(GL_SHADING_LANGUAGE_VERSION)) << endl;
    cout << "GLEW version: " << string((char*)glewGetString(GLEW_VERSION)) << endl << endl;

    GLint MaxTextureUnits;
    glGetIntegerv(GL_MAX_TEXTURE_UNITS, &MaxTextureUnits);
    cout << "Max supported textures : " << MaxTextureUnits << endl << endl;
}


////////////////////////////////////////
// main file
int main()
{
    // start GL context and O/S window using the GLFW helper library
    if (!glfwInit()) // Initialise GLFW
    {
        fprintf(stderr, "ERROR: could not start GLFW3\n");
        return 1;
    }

    GLFWwindow* window = glfwCreateWindow(width, height, "test1", NULL, NULL);
    if (!window)
    {
        fprintf(stderr, "ERROR: could not open window with GLFW3\n");
        glfwTerminate();
        return 1;
    }
    glfwMakeContextCurrent(window); // Initialise GLEW

    // Set key callback function
    glfwSetErrorCallback(error_callback); 
    glfwSetKeyCallback(window, key_callback); 
    glfwSetCharCallback(window, char_callback); 

    // start GLEW extension handler
    glewExperimental = GL_TRUE; 
    glewInit(); // Initialise GLEW

    // get version info
    consoleMessage();

    GLuint srcTexIndex;

    if (!loadtexture("blablabla.png", srcTexIndex, GL_TEXTURE0, true)) 
    { 
        return -1;
    }

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    ////////////////////////////////////////
    // Load shaders
    GLuint shader_image_programme_HB = LoadShaders("shaders/SimpleVertexShader_VS_HB.glsl", "shaders/AddGrain_FS_HB.glsl");
    GLuint shader_image_programme_VB = LoadShaders("shaders/SimpleVertexShader_VS_VB.glsl", "shaders/AddGrain_FS_VB.glsl");

    ////////////////////////////////////////
    // shader parameter bindings

    uniform_srcTex = glGetUniformLocation(shader_image_programme_HB, "srcTex"); 
    uniform_offset_x = glGetUniformLocation(shader_image_programme_HB, "offset_x");
    uniform_offset_y = glGetUniformLocation(shader_image_programme_HB, "offset_y");

    const int nb_frame = 4096;

    vector<float> offset_x(nb_frame, 0.0);
    vector<float> offset_y(nb_frame, 0.0);

    int frame_index = 0;

    glUseProgram(shader_image_programme_HB); 

    glUniform1i(uniform_srcTex, 0); //Texture unit 0

    // input texture (loaded texture)
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_RECTANGLE, srcTexIndex);

    // setup the projection
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, (double)width, 0, (double)height, -1, 1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // The framebuffer, which regroups 0, 1, or more textures, and 0 or 1 depth buffer.
    GLuint FramebufferName;
    glGenFramebuffers(1, &FramebufferName);
    glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);

    // The texture we're going to render to
    GLuint renderedTexture;
    glGenTextures(1, &renderedTexture);

    glActiveTexture(GL_TEXTURE1);
    // "Bind" the newly created texture : all future texture functions will modify this texture
    glBindTexture(GL_TEXTURE_2D, renderedTexture);

    // Give an empty image to OpenGL ( the last "0" )
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, 0);

    // Poor filtering. Needed !
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    // Set "renderedTexture" as our colour attachement #0
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0);

    // Set the list of draw buffers.
    GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
    glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers

    // Always check that our framebuffer is ok
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    {
        printf("Error with Frame Buffer !!!\n");
        return 1;
    }

    // Render to our framebuffer
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    cout << "ok HB" << endl;


    GLuint srcTexIndex1;

    uniform_srcTex1 = glGetUniformLocation(shader_image_programme_VB, "srcTex"); 
    uniform_offset_x = glGetUniformLocation(shader_image_programme_VB, "offset_x");
    uniform_offset_y = glGetUniformLocation(shader_image_programme_VB, "offset_y");

    frame_index = 0;

    glUseProgram(shader_image_programme_VB); // On dit à OpenGL qu'on veut utiliser les shaders

    glUniform1i(uniform_srcTex1, 1); //Texture unit 1

    // input texture (loaded texture)
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_RECTANGLE, srcTexIndex1);

    // setup the projection
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, (double)width, 0, (double)height, -1, 1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // The framebuffer, which regroups 0, 1, or more textures, and 0 or 1 depth buffer.
    GLuint FramebufferName1;
    glGenFramebuffers(1, &FramebufferName1);
    glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName1);

    // The texture we're going to render to
    GLuint renderedTexture1;
    glGenTextures(1, &renderedTexture1);

    glActiveTexture(GL_TEXTURE2);
    // "Bind" the newly created texture : all future texture functions will modify this texture
    glBindTexture(GL_TEXTURE_2D, renderedTexture1);

    // Give an empty image to OpenGL ( the last "0" )
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, 0);

    // Poor filtering. Needed !
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    // Set "renderedTexture" as our colour attachement #1
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, renderedTexture1, 0);

    // Set the list of draw buffers.
    GLenum DrawBuffers1[1] = { GL_COLOR_ATTACHMENT1 };
    glDrawBuffers(1, DrawBuffers1); // "1" is the size of DrawBuffers

    // Always check that our framebuffer is ok
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    {
        printf("Error with Frame Buffer !!!\n");
        return 1;
    }

    // Render to our framebuffer
    glBindFramebuffer(GL_FRAMEBUFFER, 0);


    cout << "ok VB" << endl;

    glViewport(0, 0, width, height); // Render on the whole framebuffer, complete from the lower left corner to the upper right

    // Returned data
    Mat myData = Mat::zeros(height, width, CV_32FC3);

    ////////////////////////////////////////
    // endless rendering loop
    int nbFrames = 0;

    clock_t start = clock();

    while (!glfwWindowShouldClose(window))
    {


        //////////////////////////////////////////////////
        // PASS #1
        // output buffer cleanup
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

        glUniform1f(uniform_offset_x, offset_x[frame_index]);
        glUniform1f(uniform_offset_y, offset_y[frame_index]);

        // Define the drawing area by setting the corresponding vertices
        glBegin(GL_QUADS);
        glVertex2f(0., 0.);
        glVertex2f(0., (float)height);
        glVertex2f((float)width, (float)height);
        glVertex2f((float)width, 0.);
        glEnd();


        if (nbFrames == 0)
        {
            glReadPixels(0, 0, width, height, GL_RGB, GL_FLOAT, myData.ptr(0));

            myData.convertTo(myData, CV_8U, 255.0, 0.0);

            imwrite("C:/Temp/images/testOpenGL.png", myData);
        }


        ///////////////////////////////////////
        // EVENTS + FB swap 
        // Permet de quitter la fenêtre avec la touche esc

        // update other events like input handling 
        glfwPollEvents();

        // put the stuff we've been drawing onto the display
        glfwSwapBuffers(window);

        nbFrames++;
        frame_index = (frame_index + 1) % 4096;
    }

    clock_t duration = clock() - start;

    //printf("%d processed frames\n", nbFrames);

    cout << nbFrames << " in " << duration << " ms : " << 1000.0*(float)nbFrames / (float)duration << " frame/s" << endl;

    // close GL context and any other GLFW resources
    glfwDestroyWindow(window);
    glfwTerminate();
    exit(EXIT_SUCCESS);
}

HB 的顶点着色器:

void main()
{
    gl_Position = ftransform();
}

VB 的顶点着色器:

void main()
{
    gl_Position = ftransform();
}

HB 的片段着色器:

in vec2 texCoordOut;
layout (location = 0) out vec4 outColor0;
uniform sampler2DRect srcTex;

uniform float offset_x;
uniform float offset_y;

const vec2 texOffset = vec2(1.0, 1.0);
const int BLUR_AMOUNT = 100;

void main()
{
    vec2 CoordRef = gl_FragCoord.xy + vec2(offset_x,offset_y);
    vec3 luma = vec3(0);
    luma = texture2DRect( srcTex, CoordRef ).rgb;

    for (int i = 1; i < BLUR_AMOUNT+1; ++i) {
        luma.r += texture2DRect( srcTex, CoordRef + vec2(0, i) ).r * 0.5/BLUR_AMOUNT;
        luma.g += texture2DRect( srcTex, CoordRef + vec2(0, i) ).g * 0.5/BLUR_AMOUNT;
        luma.b += texture2DRect( srcTex, CoordRef + vec2(0, i) ).b * 0.5/BLUR_AMOUNT;
    }
    vec4 out_bw = vec4(luma, 1.0);
    gl_FragColor = out_bw;  
}

VB 的片段着色器:

in vec2 texCoordOut;
layout (location = 0) out vec4 outColor0;
uniform sampler2DRect srcTex; 

uniform float offset_x;
uniform float offset_y;

const vec2 texOffset = vec2(1.0, 1.0);
const int BLUR_AMOUNT = 100;

void main()
{
    vec2 CoordRef = gl_FragCoord.xy + vec2(offset_x,offset_y);
    vec3 luma = vec3(0);
    luma = texture2DRect( srcTex, CoordRef ).rgb;

    for (int i = 1; i < BLUR_AMOUNT+1; ++i) {
        luma.r += texture2DRect( srcTex, CoordRef + vec2(i, 0) ).r * 0.5/BLUR_AMOUNT;
        luma.g += texture2DRect( srcTex, CoordRef + vec2(i, 0) ).g * 0.5/BLUR_AMOUNT;
        luma.b += texture2DRect( srcTex, CoordRef + vec2(i, 0) ).b * 0.5/BLUR_AMOUNT;
    }

    vec4 out_bw = vec4(luma, 1.0);
    gl_FragColor = out_bw;
}

最后,我有一个全黑屏,这不是参加的结果(我检查过)。所有着色器都工作正常,这是两个着色器的完整序列不起作用。你能告诉我我在代码中做了什么错误吗?

谢谢您的帮助 !

标签: openglglslframebuffer

解决方案


推荐阅读