PART ONE
codes.cpp
#include <stdio.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#define width 222
#define height 207
GLubyte image[height][width][4];
void initImage()
{
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++)
{
image[h][w][0] = 255;
image[h][w][1] = 0;
image[h][w][2] = 0;
image[h][w][3] = 255;
}
}
}
GLuint FBO;
GLuint RBO[2];
void initFBO()
{
glGenFramebuffers(1, &FBO);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
glGenRenderbuffers(2, RBO);
glBindRenderbuffer(GL_RENDERBUFFER, RBO[0]);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, RBO[0]);
glBindRenderbuffer(GL_RENDERBUFFER, RBO[1]);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, RBO[1]);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
#define BMP_Header_Length 54
void grab_green() {
FILE* pDummyFile;
FILE* pWritingFile;
GLubyte* pPixelData;
GLubyte BMP_Header[BMP_Header_Length];
GLint i, j;
GLint PixelDataLength;
// 计算像素数据的实际长度 得到每一行的像素数据长度
i = width * 3;
while (i % 4 != 0) ++i;
PixelDataLength = i * height;
pPixelData = (GLubyte*)malloc(PixelDataLength);// 分配内存和打开文件
if (pPixelData == 0) exit(0);
pDummyFile = fopen("head.bmp", "rb");
if (pDummyFile == 0) exit(0);
char outFileStr[40];
sprintf_s(outFileStr, 40, "green.bmp");
pWritingFile = fopen(outFileStr, "wb");
if (pWritingFile == 0) exit(0);
// 读取像素
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glReadPixels(0, 0, width, height, GL_BGR_EXT, GL_UNSIGNED_BYTE, pPixelData);
// 把head.bmp的文件头复制为新文件的文件头
fread(BMP_Header, sizeof(BMP_Header), 1, pDummyFile);
fwrite(BMP_Header, sizeof(BMP_Header), 1, pWritingFile);
fseek(pWritingFile, 0x0012, SEEK_SET);
i = width;
j = height;
fwrite(&i, sizeof(i), 1, pWritingFile);
fwrite(&j, sizeof(j), 1, pWritingFile);
// 写入像素数据
fseek(pWritingFile, 0, SEEK_END);
fwrite(pPixelData, PixelDataLength, 1, pWritingFile);
// 释放内存和关闭文件
fclose(pDummyFile);
fclose(pWritingFile);
free(pPixelData);
}
void grab_red() {
FILE* pDummyFile;
FILE* pWritingFile;
GLubyte* pPixelData;
GLubyte BMP_Header[BMP_Header_Length];
GLint i, j;
GLint PixelDataLength;
// 计算像素数据的实际长度 得到每一行的像素数据长度
i = width * 3;
while (i % 4 != 0) ++i;
PixelDataLength = i * height;
pPixelData = (GLubyte*)malloc(PixelDataLength);// 分配内存和打开文件
if (pPixelData == 0) exit(0);
pDummyFile = fopen("head.bmp", "rb");
if (pDummyFile == 0) exit(0);
char outFileStr[40];
sprintf_s(outFileStr, 40, "red.bmp");
pWritingFile = fopen(outFileStr, "wb");
if (pWritingFile == 0) exit(0);
// 读取像素
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glReadPixels(0, 0, width, height, GL_BGR_EXT, GL_UNSIGNED_BYTE, pPixelData);
// 把head.bmp的文件头复制为新文件的文件头
fread(BMP_Header, sizeof(BMP_Header), 1, pDummyFile);
fwrite(BMP_Header, sizeof(BMP_Header), 1, pWritingFile);
fseek(pWritingFile, 0x0012, SEEK_SET);
i = width;
j = height;
fwrite(&i, sizeof(i), 1, pWritingFile);
fwrite(&j, sizeof(j), 1, pWritingFile);
// 写入像素数据
fseek(pWritingFile, 0, SEEK_END);
fwrite(pPixelData, PixelDataLength, 1, pWritingFile);
// 释放内存和关闭文件
fclose(pDummyFile);
fclose(pWritingFile);
free(pPixelData);
}
void render()
{
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.0f,1.0f,0.0f,0.0f);
glReadBuffer(GL_COLOR_ATTACHMENT0);
grab_green();
glDrawBuffer(GL_COLOR_ATTACHMENT1);
glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, image);
glReadBuffer(GL_COLOR_ATTACHMENT1);
grab_red();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glutSwapBuffers();
}
int main(int argc, char** argv)
{
// init GLUT
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(width, height);
glutInitWindowPosition(200, 100);
int id = glutCreateWindow("FBO");
// init GLEW after GLUT
GLenum err = glewInit();
if (err != GLEW_OK) {
fprintf(stderr, "Error: '%s'\n", glewGetErrorString(err));
return 1;
}
initImage();
initFBO();
glutDisplayFunc(render);
glutMainLoop();
return 0;
}
部分二
代码分析
1、通过initFBO()函数初始化FBO,并为其配置具有实际GPU端内存大小的两个渲染缓冲对象(RBO:Render Buffer Object)。
2、在render()函数中使用FBO,首先通过glDrawBuffer()函数将附着点GL_COLOR_ATTACHMENT0对应的RBO [0] 设置为写入模式,使用glClearColor(0.0f,1.0f,0.0f,1.0f)写入绿色像素,之后通过glReadBuffer()函数将附着点GL_COLOR_ATTACHMENT0对应的RBO [0] 设置为读取模式,调用grab_green()函数将RBO[0]中的数据保存为“green.bmp”。同理,对于附着点GL_COLOR_ATTACHMENT1对应的RBO [1],我们通过glDrawPixels()函数将image[height][width][4]数组中初始化的红色像素写入其中,并通过调用grab_red()函数进行保存,在项目对应的文件夹中得到“red.bmp”。
3、由于FBO中的数据无法直接可见,因此我们将FBO中的数据保存到CPU端进行查看。OpenGL中唯一可见的数据是默认的屏幕缓冲区中渲染出的数据。