关于OpenGL Framebuffer Object、glReadPixels与离屏渲染
最近写论文需要用到离屏渲染(主要是因为模型太大普通窗口绘制根本做不了),于是翻阅了红宝书查了下相关api和用法。中文版的红宝书可读性有点差,很多地方翻译地晦涩,但好歹读起来比较快,主要相关章节为第8章和第10章(可以连带把第9章读完以后写GLSL会顺利成章)。貌似superbible可读性更强,但红宝书讲得也差不多了就没再继续看。
由于红宝书过于学术,想动手还是最好查查网上的资料,于是把一些还可以的资料列一下。
关于FBO:
关于glReadPixels:
OpenGL中位图的操作(glReadPixels,glDrawPixels等)
关于在FBO中使用多重采样:
【OpenGL】FBO中多重采样抗锯齿(MSAA:MultiSampling Anti-Aliasing)
总结上面的参考资料,并主要参照红宝书的代码,离屏渲染的代码如下(经测试确实可用):
void *GlWidget::offScreenRender(string file_path) {
int render_width = *window_width_, render_height = *window_height_; enum { Color, Depth, NumRenderbuffers };
// multi-sampled frame buffer object as the draw target
GLuint framebuffer_ms, renderbuffer_ms[NumRenderbuffers]; // generate color and depth render buffers and allocate storage for the multi-sampled FBO
glGenRenderbuffers(NumRenderbuffers, renderbuffer_ms);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer_ms[Color]);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, ,
GL_RGBA8, render_width, render_height);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer_ms[Depth]);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, ,
GL_DEPTH_COMPONENT24, render_width, render_height); // generate frame buffer object for the multi-sampled FBO
glGenFramebuffers(, &framebuffer_ms);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer_ms);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, renderbuffer_ms[Color]);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, renderbuffer_ms[Depth]); if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
// draw
glViewport(, , render_width, render_height);
glDrawBuffer(GL_COLOR_ATTACHMENT0); // set draw to the created color render buffer
glEnable(GL_MULTISAMPLE); // antialiasing
glEnable(GL_DEPTH_TEST);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClearDepth(1.0f);
HMeshModel model;
bool draw_success = drawModel(model, true, file_path.c_str()); // copy to memory
if (draw_success) {
// single-sampled frame buffer object as the server-side copy target and copy-to-memory source
GLuint framebuffer, renderbuffer[NumRenderbuffers]; // generate color and depth render buffers and allocate storage for the single-sampled FBO
glGenRenderbuffers(NumRenderbuffers, renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer[Color]);
glRenderbufferStorage(GL_RENDERBUFFER,
GL_RGBA, render_width, render_height);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer[Depth]);
glRenderbufferStorage(GL_RENDERBUFFER,
GL_DEPTH_COMPONENT24, render_width, render_height); // generate frame buffer object
glGenFramebuffers(, &framebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, renderbuffer[Color]);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, renderbuffer[Depth]);
glDrawBuffer(GL_COLOR_ATTACHMENT0); if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
// set up to read from the multi-sampled FBO
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer_ms); // copy from the multi-sampled FBO to the single-sampled FBO
glBlitFramebuffer(
, , render_width, render_height,
, , render_width, render_height,
GL_COLOR_BUFFER_BIT, GL_NEAREST); // create memory storage for the pixel array
int image_bytes = alignInteger(render_width*, BMP_ROW_ALIGN) * render_height;
unsigned char *image = new unsigned char[image_bytes]; // copy pixels to memory from the single-sampled frame bffer
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer); // set up to read from the single-sampled FBO
glBindBuffer(GL_PIXEL_PACK_BUFFER, ); // do not copy into any server side buffer object
glReadBuffer(GL_COLOR_ATTACHMENT0);
glPixelStorei(GL_PACK_ALIGNMENT, BMP_ROW_ALIGN);
glGetError();
glReadPixels(, , render_width, render_height,
GL_BGR, GL_UNSIGNED_BYTE, image);
GLenum error = checkGLError(__FILE__, __LINE__); // write to file
string image_path = getFilename(file_path.c_str()) + "_off_screen.bmp";
writeBMP(image_path.c_str(), render_width, render_height, BMP_BGR, image); delete[] image;
} else {
cout << internalErrorPrefix() << "): frame buffer object not complete" << endl;
} // delete the created frame buffer objects and render buffer objects
glDeleteRenderbuffers(NumRenderbuffers, renderbuffer);
glDeleteFramebuffers(, &framebuffer);
}
} else {
cout << internalErrorPrefix() << "): frame buffer object not complete" << endl;
} // delete the created frame buffer objects and render buffer objects
glDeleteRenderbuffers(NumRenderbuffers, renderbuffer_ms);
glDeleteFramebuffers(, &framebuffer_ms);
// bind the read and draw frame buffer to the default (window)
glBindFramebuffer(GL_READ_FRAMEBUFFER, );
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ); // restore the opengl status for window buffer drawing
initializeGL();
glViewport(, , window_width_, window_height_);
}
window_width_和window_height_分别是窗口的宽高,checkGLError是一个获取openGL错误的函数。虽然函数是一个QT的GLWidget类的一个成员函数,不过由于实际上与类本身的关联并不大,故比较容易粘贴移植到其他场景下(之所以没有做一个可复用的版本可能是觉得这样做起来实在太麻烦而且容易出错,也许以后可以写一个)。使用时把drawModel函数替换成自己的其他可能只要稍微修改下就好了。另附上一些支撑的函数和自己从网上修改得来的写BMP文件的代码:
template<typename T>
T alignInteger (T n, T divisor) {
if (n % divisor != )
n = n - n % divisor + divisor; return n;
} const int BMP_ROW_ALIGN = ;
enum BMPPixelType { BMP_BGR = , BMP_BGRA = };
const int BMP_HEADER_LEN = ;
const static unsigned char pixel_bytes[] = { /*BGR*/, /*BGRA*/ };
const static unsigned char pixel_bits[] = { /*BGR*/, /*BGRA*/ }; bool writeBMP(
const char *file_path, const int width, const int height,
const BMPPixelType pixel_type, const unsigned char *pdata
){
unsigned char header[BMP_HEADER_LEN] = {
0x42, 0x4d, , , , , , , , ,
, , , , , , , , , , , , , , , , , , pixel_bits[pixel_type], ,
, , , , , , , , , , , , , , , , , , , ,
, , ,
}; long file_size = (long)width * (long)height * pixel_bytes[pixel_type] + ;
header[] = (unsigned char)(file_size &0x000000ff);
header[] = (file_size >> ) & 0x000000ff;
header[] = (file_size >> ) & 0x000000ff;
header[] = (file_size >> ) & 0x000000ff; long w = width;
header[] = w & 0x000000ff;
header[] = (w >> ) &0x000000ff;
header[] = (w >> ) &0x000000ff;
header[] = (w >> ) &0x000000ff; long h = height;
header[] = h &0x000000ff;
header[] = (h >> ) &0x000000ff;
header[] = (h >> ) &0x000000ff;
header[] = (h >> ) &0x000000ff; FILE *pfile = NULL; pfile = fopen(file_path, "wb");
if (pfile == NULL) {
fprintf(stderr,
"#error(%s, line %d): open file '%s' for write failed\n",
__FILE__, __LINE__, file_path);
return false;
} fwrite(header, sizeof(unsigned char), , pfile);
int row_length, total_length;
row_length = width * pixel_bytes[pixel_type]; // 每行数据长度大致为图象宽度乘以每像素字节数
row_length = alignInteger(row_length, BMP_ROW_ALIGN); // 修正LineLength使其为4的倍数
total_length = row_length * height; // 数据总长 = 每行长度 * 图象高度 fwrite(pdata, sizeof(unsigned char), (size_t)(long)total_length, pfile); // 释放内存和关闭文件
fclose(pfile);
return true;
}
关于OpenGL Framebuffer Object、glReadPixels与离屏渲染的更多相关文章
- IOS 中openGL使用教程4(openGL ES 入门篇 | 离屏渲染)
通常情况下,我们使用openGL将渲染好的图片绘制到屏幕上,但有时候我们不想显示处理结果,这时候就需要使用离屏渲染了. 正常情况下,我们将屏幕,也就是一个CAEAGLLayer对象作为渲染目标,离屏渲 ...
- Android OpenGL ES 离屏渲染(offscreen render)
通常在Android上使用OpenGL ES,都是希望把渲染后的结果显示在屏幕上,例如图片处理.模型显示等.这种情况下,只需要使用Android API中提供的GLSurfaceView类和Rende ...
- opengl离屏渲染(不需要和窗口绑定,仅当作一个可以渲染一张图片的API使用)+ opencv显示
具体过程参考的是这篇BLOG: http://wiki.woodpecker.org.cn/moin/lilin/swig-glBmpContext 这一片BLOG的代码有个 BOOL SaveBmp ...
- OpenGL于MFC使用汇总(三)——离屏渲染
有时直接创建OpenGL形式不适合,或者干脆不同意然后创建一个表单,正如我现在这个项目,创建窗体不显示,它仅限于主框架.而我只是ActiveX里做一些相关工作,那仅仅能用到OpenGL的离屏渲染技术了 ...
- iOS-----openGL--openGL ES iOS 入门篇4---> 离屏渲染
http://www.cnblogs.com/CoderAlex/p/6604618.html 通常情况下,我们使用openGL将渲染好的图片绘制到屏幕上,但有时候我们不想显示处理结果,这时候就需要使 ...
- WebGL简易教程(十三):帧缓存对象(离屏渲染)
目录 1. 概述 2. 示例 2.1. 着色器部分 2.2. 初始化/准备工作 2.2.1. 着色器切换 2.2.2. 帧缓冲区 2.3. 绘制函数 2.3.1. 初始化顶点数组 2.3.2. 传递非 ...
- NDK OpenGLES3.0 开发(五):FBO 离屏渲染
什么是 FBOFBO(Frame Buffer Object)即帧缓冲区对象,实际上是一个可添加缓冲区的容器,可以为其添加纹理或渲染缓冲区对象(RBO). FBO 本身不能用于渲染,只有添加了纹理或者 ...
- iOS 离屏渲染的研究
GPU渲染机制: CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区,随后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器显示. G ...
- iOS离屏渲染简书
更详细地址https://zsisme.gitbooks.io/ios-/content/chapter15/offscreen-rendering.html(包含了核心动画) GPU渲染机制: CP ...
随机推荐
- IOS开发 多线程GCD
Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法. dispatch queue分成以下三种: 1)运行在主线程的Main queue,通过dispat ...
- Andriod4.2 Camera 架构与实现
1.Camera架构包括客户端和服务端,他们之间的通信采用Binder机制实现. Camera的实现主要包括本地代码和Java代码两个层次: Camera本地框架: frameworks/native ...
- Android 编程 AMapLocationClientOption 类中的 setNeedAddress 方法用处 (高德地图 com.amap.api.location.AMapLocationClientOption 中的类)
最近在用高德地图来写Android App, 其中有一些 方法是不太理解的,这里写一下 对 高德地图 com.amap.api.location.AMapLocationClientOption ...
- caffe 细节
batch :http://www.zhihu.com/question/32673260 caffe blog: http://blog.csdn.net/abcjennifer/article/d ...
- mac下安装伪分布hadoop2.6.0和hbase1.0.1.1
1.安装JDK,我安装的是java1.7 2.创建管理员账户 3.安装ssh服务(如果已有跳过此步) 4.ssh无密码验证登陆 以上过程略,可参考ubuntu下安装hadoop一文. 5.下载并解压h ...
- HDFS原理分析之HA机制:avatarnode原理
一.问题描述 由于namenode 是HDFS的大脑,而这个大脑又是单点,如果大脑出现故障,则整个分布式存储系统就瘫痪了.HA(High Available)机制就是用来解决这样一个问题的.碰到这么个 ...
- win7如何安装maven、安装protoc
问题导读1.protoc安装需要安装哪些软件?2.如何验证maven是否安装成功?3.如何验证protoc是否安装成功 ? 一.安装mvaven包 1.首先我们下载maven包 apache-mave ...
- CH0805 防线(秦腾与教学评估)
题意 lsp 学习数学竞赛的时候受尽了同仁们的鄙视,终于有一天......受尽屈辱的 lsp 黑化成为了黑暗英雄Lord lsp.就如同中二漫画的情节一样,Lord lsp 打算毁掉这个世界.数学竞赛 ...
- select rows by values in a column from Dataframe
df.loc[df['column_name'] == some_value] details in: http://stackoverflow.com/questions/17071871/sele ...
- web 调试工具docker的安装使用
1. weinre 工具 docker run -d -p 8080:8080 beevelop/weinre 2. vorlonjs(不支持https) docker run --name v ...