【OpenGL】高级片段着色器——高斯模糊和索贝尔边缘检测

顶点着色器 convolve.vs

#version 150
precision highp float;

in vec2 position;

out Fragment
{
    vec2 tex_coord;
} fragment;

void main(void)
{
    gl_Position = vec4(position, 0.5, 1.0);

    // This produces a texture coordinate that ranges from (0.0, 0.0) to (1.0, 1.0)
    fragment.tex_coord = position * 0.5 + vec2(0.5, 0.5);
}

高斯模糊着色器 convolve.fs

#version 150
precision highp float;

// Input interface block from vertex shader
in Fragment
{
    vec2 tex_coord;
} fragment;

//
uniform sampler2D tex_input_image;

uniform samplerBuffer tbo_coefficient;

uniform vec2 tc_scale;

uniform int kernel_size;

out vec4 output_color;

void main(void)
{
    int filter_size = kernel_size; // textureSize(tbo_coefficient);
    vec4 color = vec4(0.0);
    vec2 tc_offset;
    float coefficient;

    for (int i = 0; i < filter_size; i++) {
        coefficient = texelFetch(tbo_coefficient, i).r;
        tc_offset = float(i - filter_size / 2) * tc_scale;
        color += coefficient * texture(tex_input_image, fragment.tex_coord + tc_offset);
    }

    // output_color = texture(tex_input_image, fragment.tex_coord) * texelFetch(tbo_coefficient, 3).r;
    output_color = color;
}

索贝尔边缘检测片段着色器 absvalue.fs 

#version 150
precision highp float;

// Input interface block from vertex shader
in Fragment
{
    vec2 tex_coord;
} fragment;

//
uniform sampler2D tex_input_image;

out vec4 output_color;

void main(void)
{
    output_color = abs(texture(tex_input_image, fragment.tex_coord));
}
#include "explode.h"

ConvolutionApp::ConvolutionApp(void)
    : screenWidth(1024 + 16), screenHeight(768 + 32)
{

}

void ConvolutionApp::Initialize(void)
{
    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        /* Problem: glewInit failed, something is seriously wrong. */
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
    }

    instancingProg = gltLoadShaderPair("convolve.vs", "convolve.fs");
    glBindAttribLocation(instancingProg, 0, "position");
    glLinkProgram(instancingProg);

    absValueProg = gltLoadShaderPair("convolve.vs", "absvalue.fs");
    glBindAttribLocation(instancingProg, 0, "position");
    glLinkProgram(instancingProg);

    glUseProgram(instancingProg);

    GLbyte *pBits;
    int nWidth, nHeight, nComponents;
    GLenum eFormat;

    // Read the texture bits
    pBits = gltReadTGABits("image.tga", &nWidth, &nHeight, &nComponents, &eFormat);

    glGenTextures(1, &sourceTexture);
    glBindTexture(GL_TEXTURE_2D, sourceTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBits);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glGenFramebuffers(1, &intermediateFBO);
    glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
    glGenTextures(1, &intermediateTexture);
    glBindTexture(GL_TEXTURE_2D, intermediateTexture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 1027, 768, 0, GL_RGBA, GL_FLOAT, NULL);
    glBindTexture(GL_TEXTURE_2D, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, intermediateTexture, 0);

    glGenFramebuffers(1, &targetFBO);
    glBindFramebuffer(GL_FRAMEBUFFER, targetFBO);
    glGenTextures(1, &targetTexture);
    glBindTexture(GL_TEXTURE_2D, targetTexture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 1027, 768, 0, GL_RGBA, GL_FLOAT, NULL);
    glBindTexture(GL_TEXTURE_2D, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, targetTexture, 0);

    /*
    static const GLfloat kernel[] =
    {
        0.015625, 0.09375, 0.234375, 0.3125, 0.234375, 0.09375, 0.015625
    };
    */

    static const GLfloat gaussian_kernel[] =
    {
        0.004f,
        0.008f,
        0.014f,
        0.022f,
        0.033f,
        0.046f,
        0.061f,
        0.076f,
        0.089f,
        0.098f,
        0.101f,
        0.098f,
        0.089f,
        0.076f,
        0.061f,
        0.046f,
        0.033f,
        0.022f,
        0.014f,
        0.008f,
        0.004f
    };

    /*
    static const GLfloat gaussian_kernel[] =
    {
        0.0f,
        0.0f,
        0.0f,
        0.0f,
        0.0f,
        0.0f,
        0.0f,
        0.0f,
        0.0f,
        0.0f,
        1.0f,
        0.0f,
        0.0f,
        0.0f,
        0.0f,
        0.0f,
        0.0f,
        0.0f,
        0.0f,
        0.0f,
        0.0f
    };
    */

    // glUniform2f(glGetUniformLocation(instancingProg, "tc_scale"), 1.0f / (float)nWidth, 0.0f); // 1.0f / (float)nHeight);
    // glUniform2f(glGetUniformLocation(instancingProg, "tc_scale"), 0.0f, 1.0f / (float)nHeight);
    kernelScale[0] = 1.0f / (float)nWidth;
    kernelScale[1] = 1.0f / (float)nHeight;
    glUniform1i(glGetUniformLocation(instancingProg, "tex_input_image"), 0);
    glUniform1i(glGetUniformLocation(instancingProg, "tbo_coefficient"), 1);

    glActiveTexture(GL_TEXTURE1);
    glGenTextures(1, &gaussian_kernelTexture);
    glBindTexture(GL_TEXTURE_BUFFER, gaussian_kernelTexture);
    glGenBuffers(1, &gaussian_kernelBuffer);
    glBindBuffer(GL_TEXTURE_BUFFER, gaussian_kernelBuffer);
    glBufferData(GL_TEXTURE_BUFFER, sizeof(gaussian_kernel), gaussian_kernel, GL_STATIC_DRAW);
    glTexBufferARB(GL_TEXTURE_BUFFER, GL_R32F, gaussian_kernelBuffer);

    static const GLfloat sobel_kernel1[] =
    {
        1.0f, 2.0, 1.0f
    };

    static const GLfloat sobel_kernel2[] =
    {
        1.0f, 0.0f, -1.0f
    };

    glGenTextures(1, &sobel_kernelTexture1);
    glBindTexture(GL_TEXTURE_BUFFER, sobel_kernelTexture1);
    glGenBuffers(1, &sobel_kernelBuffer1);
    glBindBuffer(GL_TEXTURE_BUFFER, sobel_kernelBuffer1);
    glBufferData(GL_TEXTURE_BUFFER, sizeof(sobel_kernel1), sobel_kernel1, GL_STATIC_DRAW);
    glTexBufferARB(GL_TEXTURE_BUFFER, GL_R32F, sobel_kernelBuffer1);

    glGenTextures(1, &sobel_kernelTexture2);
    glBindTexture(GL_TEXTURE_BUFFER, sobel_kernelTexture2);
    glGenBuffers(1, &sobel_kernelBuffer2);
    glBindBuffer(GL_TEXTURE_BUFFER, sobel_kernelBuffer2);
    glBufferData(GL_TEXTURE_BUFFER, sizeof(sobel_kernel2), sobel_kernel2, GL_STATIC_DRAW);
    glTexBufferARB(GL_TEXTURE_BUFFER, GL_R32F, sobel_kernelBuffer2);

    static const GLfloat square_vertices[] =
    {
        -1.0f, -1.0f,
         1.0f, -1.0f,
        -1.0f,  1.0f,
         1.0f,  1.0f
    };

    GLuint offset = 0;

    glGenVertexArrays(1, &square_vao);
    glGenBuffers(1, &square_vbo);
    glBindVertexArray(square_vao);
    glBindBuffer(GL_ARRAY_BUFFER, square_vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(square_vertices), square_vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);

    glEnableVertexAttribArray(0);
}

void ConvolutionApp::Shutdown(void)
{
    glDeleteBuffers(1, &square_vbo);
    glDeleteVertexArrays(1, &square_vao);
}

void ConvolutionApp::Resize(GLsizei nWidth, GLsizei nHeight)
{
    screenWidth = nWidth;
    screenHeight = nHeight;
    glViewport(0, 0, nWidth, nHeight);
}

void ConvolutionApp::Render(void)
{
    glUseProgram(instancingProg);
    glBindVertexArray(square_vao);

    //高斯模糊
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_BUFFER, gaussian_kernelTexture);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, sourceTexture);

    glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glUniform1i(glGetUniformLocation(instancingProg, "kernel_size"), 21);
    glUniform2f(glGetUniformLocation(instancingProg, "tc_scale"), 0.0f, kernelScale[1]);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glBindTexture(GL_TEXTURE_2D, intermediateTexture);

    glUniform2f(glGetUniformLocation(instancingProg, "tc_scale"), kernelScale[0], 0.0f);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    /* 索贝边缘检测 代码段 开启它时需注释上面的
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_BUFFER, sobel_kernelTexture1);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, sourceTexture);

    glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glUniform1i(glGetUniformLocation(instancingProg, "kernel_size"), 3);
    glUniform2f(glGetUniformLocation(instancingProg, "tc_scale"), 0.0f, kernelScale[1]);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glBindFramebuffer(GL_FRAMEBUFFER, targetFBO);
    glBindTexture(GL_TEXTURE_2D, intermediateTexture);

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_BUFFER, sobel_kernelTexture2);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glActiveTexture(GL_TEXTURE0);

    glBindTexture(GL_TEXTURE_2D, targetTexture);

    glUseProgram(absValueProg);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    */
    GLenum e = glGetError();
}

高斯模糊相关说明:其中sourceImage是原图纹理,作为第一个纹理目标传入,第二个纹理目标是以纹理缓冲区形式传入convolve.fs即tbo_coefficient变量,它是高斯模糊一维纹理数据,关于纹理缓冲区数据是samplerBuffer类型的,它的获取是直接根据整数纹理来拿到对应的数据,最终我们在convolve.fs得到一个经过高斯模糊的颜色值进行输出。

索贝尔边缘检测相关说明:它总共经过3次glDrawArrays进行渲染屏幕四边形。

第一次是使用sourceTexture纹理作为第一纹理和sobel_kernelTexture1作为第二纹理,去使用instancingProg着色器生成intermediateFBO捆绑的intermediateTexture;

第二次使用intermediateTexture作为第一纹理和sobel_kernelTexture2作为第二纹理,使用instancingProg着色器生成targetFBO捆绑的targetTexture;

第三次使用targetTexture纹理作为第一纹理,使用absValueProg着色器渲染,将结果输出到帧缓冲区(屏幕上)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值