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的主要内容,如果未能解决你的问题,请参考以下文章
如何获得在着色器中用作Vulkan API中的变量的GPU输入?