那么帧缓冲对象到底是个什么东西呢?首先帧缓冲区你可以理解为就是一个概念,下面这个图可以很形象的解释帧缓冲区的意思。这里对这个图解释一下:
其实真实存放数据的缓存就是纹理缓存和render缓存,FBO就是将纹理缓存和render缓存整了一个句柄关联起来,对其进行处理,现在理解为啥FBO只是一个概念了。
本篇博客主要有以下3个技术点:
1:将一个矩阵,这个矩阵存储着我们需要的数值,有可能就是一系数矩阵或者说权值矩阵,把这个矩阵放入纹理缓冲中,当做纹理来使用。
2:这里面用到了多重纹理,多重纹理的处理还是比单重的纹理处理的过程复杂的多的。
3:也是本文的重点,就是对帧缓存(FBO)的使用。
具体的使用还是要看代码吧。
大家在把代码贴到自己电脑上会缺少一个savePicture.h这个头文件,这个头文件包含了loadBMP和saveBMP两个函数,很抱歉,这两个函数不是我写的,不方便发到网上,但是这两个函数都是很简单的,大家可以自己到网上找到相关的函数来代替。有了这两个功能,程序就可以跑起来了。
#include "stdafx.h"
#include
#include
#include
#include
#include
#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 error
2. -2 link error
3. 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");
//初始化权值矩阵1
for ( 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 );
//初始化权值矩阵2
for ( int i = 0; i
经过处理后的图像为:
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/