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

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

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

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

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

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

#include "stdafx.h"
#include<windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>
#include "savePicture.h"//纹理的编号
static GLuint texture;    //lena图像作为纹理
static GLuint texWeigArr1;  //自己生成的纹理1
static GLuint texWeigArr2;  //自己生成的纹理2
static GLuint texOutput;    //产生结果的纹理static GLuint fb;          //FBO编号#define printOpenGLError() printOglError(__FILE__, __LINE__)const GLint imgHeight = 512, imgWidth = 512;
const GLint imgHeight2 = 256, imgWidth2 = 256;
static GLfloat   weight_1[imgWidth][imgHeight];    //权值矩阵1
static GLfloat   weight_2[imgHeight2][imgWidth2];   //权值矩阵2
static  GLfloat outPutFb[imgHeight * imgWidth];   //输出纹理缓冲
static GLubyte  pData[imgHeight * imgWidth];   //存储最终的图像数据//顶点着色器
const char *vShader = {//"#version 110  \n ""void main()""{""gl_TexCoord[0] = gl_MultiTexCoord0;""gl_TexCoord[1] = gl_MultiTexCoord1;""gl_TexCoord[2] = gl_MultiTexCoord2;""gl_Position = ftransform();""}"
};//片元着色器
const char *fShader = {//"#version 110          \n ""#extension GL_ARB_texture_rectangle : enable  \n""uniform sampler2DRect  LenaTexture;         \n""uniform sampler2DRect  WeightTex1;         \n""uniform sampler2DRect  WeightTex2;         \n""void main()         \n""{          \n""vec2   weig1Pos =  gl_TexCoord[1].st;                  \n ""vec2   weig2Pos =  gl_TexCoord[0].st / 2.0;""vec2     pos1 = vec2(gl_TexCoord[0].s,512.0-gl_TexCoord[0].t);""vec4   texColor   =  texture2DRect(LenaTexture,pos1 );         \n""vec4   weight1    =  texture2DRect(WeightTex1, weig1Pos);          \n ""vec4   weight2    =  texture2DRect(WeightTex2, weig2Pos);          \n""texColor.yzw = vec3(0.0,0.0,0.0);         \n""weight1.yzw = vec3(0.0,0.0,0.0);         \n""if ( gl_TexCoord[0].s >256.0)""{ gl_FragColor = texColor;     }   \n""else""{gl_FragColor =   weight1 * weight2;   }     \n""}        \n"
};//输出错误相关信息
int printOglError(char *file, int line)
{GLenum glErr;int retCode = 0;glErr = glGetError();while (glErr != GL_NO_ERROR){printf("glError in file %s @ line %d: %s\n", file, line, gluErrorString(glErr));retCode = 1;glErr = glGetError();}return retCode;
}//输出opengl错误
void printInfoLog(GLhandleARB obj)
{int infologLength = 0;int charsWritten = 0;GLcharARB *infoLog;printOpenGLError();glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infologLength);printOpenGLError();if(infologLength > 0){infoLog = (GLcharARB*)malloc(infologLength);if(infoLog == NULL){printf("ERROR: Could not allocate InfoLog buffer\n");exit(1);}glGetInfoLogARB(obj,infologLength,&charsWritten,infoLog);printf("InfoLog:\n%s\n\n",infoLog);free(infoLog);}printOpenGLError();
}/*************************************************************
function name:   initShaders
input:   1.    const char *vShaderCode, 2.     const char *fShaderCode,
output:  1.    -1   compile error2.    -2    link  error3.       progHandle
description:*****************************************************************/
GLhandleARB initShaders( const char *vShaderCode, const char *fShaderCode )
{GLhandleARB vertHandle, fragHandle, progHandle;   //对象句柄GLint vertCompiled, fragCompiled;              //状态值GLint linked;//创建顶点着色器对象和片元着色器对象vertHandle = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);fragHandle = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);//将源代码字符串加载到着色器中glShaderSource( vertHandle, 1, &vShaderCode, NULL );glShaderSource( fragHandle, 1, &fShaderCode, NULL );printf("编译码块顶点着色器并打印编译器日志文件:\n");//编译码块顶点着色器并打印编译器日志文件glCompileShaderARB(vertHandle);printOpenGLError();               //检查opengl错误glGetObjectParameterivARB(vertHandle,GL_OBJECT_COMPILE_STATUS_ARB, &vertCompiled);printInfoLog(vertHandle);printf("编译码块片元着色器并打印编译器日志文件:\n");//编译码块片元着色器并打印编译器日志文件glCompileShaderARB(fragHandle);printOpenGLError();             //检查opengl错误glGetObjectParameterivARB(fragHandle,GL_OBJECT_COMPILE_STATUS_ARB, &fragCompiled);printInfoLog(fragHandle);if(!vertCompiled || !fragCompiled)return -1;//创建一个程序对象并附加两个编译好的着色器progHandle = glCreateProgramObjectARB();glAttachObjectARB(progHandle, vertHandle);glAttachObjectARB(progHandle, fragHandle);printf("链接程序对象并打印信息日志:\n");//链接程序对象并打印信息日志glLinkProgramARB(progHandle);printOpenGLError();             //检查opengl错误glGetObjectParameterivARB(progHandle, GL_OBJECT_LINK_STATUS_ARB, &linked);printInfoLog(progHandle);if(!linked)return -2;//将程序对象安装为当前状态的一部分glUseProgramObjectARB(progHandle);     //改为运行的函数,用于测试该算法的时间return progHandle;
}//装载一个bmp图像使之成为纹理,其中貌似包含了 glTexImage2D这个函数的功能int LoadGLTextures(char *textureFilePath)
{unsigned char *pTexData = NULL;long bitCnt =  0;long iw =0;long ih = 0;   //以上三个参数其实是没有的,~_~long status = LoadBMP( textureFilePath, &pTexData,&iw, &ih, &bitCnt );glGenTextures( 1, &texture );glBindTexture(GL_TEXTURE_RECTANGLE_ARB,texture);//当卷积内核超过了图像边界时使用图像边缘的像素值glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );//纹理过滤的方式不应该设置为线性插值glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_NEAREST);glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_NEAREST);glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, imgWidth, imgHeight, 0,GL_RGB,GL_UNSIGNED_BYTE,pTexData );glTexEnvi( GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE );return 0;
}void init()
{glShadeModel( GL_FLAT );glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );glViewport(0,0, imgWidth, imgHeight );glEnable ( GL_DEPTH_TEST );//LoadGLTextures("texture.bmp");if ( LoadGLTextures("texture.bmp") == 1 )printf( " Load Faild!   \n");//初始化权值矩阵1for ( int i = 0; i < imgHeight; ++i )for ( int j = 0; j < imgWidth; ++j ){weight_1[i][j]=1.0;}glGenTextures( 1, &texWeigArr1 );glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texWeigArr1 );//当卷积内核超过了图像边界时使用图像边缘的像素值glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );//纹理过滤的方式不应该设置为线性插值glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_NEAREST);glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_NEAREST);glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, imgWidth, imgHeight, 0,GL_LUMINANCE,GL_FLOAT,weight_1 );glTexEnvi( GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE );//初始化权值矩阵2for ( int i = 0; i <imgHeight2 / 2; ++i )for ( int j = 0; j <imgWidth2 /2; ++j ){weight_2[i][j] = 0.8;}for ( int i = 0; i <imgHeight2/ 2; ++i )for ( int j = imgWidth2 /2; j <imgWidth2; ++j ){weight_2[i][j] = 0.0;}for ( int i = imgHeight2 / 2; i <imgHeight2; ++i )for ( int j = 0; j <imgWidth2 /2; ++j ){weight_2[i][j] = 1.0;}      for ( int i = imgHeight2 / 2; i <imgHeight2; ++i )for ( int j =imgWidth2 /2; j <imgWidth2 ; ++j ){weight_2[i][j] = 0.2;}       glGenTextures( 1, &texWeigArr2 );glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texWeigArr2 );//当卷积内核超过了图像边界时使用图像边缘的像素值glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );//纹理过滤的方式不应该设置为线性插值glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_NEAREST);glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_NEAREST);glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, imgWidth2,imgHeight2, 0,GL_LUMINANCE,GL_FLOAT,weight_2 );//设置输出纹理的参数glGenTextures( 1, &texOutput );glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texOutput );glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );//纹理过滤的方式不应该设置为线性插值glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_NEAREST);glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_NEAREST);//没有给输出的纹理数据,等待程序进行赋值glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, imgWidth, imgHeight, 0,GL_RGBA,GL_FLOAT,0 ); glTexEnvi( GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE );//激活各个纹理glActiveTexture( GL_TEXTURE0 );glBindTexture(GL_TEXTURE_RECTANGLE_ARB,texture);glActiveTexture ( GL_TEXTURE1 );glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texWeigArr1 );glActiveTexture ( GL_TEXTURE2 );glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texWeigArr2 );
}
void initFBO( unsigned unWidth, unsigned unHeight )
{//创建FBO,准备屏幕外帧缓存glGenFramebuffersEXT( 1, &fb );//绑定屏幕外帧缓存,即避开了窗口系统默认的渲染目标glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT, fb );}
void readFromTexture( GLfloat *data )
{glReadBuffer( GL_COLOR_ATTACHMENT0_EXT );glReadPixels( 0, 0, imgWidth, imgHeight,GL_LUMINANCE, GL_FLOAT, data );}
void display( void )
{glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );关联输出缓存至FBOglFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB,texOutput,0 );glDrawBuffer( GL_COLOR_ATTACHMENT0_EXT );glBegin( GL_QUADS );  glMultiTexCoord2f( GL_TEXTURE0, 0.0, 0.0);  glMultiTexCoord2f( GL_TEXTURE1, 0.0, 0.0); glMultiTexCoord2f( GL_TEXTURE2, 0.0, 0.0); glVertex2f( -1.0, -1.0);   glMultiTexCoord2f(GL_TEXTURE0, 0.0, 512.0 );  glMultiTexCoord2f(GL_TEXTURE1, 0.0, 512.0 );  glMultiTexCoord2f( GL_TEXTURE2, 0.0, 512.0); glVertex2f( -1.0, 1.0 );glMultiTexCoord2f(GL_TEXTURE0, 512.0, 512.0 );  glMultiTexCoord2f(GL_TEXTURE1, 512.0, 512.0 );  glMultiTexCoord2f( GL_TEXTURE2, 512.0,512.0); glVertex2f( 1.0, 1.0 );glMultiTexCoord2f(GL_TEXTURE0, 512.0, 0.0 ); glMultiTexCoord2f(GL_TEXTURE1, 512.0, 0.0 ); glMultiTexCoord2f( GL_TEXTURE2, 512.0, 0.0); glVertex2f ( 1.0, -1.0 );glEnd( );glFlush();
}int _tmain(int argc, char* argv[])
{GLhandleARB progHandle = 0;glutInit( &argc, argv );glutInitDisplayMode( GLUT_SINGLE| GLUT_LUMINANCE);glutInitWindowSize ( imgWidth, imgHeight);glutInitWindowPosition( 100, 100 );glutCreateWindow(" gningh多重纹理&FBO ");glewInit();initFBO(imgWidth, imgHeight );init();progHandle = initShaders(vShader, fShader); if ( progHandle <= 0 )printf("Failed to run shader.\n");else{//设置初始一致变量glUniform1i( glGetUniformLocation( progHandle, "LenaTexture" ), 0 );   //0 是纹理的句柄glUniform1i( glGetUniformLocation( progHandle, "WeightTex1" ), 1 );   glUniform1i( glGetUniformLocation(progHandle, "WeightTex2" ), 2 );}display();readFromTexture( outPutFb );//因为outputFb中保存的图像灰度都是0~1之间的数值表示的//这里我们要将0~1之间的数值乘以255变为0~255之间的灰度for ( int i =0; i < imgHeight * imgWidth; ++i ){pData[i] = (char)(outPutFb[i] * 255);}//将pData中数据保存为result.bmp。8代表是8位灰度asrSaveBMP("result.bmp",pData,imgWidth,imgHeight,8);return 0;
}

原始图像:

经过处理后的图像为:

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/

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

  1. GLSL着色器周记02

    GLSL着色器周记02 来源:网络    编辑:admin 这周学了好多.包括伪随机数.柏林噪声. 先说伪随机数.伪随机数我们用的是周期函数而不是那种由前一项乘一个超大的数取余数的方法.使用周期函数的 ...

  2. openglshader实现虚拟场景_opengl – 如何使用GLSL着色器将径向模糊应用于整个场景?...

    我在GLSL中有一个径向模糊着色器,它采用纹理,对其进行径向模糊,并将结果呈现给屏幕.这个工作很好,到目前为止. 问题在于,它将径向模糊应用于场景中的第一个纹理.但是我实际上想做的就是将这个模糊应用于 ...

  3. HLSL CG 与glsl着色器编译及其原理

    导言:公司旧的渲染引擎用的结构无语了,要写一个渲染特效现在Unity 用shaderlab实现调试好,Unity插件导出GLTF格式(shader等已经包含在材质信息中),然后再导到自研引擎(用的OP ...

  4. OpenGL着色器程序解析--纹理贴图

    背景 纹理贴图意思是将任意类型的图片贴在3d模型的一个或者多个面上.图片可以是任意的但通常是一种通用的样式,比如:砖块.植物.荒芜的土地等等,可以提高场景的真实性.比较下面两幅图片:  为了实现纹理贴 ...

  5. 帧缓冲区对象 FBO

    帧缓冲区对象 FBO(Frame Buffer Object). 1.FBO(framebuffer object) (我习惯于把EGL创建的framebuffer称为framebuffer,也叫做w ...

  6. OpenGL学习脚印: 帧缓冲对象(Frame Buffer Object)

    写在前面 一直以来,我们在使用OpenGL渲染时,最终的目的地是默认的帧缓冲区,实际上OpenGL也允许我们创建自定义的帧缓冲区.使用自定义的帧缓冲区,可以实现镜面,离屏渲染,以及很酷的后处理效果.本 ...

  7. 【OpenGL ES】帧缓冲区对象FBO

    1.FBO 使用OpenGL ES,一般要通过EGL来配置本地窗口系统,关于EGL的介绍可参照"[OpenGL ES]EGL简介"http://blog.csdn.net/ieea ...

  8. OpenGL ES之离屏渲染的帧缓冲区对象FBO的说明和使用

    一.什么是 FBO ? FBO(Frame Buffer Object)即帧缓冲区对象,实际上是一个可添加缓冲区的容器,可以为其添加纹理或渲染缓冲区对象(RBO). FBO 本身不能用于渲染,只有添加 ...

  9. OpenGL 基本帧缓冲对象实例

    OpenGL 基本帧缓冲对象实例 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <vmath.h> #include <sb7 ...

最新文章

  1. 路遥知马力——Momentum动量梯度
  2. Python黑客入门:暴力破解zip,零基础也可以学会!
  3. springboot 禁用 cookie / chrome 禁用 cookie
  4. 如何遍历维数和各维上限未定的多维数组
  5. Loadrunner-web资源相关图表
  6. java web过滤器
  7. mysql count 1_高性能MySQL count(1)与count(*)的差别
  8. ICQ被购后看腾讯出击DST:迈出国际化的关键一步
  9. 云安全并非神话 五个源头严控把关
  10. 监控系统故障定位之事件关联分析的设计
  11. bc8-android导航,路畅A6导航刷机固件 4.09 CN-A6-GBDS-BC8-VIN-256-V1.51
  12. MLP手写数字识别实现
  13. BOSS直聘免费下载个人简历为PDF的方法
  14. matlab打开dat形式文件_将matlab中数据保存为txt或dat格式
  15. thinkPHP 接口访问限制
  16. QT程序退出后托盘图标不消失问题
  17. Postgresql数组操作符及数组函数
  18. Linux UART接口调试技巧
  19. 南京大学软件工程842参考书攻略
  20. AWS 再次发生宕机事件,云时代下的我们该如何补救?

热门文章

  1. PotPlayer视频播放器使用技巧
  2. Android10 系统应用wifi连接和静态ip代理设置
  3. WordCounter.icu - 一个简单的在线实时字数统计工具
  4. 【乐逍遥网站设计】网站建设如何让网站设计更加合理化?
  5. ARM嵌入式的定义和开发工具介绍
  6. 学习黑客必须要掌握的DOS命令全集
  7. python 解压缩文件中文名字乱码解决
  8. 在Coordinatorlayout中使用RecyclerView导致recyclerview最后一个item显示不全的问题
  9. 铜三铁四,京东裁员,offer毁约,对此我们真的没办法吗?
  10. HBuilderX 使用内置终端打开命令框 操作文件