OpenGL ES 学习教程(十五) 从 颜色缓冲区(FBO的颜色附着)中 读取颜色数据 保存到图片(FreeImage)

标签: opengl es 保存图片 FBO 离屏渲染
1717人阅读 评论(0) 收藏 举报
分类:

游戏中需要截屏功能,GL中也有提供读取像素数据的API

glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);

传入相关参数,然后传入像素数据指针,就可以从绑定的颜色缓冲区中读取出来像素数据,然后通过FreeImage或者其他方式,存储为图片文件。


在上一篇的基础上,从FBO的颜色附着上,即纹理,即颜色缓冲区中读取像素数据。

转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

在第一次绘制之后,添加代码

virtual void render()
{
	if (m_width == 0 || m_height == 0)
	{
		return;
	}

	glBindRenderbuffer(GL_RENDERBUFFER, m_depthRenderBuffer);
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthRenderBuffer);

	glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer);
	//用作纹理的颜色缓冲区,glReadPixels从这个颜色缓冲区中读取
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0);

	GLenum tmpStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
	if (tmpStatus == GL_FRAMEBUFFER_COMPLETE)
	{
		glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

		glViewport(0, 0, m_width, m_height);
		{
			//model;
			glm::mat4 model = glm::mat4(1.0f);

			//View
			glm::mat4 view = glm::lookAt(glm::vec3(0, 0, 10), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));

			//透视
			glm::mat4 proj = glm::perspective(glm::radians(60.0f), 1.0f, 0.3f, 1000.0f);

			proj = proj*view*model;

			m_program.begin();
			{
				glm::vec3 pos[] =
				{
					glm::vec3(-5.0f, -5.0f, 0.0f),
					glm::vec3(5.0f, -5.0f, 0.0f),
					glm::vec3(0.0f, 5.0f, 0.0f),
				};


				glm::vec4 color[] =
				{
					glm::vec4(colorX, colorY, colorZ, 1),
					glm::vec4(colorZ, colorX, colorY, 1),
					glm::vec4(colorY, colorZ, colorX, 1),
				};

				colorX += 0.001f;
				if (colorX > 1) colorX = 0;
				colorY += 0.002f;
				if (colorY > 1) colorY = 0;
				colorZ += 0.003f;
				if (colorZ > 1) colorZ = 0;

				glUniformMatrix4fv(m_program.m_mvp, 1, false, &proj[0][0]);

				glVertexAttribPointer(m_program.m_position, 2, GL_FLOAT, false, sizeof(glm::vec3), pos);
				glVertexAttribPointer(m_program.m_color, 4, GL_FLOAT, false, sizeof(glm::vec4), color);

				glDrawArrays(GL_TRIANGLES, 0, 3);
			}
			m_program.end();
		}

		int tmpPixelSize = m_textureWidth*m_textureHeight * 4;
		char* tmpPixelsBuffer = (char*)malloc(tmpPixelSize);

		//从颜色缓冲区中读取数据
		glReadPixels(0, 0, m_textureWidth, m_textureHeight,GL_RGBA, GL_UNSIGNED_BYTE, tmpPixelsBuffer);
		for (size_t i = 0; i < tmpPixelSize; i+=4)
		{
			tmpPixelsBuffer[i] ^= tmpPixelsBuffer[i + 2] ^= tmpPixelsBuffer[i] ^= tmpPixelsBuffer[i + 2];
		}
		SavePng(tmpPixelsBuffer);

		free(tmpPixelsBuffer);
		

		glBindRenderbuffer(GL_RENDERBUFFER, GL_NONE);
		glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);

		

		glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
		glBindTexture(GL_TEXTURE_2D, m_texture);
		
		......
		
		......
	}
}

读取出来数据后,就可以通过FreeImage保存为图片文件

void SavePng(char* varPixelBuffer)
{
	FIBITMAP* tmpFIBitMap = FreeImage_Allocate(m_textureWidth, m_textureHeight, 32, 8, 8, 8);
	for (size_t y = 0; y < FreeImage_GetHeight(tmpFIBitMap); y++)
	{
		BYTE* tmpBIT = FreeImage_GetScanLine(tmpFIBitMap, y);

		for (size_t x = 0; x < FreeImage_GetWidth(tmpFIBitMap); x++)
		{
			tmpBIT[0] = varPixelBuffer[(y*m_textureWidth + x) * 4 + 0];
			tmpBIT[1] = varPixelBuffer[(y*m_textureWidth + x) * 4 + 1];
			tmpBIT[2] = varPixelBuffer[(y*m_textureWidth + x) * 4 + 2];
			tmpBIT[3] = 255;
			tmpBIT += 4;
		}
	}

	bool bSuccess = FreeImage_Save(FIF_PNG, tmpFIBitMap, "Screen.png", PNG_DEFAULT);

	FreeImage_Unload(tmpFIBitMap);
}
转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

保存后的效果



示例工程下载:

http://pan.baidu.com/s/1gfMD2fT 提取码a7q3


查看评论

FreeImage图像编程入门

(来源:http://blog.bioon.net/user1/2484/archives/2009/233212.shtml )过去一直使用OpenGL进行图形编程,听说使用FreeImage进行...
  • lmjq
  • lmjq
  • 2010-10-20 14:41:00
  • 4739

颜色缓冲区和深度缓冲区的对比

// create render buffer 颜色缓冲区 - (void)setupRenderBuffer { glGenRenderbuffers(1, &_colorRenderBuf...
  • xingxiliang
  • xingxiliang
  • 2014-06-13 14:09:57
  • 1270

OpenGL中的缓冲区

OpenGL中的缓冲区 颜色缓冲区          OpenGL在绘制图元时,先是在一个缓冲区中完成渲染,然后再把渲染结果交换到屏幕上。我们把这两个缓冲区称为前颜色缓冲区(屏幕)和后颜色缓冲区。...
  • Haohan_Meng
  • Haohan_Meng
  • 2014-05-07 22:06:27
  • 8670

qt opengl中 glReadPixels 获取鼠标位置的颜色失效 处理方法

void SelectTrend::mousePressEvent(QMouseEvent *event) { float pix[3] = { 0.0 }; glReadPixels(event-...
  • ckwave
  • ckwave
  • 2017-02-22 18:53:52
  • 755

glReadPixels

glReadPixels: 从frame buffer里读取一段pixels void glReadPixels( GLint x, GLint y, GLsizei width,GLsizei ...
  • huangmeimao
  • huangmeimao
  • 2012-05-23 16:19:11
  • 1357

【OPENGL】glReadPixels读取深度信息出现的问题

问题描述:我在用glReadPixels读取深度信息的时候,最后得到的结果是一个极小的一个趋于0的数。glReadPixels((int)10, (int)10, 1, 1, GL_DEPTH_COM...
  • u012130706
  • u012130706
  • 2017-10-28 08:17:26
  • 327

glReadPixels的使用问题

想把屏幕上的二维坐标转换成OpenGL下面的三维坐标一般常用的方法是: GLint    viewport[4]; GLdouble modelview[16]; GLdouble projectio...
  • Augusdi
  • Augusdi
  • 2012-05-25 09:03:10
  • 11544

OpenGL如何利用glDrawPixels来读取glreadPixels保存的文件

代码例子: void drawPixels() { FILE *pPixelsFile = 0; pPixelsFile = fopen("d:\\grab.bmp", "rb");...
  • ganpengjin1
  • ganpengjin1
  • 2014-09-19 11:50:37
  • 2516

PNG8格式图片详解

最近搜索了一下有关PNG8格式图片的详细解析。发现信息比较零散,也存在有某些争议(当然了,不排除本人搜索功力差的因素)。有说PNG8格式图片是不 支持半透明的,也有持反对意见的。所有才有了写这篇文章的...
  • fg5823820
  • fg5823820
  • 2012-12-05 22:31:56
  • 2703

如何将OpenGL渲染的图片保存到本地(正常渲染和离屏渲染)

关于如何将OpenGL渲染的图片保存到本地标签(空格分隔):CG opengl 主要就是使用函数 glReadPixels()...
  • hust_sheng
  • hust_sheng
  • 2017-07-17 21:00:26
  • 1591
    个人资料
    专栏达人
    等级:
    访问量: 145万+
    积分: 1万+
    排名: 669
    我的Github
    @ThisisGame
    博客专栏
    最新评论