GPU 上的图像处理 - 过滤器的连续着色器 - FBO

Posted

技术标签:

【中文标题】GPU 上的图像处理 - 过滤器的连续着色器 - FBO【英文标题】:Image Processing on GPU- sucessive shaders for filters - FBO 【发布时间】:2010-07-09 17:52:01 【问题描述】:

我目前正在尝试在 OpenGL 图像处理算法中实现。

我想连续使用几个着色器来执行多个过滤器(Sobel Gaussian,...)。 我知道要做到这一点,我必须通过 FBO 渲染纹理。我读了很多关于这个的东西,并写了一个代码。但我没有得到我预期的结果。

目前,我只是尝试使用两个着色器。所以,我有一个原始图像,它是我的第一个着色器的输入。然后,我想将着色器的输出渲染为纹理,然后将其作为第二个着色器的输入(乒乓技术)。最后,我想显示第二个着色器的输出。

但结果,我得到了原始图像。

我的代码如下:

/******************** Shaders Function *******************************/
void setupShaders(char *vert, char *frag, GLuint p) 
GLuint v, f;
char *vs = NULL,*fs = NULL; 
v = glCreateShader(GL_VERTEX_SHADER);
f = glCreateShader(GL_FRAGMENT_SHADER);
vs = textFileRead(vert); 
fs = textFileRead(frag);
const char * ff = fs;
const char * vv = vs;
glShaderSource(v, 1, &vv, NULL);
glShaderSource(f, 1, &ff, NULL);
free(vs);free(fs);
glCompileShader(v);
glCompileShader(f);
p = glCreateProgram();
glAttachShader(p,f);
glAttachShader(p,v);
glLinkProgram(p);
glUseProgram(p);
 
/******************** Texture Function ***********************************/
void setupTexture(void) 
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_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

/******************** Quad Drawing Function ******************************/
void ShaderDraw(void)
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.0); 
glTexCoord2f(0.0, 1.0); glVertex3f(0.0, height, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(width, height, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(width, height, 0.0);
glEnd();


/******************** Initialization Function ***************************/
void init(void)
 
//Checking GLSL 
glewInit();
if (glewIsSupported("GL_VERSION_2_0"))
printf("Ready for OpenGL 2.0\n");
else 
printf("OpenGL 2.0 not supported\n");
exit(1);


// Init
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);

/******************** Display Function **********************************/
void display(void)

glEnable(GL_TEXTURE_2D);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(-4.0, -4.0, 0.0); 
glTexCoord2f(0.0, 1.0); glVertex3f(-4.0, 4.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(4.0, 4.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(4.0, -4.0, 0.0);
glEnd();

glFlush();
glDisable(GL_TEXTURE_2D);

/******************** Reshape Function *********************************/
void reshape(int w, int h)

glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -7.0);

/******************** Main Function *************************************/
int main(int argc, char** argv)
 
// Glut Initialisation
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
// Window Generation
glutInitWindowSize(1000,800);
glutInitWindowPosition(100, 100); 
glutCreateWindow("Night Vision");

// Initialisation Function
init();

// Downloading Image
data = cLoadBitmap("lena.bmp", &height, &width);
checkGLErrors ("Downloading Image");

int read_tex = 0;
int write_tex = 1;

// Generating Texture
glEnable(GL_TEXTURE_2D);
glGenTextures(2, texImg);
// Init Texture0
glActiveTexture(GL_TEXTURE0);   
glBindTexture(GL_TEXTURE_2D, texImg[read_tex]);
setupTexture();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
checkGLErrors ("InitTexture0");
// Init Texture1
glActiveTexture(GL_TEXTURE1); 
glBindTexture(GL_TEXTURE_2D, texImg[write_tex]);
setupTexture();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
checkGLErrors ("InitTexture1");

// Setup Framebuffer Object
GLuint fb;
glGenFramebuffersEXT(1, &fb);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
checkGLErrors ("Framebuffer->fb");

GLenum att_point[] = GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT;
glBindTexture(GL_TEXTURE_2D, texImg[read_tex]);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, att_point[read_tex], GL_TEXTURE_2D, texImg[read_tex], 0);
glBindTexture(GL_TEXTURE_2D, texImg[write_tex]);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, att_point[write_tex], GL_TEXTURE_2D, texImg[write_tex], 0);
checkFramebufferStatus();

//set the write texture as output buffer for the shader
glDrawBuffer(att_point[write_tex]);

// create, init and enable the shader
setupShaders("filter.vert", "sobel_filter_3.frag", p1);
checkGLErrors ("Shaders 1");
// attach the input texture(read texture) to the first texture unit
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,texImg[read_tex]);
GLuint texLoc; 
texLoc = glGetUniformLocation(p1,"tex"); 
glUniform1i(texLoc, 0); 
// draw a square with the texture on it so to perform the computation
ShaderDraw();

// swap the buffers
read_tex = 1;
write_tex = 0;

// Delete program 1 
glDeleteProgram(p1);

// set the write texture as output buffer for the shader
glDrawBuffer(att_point[write_tex]);
// create, init and enable the shaders
setupShaders("filter.vert", "gaussian7.frag", p2);
checkGLErrors ("Shaders 2");
// attach the input texture(read texture) to the first texture unit
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,texImg[read_tex]); 
texLoc = glGetUniformLocation(p2,"tex"); 
glUniform1i(texLoc, 0); 
// draw a square with the texture on it so to perform the computation
ShaderDraw();

// Delete program 2 & disable the FBO 
glDeleteProgram(p2);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glUseProgram(0);

// Bind the texture to display
glBindTexture(GL_TEXTURE_2D,texImg[0]);

// Glut Functions: Display, Reshape, Keyboard
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
// Calling Main
glutMainLoop();
return 0; 

有人知道出了什么问题吗???

【问题讨论】:

嗨,zenna,我是 openframeworks 用户,我正在努力实现与您完全相同的目标。一个简单的乒乓着色器链接在一个 fbo 中。你解决了这个问题吗?你能指出一个解决方案吗?您能在 eloi attelenoika [dot] net 上写一封电子邮件吗...我不知道如何为您的帖子发邮件...非常感谢! 您听说过 OpenCL 和 CUDA 吗?我认为以可维护的方式执行这些操作是最先进的 【参考方案1】:

您正在尝试同时使用 FBO 作为渲染源和渲染目标。 Afaik 你不能这样做 - 如果你想使用绑定到 FBO 作为渲染源的纹理,你需要取消绑定 FBO(通过调用 glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); 或绑定另一个 FBO)。

看起来您正试图通过使用起始纹理作为 FBO 的颜色缓冲区来节省内存。我不确定这是否也可能。

因此您可能想尝试创建两个 FBO,每个 FBO 都有一个颜色缓冲区,然后交换整个 FBO,然后开始将纹理渲染到第一个 FBO。此外,不要将起始纹理用作 FBO 的颜色缓冲区,而是为每个 FBO 创建单独的颜色缓冲区。

在将纹理附加到 FBO 之前,您也不需要将纹理绑定到纹理单元。

【讨论】:

以上是关于GPU 上的图像处理 - 过滤器的连续着色器 - FBO的主要内容,如果未能解决你的问题,请参考以下文章

GPU上的纹理图像处理?

如何获得在着色器中用作Vulkan API中的变量的GPU输入?

GPU渲染管线概述

DirectX11 With Windows SDK--26 计算着色器:入门

WebGL着色器入门简介

第3章-图形处理单元-3.3-可编程着色器阶段