关于如何将OpenGL渲染的图片保存到本地
标签(空格分隔):CG opengl
转载请说明出处:http://blog.csdn.net/hust_sheng/article/details/75268056
主要就是使用函数
glReadPixels()
#define BMP_Header_Length 54 void saveFrameBuff(const char* fileName) { FILE* pDummyFile; FILE* pWritingFile; GLubyte* pPixelData; GLubyte BMP_Header[BMP_Header_Length]; GLint i, j; GLint PixelDataLength; // 因为是窗口渲染,此处设置读取的数据来源于“前端窗口”(也可以是后端,详细见http://blog.csdn.net/hust_sheng/article/details/75268410) //glReadBuffer(GL_BACK); glReadBuffer(GL_FRONT); // 计算像素数据的实际长度 // 默认是3通道 i = width * 3; // 得到每一行的像素数据长度 while (i % 4 != 0) // 补充数据,直到 i 是的倍数 ++i; PixelDataLength = i * height; // 但这里仅追求直观,对速度没有太高要求PixelDataLength = i * WindowHeight; // 分配内存和打开文件 pPixelData = (GLubyte*)malloc(PixelDataLength); if (pPixelData == 0) exit(0); pDummyFile = fopen("ground.bmp", "rb"); if (pDummyFile == 0) exit(0); pWritingFile = fopen(fileName, "wb"); if (pWritingFile == 0) exit(0); // 读取像素 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glReadPixels(0, 0, width, height, GL_BGR_EXT, GL_UNSIGNED_BYTE, pPixelData); // 把 dummy.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); }
#define BMP_Header_Length 54 static void saveFrameBuff1(const int outImageNo) { // 因为是离屏渲染,此处设置读取的数据来源于我们自己设置的m_FboID对应的FBO glBindFramebuffer(GL_READ_FRAMEBUFFER, m_FboID); // GPU -> CPU 数据读取异步操作,详细见:http://blog.csdn.net/hust_sheng/article/details/75268410 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[0]); glReadPixels(0, 0, width, height * 30, GL_BGR_EXT, GL_UNSIGNED_BYTE, 0); GLubyte* image_src = (GLubyte*)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB); if (image_src){ glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); } FILE* pDummyFile; FILE* pWritingFile; GLubyte BMP_Header[BMP_Header_Length]; //GLubyte* pPixelData; GLint i, j, k; GLint PixelDataLength; // 计算像素数据的实际长度 i = width * 3; // 得到每一行的像素数据长度 while (i % 4 != 0) // 补充数据,直到 i 是的倍数 ++i; PixelDataLength = i * height; // 同时渲染以及传输多张图片 for (k = 0; k < 30; k++){ char outFileStr[OUTIMAGE_FILENAME_LEN]; sprintf_s(outFileStr, 20, "outView_GL%d_x.bmp", outImageNo + 1 - OPENGL_FBO_PARALLELNUM + k); pWritingFile = fopen(outFileStr, "wb"); if (pWritingFile == 0) exit(0); pDummyFile = fopen("ground.bmp", "rb"); if (pDummyFile == 0) exit(0); // 把 dummy.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(image_src + width*height * 3 * k, PixelDataLength, 1, pWritingFile); // 释放内存和关闭文件 fclose(pDummyFile); fclose(pWritingFile); } }
上述两段代码,前者是一般的过程,也是窗口渲染的过程,后者是离屏渲染且加上了异步优化。基本的思路都是先读取GPU图片数据,再读取本地的*.bmp文件的头部54个byte的信息,将两者拼接得到新的bmp文件,保存在本地。贴图渲染和异步优化见链接。