0
点赞
收藏
分享

微信扫一扫

OpenGL之FBO中的glDrawBuffer和glReadBuffer

一天清晨 2022-04-29 阅读 46
c++

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中唯一可见的数据是默认的屏幕缓冲区中渲染出的数据。

举报

相关推荐

0 条评论