GLSL着色器实现多重纹理与帧缓冲对象(FBO)

本文介绍如何利用OpenGL实现多重纹理处理及帧缓存对象(FBO)的应用,通过实例展示了如何将不同权重矩阵作为纹理输入,并结合FBO完成图像处理任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

还记得我前面几篇博客上写的东西都是将纹理直接渲染到屏幕上,就是产生一个和纹理尺寸大小相同的窗口进行渲染,那么渲染完了就正好完整的显示了纹理图案。但是在做数值计算的时候,一般是不需要输出到屏幕上的,这就是今天我们要用到的帧缓存。有了帧缓存,我们的输出不需要是屏幕了,而是直接输出到帧缓存中去。而且帧缓冲区对象的使用还会对程序的性能有一定提升

那么帧缓冲对象到底是个什么东西呢?首先帧缓冲区你可以理解为就是一个概念,下面这个图可以很形象的解释帧缓冲区的意思。这里对这个图解释一下: 

       

其实真实存放数据的缓存就是纹理缓存和render缓存,FBO就是将纹理缓存和render缓存整了一个句柄关联起来,对其进行处理,现在理解为啥FBO只是一个概念了。


本篇博客主要有以下3个技术点:
1:将一个矩阵,这个矩阵存储着我们需要的数值,有可能就是一系数矩阵或者说权值矩阵,把这个矩阵放入纹理缓冲中,当做纹理来使用。
2:这里面用到了多重纹理,多重纹理的处理还是比单重的纹理处理的过程复杂的多的。
3:也是本文的重点,就是对帧缓存(FBO)的使用。

具体的使用还是要看代码吧。

大家在把代码贴到自己电脑上会缺少一个savePicture.h这个头文件,这个头文件包含了loadBMP和saveBMP两个函数,很抱歉,这两个函数不是我写的,不方便发到网上,但是这两个函数都是很简单的,大家可以自己到网上找到相关的函数来代替。有了这两个功能,程序就可以跑起来了。


[cpp]  view plain  copy
  1. #include "stdafx.h"  
  2. #include<windows.h>  
  3. #include <stdio.h>  
  4. #include <stdlib.h>  
  5. #include <GL/glew.h>  
  6. #include <GL/glut.h>  
  7. #include "savePicture.h"  
  8.   
  9. //纹理的编号  
  10. static GLuint texture;    //lena图像作为纹理  
  11. static GLuint texWeigArr1;  //自己生成的纹理1  
  12. static GLuint texWeigArr2;  //自己生成的纹理2  
  13. static GLuint texOutput;    //产生结果的纹理  
  14.   
  15. static GLuint fb;           //FBO编号  
  16.   
  17. #define printOpenGLError() printOglError(__FILE__, __LINE__)  
  18.   
  19. const GLint imgHeight = 512, imgWidth = 512;  
  20. const GLint imgHeight2 = 256, imgWidth2 = 256;  
  21. static GLfloat   weight_1[imgWidth][imgHeight];    //权值矩阵1  
  22. static GLfloat   weight_2[imgHeight2][imgWidth2];   //权值矩阵2  
  23. static  GLfloat outPutFb[imgHeight * imgWidth];   //输出纹理缓冲  
  24. static GLubyte  pData[imgHeight * imgWidth];   //存储最终的图像数据  
  25.   
  26. //顶点着色器  
  27. const char *vShader = {  
  28.     //"#version 110  \n "  
  29.     "void main()"  
  30.     "{"  
  31.         "gl_TexCoord[0] = gl_MultiTexCoord0;"  
  32.         "gl_TexCoord[1] = gl_MultiTexCoord1;"  
  33.         "gl_TexCoord[2] = gl_MultiTexCoord2;"  
  34.         "gl_Position = ftransform();"  
  35.     "}"  
  36. };  
  37.   
  38. //片元着色器  
  39. const char *fShader = {  
  40.     //"#version 110          \n "  
  41.     "#extension GL_ARB_texture_rectangle : enable  \n"  
  42.     "uniform sampler2DRect  LenaTexture;         \n"  
  43.     "uniform sampler2DRect  WeightTex1;         \n"  
  44.     "uniform sampler2DRect  WeightTex2;         \n"  
  45.     "void main()         \n"  
  46.     "{          \n"  
  47.         "vec2   weig1Pos =  gl_TexCoord[1].st;                  \n "  
  48.         "vec2   weig2Pos =  gl_TexCoord[0].st / 2.0;"  
  49.         "vec2     pos1 = vec2(gl_TexCoord[0].s,512.0-gl_TexCoord[0].t);"  
  50.         "vec4   texColor   =  texture2DRect(LenaTexture,pos1 );         \n"  
  51.         "vec4   weight1    =  texture2DRect(WeightTex1, weig1Pos);          \n "  
  52.         "vec4   weight2    =  texture2DRect(WeightTex2, weig2Pos);          \n"  
  53.         "texColor.yzw = vec3(0.0,0.0,0.0);         \n"  
  54.         "weight1.yzw = vec3(0.0,0.0,0.0);         \n"  
  55.         "if ( gl_TexCoord[0].s >256.0)"  
  56.         "{ gl_FragColor = texColor;     }   \n"  
  57.         "else"  
  58.         "{gl_FragColor =   weight1 * weight2;   }     \n"  
  59.     "}        \n"  
  60. };  
  61.   
  62. //输出错误相关信息  
  63. int printOglError(char *file, int line)  
  64. {  
  65.     GLenum glErr;  
  66.     int retCode = 0;  
  67.   
  68.     glErr = glGetError();  
  69.     while (glErr != GL_NO_ERROR)  
  70.     {  
  71.         printf("glError in file %s @ line %d: %s\n", file, line, gluErrorString(glErr));  
  72.         retCode = 1;  
  73.         glErr = glGetError();  
  74.     }  
  75.     return retCode;  
  76. }  
  77.   
  78. //输出opengl错误  
  79. void printInfoLog(GLhandleARB obj)  
  80. {  
  81.     int infologLength = 0;  
  82.     int charsWritten = 0;  
  83.     GLcharARB *infoLog;  
  84.     printOpenGLError();  
  85.   
  86.     glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infologLength);  
  87.     printOpenGLError();  
  88.   
  89.     if(infologLength > 0)  
  90.     {  
  91.         infoLog = (GLcharARB*)malloc(infologLength);  
  92.         if(infoLog == NULL)  
  93.         {  
  94.             printf("ERROR: Could not allocate InfoLog buffer\n");  
  95.             exit(1);  
  96.         }  
  97.         glGetInfoLogARB(obj,infologLength,&charsWritten,infoLog);  
  98.         printf("InfoLog:\n%s\n\n",infoLog);  
  99.         free(infoLog);  
  100.     }  
  101.     printOpenGLError();  
  102. }  
  103.   
  104.   
  105.   
  106. /************************************************************* 
  107. function name:   initShaders 
  108. input:   1.    const char *vShaderCode,  
  109.             2.     const char *fShaderCode, 
  110. output:  1.    -1   compile error 
  111.              2.    -2    link  error 
  112.              3.      progHandle     
  113. description: 
  114.                    
  115. *****************************************************************/  
  116. GLhandleARB initShaders( const char *vShaderCode, const char *fShaderCode )     
  117. {  
  118.     GLhandleARB vertHandle, fragHandle, progHandle;   //对象句柄  
  119.     GLint vertCompiled, fragCompiled;               //状态值  
  120.     GLint linked;  
  121.   
  122.     //创建顶点着色器对象和片元着色器对象  
  123.     vertHandle = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);  
  124.     fragHandle = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);  
  125.   
  126.     //将源代码字符串加载到着色器中  
  127.     glShaderSource( vertHandle, 1, &vShaderCode, NULL );  
  128.     glShaderSource( fragHandle, 1, &fShaderCode, NULL );  
  129.   
  130.     printf("编译码块顶点着色器并打印编译器日志文件:\n");  
  131.     //编译码块顶点着色器并打印编译器日志文件  
  132.     glCompileShaderARB(vertHandle);  
  133.     printOpenGLError();             //检查opengl错误  
  134.     glGetObjectParameterivARB(vertHandle,GL_OBJECT_COMPILE_STATUS_ARB, &vertCompiled);  
  135.     printInfoLog(vertHandle);  
  136.   
  137.     printf("编译码块片元着色器并打印编译器日志文件:\n");  
  138.     //编译码块片元着色器并打印编译器日志文件  
  139.     glCompileShaderARB(fragHandle);  
  140.     printOpenGLError();             //检查opengl错误  
  141.     glGetObjectParameterivARB(fragHandle,GL_OBJECT_COMPILE_STATUS_ARB, &fragCompiled);  
  142.     printInfoLog(fragHandle);  
  143.   
  144.   
  145.     if(!vertCompiled || !fragCompiled)  
  146.         return -1;  
  147.   
  148.     //创建一个程序对象并附加两个编译好的着色器  
  149.     progHandle = glCreateProgramObjectARB();  
  150.     glAttachObjectARB(progHandle, vertHandle);  
  151.     glAttachObjectARB(progHandle, fragHandle);  
  152.   
  153.     printf("链接程序对象并打印信息日志:\n");  
  154.     //链接程序对象并打印信息日志  
  155.     glLinkProgramARB(progHandle);  
  156.     printOpenGLError();             //检查opengl错误  
  157.     glGetObjectParameterivARB(progHandle, GL_OBJECT_LINK_STATUS_ARB, &linked);  
  158.     printInfoLog(progHandle);  
  159.   
  160.     if(!linked)  
  161.         return -2;  
  162.   
  163.     //将程序对象安装为当前状态的一部分  
  164.     glUseProgramObjectARB(progHandle);     //改为运行的函数,用于测试该算法的时间  
  165.   
  166.     return progHandle;    
  167. }  
  168.   
  169. //装载一个bmp图像使之成为纹理,其中貌似包含了 glTexImage2D这个函数的功能  
  170.   
  171. int LoadGLTextures(char *textureFilePath)  
  172. {  
  173.     unsigned char *pTexData = NULL;  
  174.   
  175.     long bitCnt =  0;  
  176.     long iw =0;  
  177.     long ih = 0;   //以上三个参数其实是没有的,~_~  
  178.     long status = LoadBMP( textureFilePath, &pTexData,&iw, &ih, &bitCnt );  
  179.   
  180.      glGenTextures( 1, &texture );  
  181.     glBindTexture(GL_TEXTURE_RECTANGLE_ARB,texture);  
  182.   
  183.     //当卷积内核超过了图像边界时使用图像边缘的像素值  
  184.     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );  
  185.     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );  
  186.   
  187.     //纹理过滤的方式不应该设置为线性插值  
  188.     glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_NEAREST);  
  189.     glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_NEAREST);  
  190.   
  191.     glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, imgWidth, imgHeight, 0,GL_RGB,GL_UNSIGNED_BYTE,pTexData );  
  192.   
  193.     glTexEnvi( GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE );  
  194.   
  195.     return 0;  
  196. }  
  197.   
  198. void init()  
  199. {  
  200.       
  201.     glShadeModel( GL_FLAT );  
  202.     glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );  
  203.     glViewport(0,0, imgWidth, imgHeight );  
  204.     glEnable ( GL_DEPTH_TEST );  
  205.   
  206.     //LoadGLTextures("texture.bmp");  
  207.     if ( LoadGLTextures("texture.bmp") == 1 )  
  208.         printf( " Load Faild!   \n");  
  209.       
  210.     //初始化权值矩阵1  
  211.     for ( int i = 0; i < imgHeight; ++i )  
  212.         for ( int j = 0; j < imgWidth; ++j )  
  213.         {  
  214.               weight_1[i][j]=1.0;  
  215.         }  
  216.     glGenTextures( 1, &texWeigArr1 );  
  217.     glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texWeigArr1 );  
  218.     //当卷积内核超过了图像边界时使用图像边缘的像素值  
  219.     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );  
  220.     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );  
  221.   
  222.     //纹理过滤的方式不应该设置为线性插值  
  223.     glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_NEAREST);  
  224.     glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_NEAREST);  
  225.   
  226.     glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, imgWidth, imgHeight, 0,GL_LUMINANCE,GL_FLOAT,weight_1 );  
  227.   
  228.     glTexEnvi( GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE );  
  229.   
  230.     //初始化权值矩阵2  
  231.     for ( int i = 0; i <imgHeight2 / 2; ++i )  
  232.         for ( int j = 0; j <imgWidth2 /2; ++j )  
  233.         {  
  234.             weight_2[i][j] = 0.8;  
  235.         }  
  236.   
  237.         for ( int i = 0; i <imgHeight2/ 2; ++i )  
  238.             for ( int j = imgWidth2 /2; j <imgWidth2; ++j )  
  239.             {  
  240.                 weight_2[i][j] = 0.0;  
  241.             }  
  242.   
  243.             for ( int i = imgHeight2 / 2; i <imgHeight2; ++i )  
  244.                 for ( int j = 0; j <imgWidth2 /2; ++j )  
  245.                 {  
  246.                     weight_2[i][j] = 1.0;  
  247.                 }         
  248.                 for ( int i = imgHeight2 / 2; i <imgHeight2; ++i )  
  249.                     for ( int j =imgWidth2 /2; j <imgWidth2 ; ++j )  
  250.                     {  
  251.                         weight_2[i][j] = 0.2;  
  252.                     }         
  253.         glGenTextures( 1, &texWeigArr2 );  
  254.         glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texWeigArr2 );  
  255.         //当卷积内核超过了图像边界时使用图像边缘的像素值  
  256.         glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );  
  257.         glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );  
  258.   
  259.         //纹理过滤的方式不应该设置为线性插值  
  260.         glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_NEAREST);  
  261.         glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_NEAREST);  
  262.         glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, imgWidth2,  
  263.                        imgHeight2, 0,GL_LUMINANCE,GL_FLOAT,weight_2 );  
  264.   
  265.         //设置输出纹理的参数  
  266.     glGenTextures( 1, &texOutput );  
  267.     glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texOutput );  
  268.   
  269.     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );  
  270.     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );  
  271.   
  272.     //纹理过滤的方式不应该设置为线性插值  
  273.     glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_NEAREST);  
  274.     glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_NEAREST);  
  275.   
  276.     //没有给输出的纹理数据,等待程序进行赋值  
  277.     glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, imgWidth, imgHeight, 0,GL_RGBA,GL_FLOAT,0 );   
  278.     glTexEnvi( GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE );  
  279.   
  280.     //激活各个纹理  
  281.     glActiveTexture( GL_TEXTURE0 );  
  282.     glBindTexture(GL_TEXTURE_RECTANGLE_ARB,texture);  
  283.     glActiveTexture ( GL_TEXTURE1 );  
  284.     glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texWeigArr1 );  
  285.     glActiveTexture ( GL_TEXTURE2 );  
  286.     glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texWeigArr2 );  
  287. }  
  288. void initFBO( unsigned unWidth, unsigned unHeight )  
  289. {  
  290.     //创建FBO,准备屏幕外帧缓存  
  291.     glGenFramebuffersEXT( 1, &fb );  
  292.   
  293.     //绑定屏幕外帧缓存,即避开了窗口系统默认的渲染目标  
  294.     glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT, fb );  
  295.   
  296.   
  297. }  
  298. void readFromTexture( GLfloat *data )  
  299. {  
  300.     glReadBuffer( GL_COLOR_ATTACHMENT0_EXT );  
  301.     glReadPixels( 0, 0, imgWidth, imgHeight,  
  302.                                GL_LUMINANCE, GL_FLOAT, data );  
  303.   
  304. }  
  305. void display( void )  
  306. {  
  307.     glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );  
  308.   
  309.     ////关联输出缓存至FBO  
  310.     glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT,   
  311.                                GL_COLOR_ATTACHMENT0_EXT,   
  312.                                 GL_TEXTURE_RECTANGLE_ARB,texOutput,0 );  
  313.   
  314.     glDrawBuffer( GL_COLOR_ATTACHMENT0_EXT );  
  315.   
  316.     glBegin( GL_QUADS );    
  317.   
  318.     glMultiTexCoord2f( GL_TEXTURE0, 0.0, 0.0);    
  319.     glMultiTexCoord2f( GL_TEXTURE1, 0.0, 0.0);   
  320.     glMultiTexCoord2f( GL_TEXTURE2, 0.0, 0.0);   
  321.     glVertex2f( -1.0, -1.0);     
  322.   
  323.     glMultiTexCoord2f(GL_TEXTURE0, 0.0, 512.0 );    
  324.     glMultiTexCoord2f(GL_TEXTURE1, 0.0, 512.0 );    
  325.     glMultiTexCoord2f( GL_TEXTURE2, 0.0, 512.0);   
  326.     glVertex2f( -1.0, 1.0 );  
  327.   
  328.     glMultiTexCoord2f(GL_TEXTURE0, 512.0, 512.0 );    
  329.     glMultiTexCoord2f(GL_TEXTURE1, 512.0, 512.0 );    
  330.     glMultiTexCoord2f( GL_TEXTURE2, 512.0,512.0);   
  331.     glVertex2f( 1.0, 1.0 );  
  332.   
  333.     glMultiTexCoord2f(GL_TEXTURE0, 512.0, 0.0 );   
  334.     glMultiTexCoord2f(GL_TEXTURE1, 512.0, 0.0 );   
  335.     glMultiTexCoord2f( GL_TEXTURE2, 512.0, 0.0);   
  336.     glVertex2f ( 1.0, -1.0 );  
  337.   
  338.     glEnd( );  
  339.     glFlush();  
  340. }  
  341.   
  342.   
  343.   
  344.   
  345. int _tmain(int argc, char* argv[])  
  346. {  
  347.     GLhandleARB progHandle = 0;  
  348.   
  349.     glutInit( &argc, argv );  
  350.     glutInitDisplayMode( GLUT_SINGLE| GLUT_LUMINANCE);  
  351.     glutInitWindowSize ( imgWidth, imgHeight);  
  352.     glutInitWindowPosition( 100, 100 );  
  353.     glutCreateWindow(" gningh多重纹理&FBO ");  
  354.       
  355.     glewInit();  
  356.     initFBO(imgWidth, imgHeight );  
  357.     init();  
  358.   
  359.     progHandle = initShaders(vShader, fShader);   
  360.     if ( progHandle <= 0 )  
  361.         printf("Failed to run shader.\n");  
  362.     else{  
  363.         //设置初始一致变量  
  364.         glUniform1i( glGetUniformLocation( progHandle, "LenaTexture" ), 0 );   //0 是纹理的句柄  
  365.         glUniform1i( glGetUniformLocation( progHandle, "WeightTex1" ), 1 );     
  366.         glUniform1i( glGetUniformLocation(progHandle, "WeightTex2" ), 2 );  
  367.   
  368.     }  
  369.   
  370.     display();  
  371.   
  372.     readFromTexture( outPutFb );  
  373.   
  374.     //因为outputFb中保存的图像灰度都是0~1之间的数值表示的  
  375.     //这里我们要将0~1之间的数值乘以255变为0~255之间的灰度  
  376.     for ( int i =0; i < imgHeight * imgWidth; ++i )  
  377.     {  
  378.         pData[i] = (char)(outPutFb[i] * 255);  
  379.     }  
  380.   
  381.     //将pData中数据保存为result.bmp。8代表是8位灰度  
  382.     asrSaveBMP("result.bmp",pData,imgWidth,imgHeight,8);  
  383.    
  384.     return 0;  
  385. }  

原始图像:



经过处理后的图像为:




reference:

http://www.songho.ca/opengl/gl_fbo.html

http://blog.csdn.NET/xiajun07061225/article/details/7283929

http://stackoverflow.com/questions/11236991/minimal-example-for-creating-fbo-using-opengl-es-2-0-on-iOS

http://hankjin.blog.163.com/blog/static/3373193720103892121336/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值