GPU渲染完数据在显存,回传内存的唯一方式glReadPixels函数

显存也被叫做显示内存、帧缓存,它是用来存储显示芯片处理过或者即将读取的渲染数据。如同计算机的内存一样,显存是用来存储图形数据的硬件。在显示器上显示出的画面是由一个个的像素点构成的,而每个像素点都以4至64位的数据来控制它的亮度和色彩,这些点构成一帧的图形画面。为了保持画面流畅,要输出和要处理的多幅帧的像素数据必须通过显存来保存,达到缓冲效果,再交由显示芯片和CPU调配,最后把运算结果转化为图形输出到显示器上
glReadPixels:读取一些像素。当前可以简单理解为“把已经绘制好的像素(它可能已经被保存到显卡的显存中)读取到内存”。

注意:glReadPixels实际上是从缓冲区中读取数据,如果使用了双缓冲区,则默认是从正在显示的缓冲(即前缓冲)中读取,而绘制工作是默认绘制到后缓冲区的。因此,如果需要读取已经绘制好的像素,往往需要先交换前后缓冲。

颜色缓冲区

OpenGL在绘制图元时,先是在一个缓冲区中完成渲染,然后再把渲染结果交换到屏幕上。我们把这两个缓冲区称为前颜色缓冲区(屏幕)和后颜色缓冲区。在默认情况下,OpenGL命令是在后颜色缓冲区进行渲染的。当然,也可以直接在前颜色缓冲区中进行渲染。
        若要在前颜色缓冲区中进行渲染,第一种方法是直接告诉OpenGL希望在前颜色缓冲区中进行绘图,可以调用下面这个函数来实现这个目的:
        void glDrawBuffer(Glenum mode);
        如果参数mode指定为GL_FRONT,OpenGL就会在前颜色缓冲区中进行渲染;
        如果参数mode指定为GL_BACK,那么渲染将在后颜色缓冲区中进行。
        在前颜色缓冲区进行渲染的第二种方法是在OpenGL被初始化时简单地不要求进行双缓冲区渲染。进行单缓冲区渲染时,如果希望把渲染结果实际绘制到屏幕上,需要调用glFlush()或glFinsh(),这点非常重要。
        OpenGL实现除了支持单纯的前颜色缓冲区和后颜色缓冲区之外,还支持其他模式,如用于立体渲染的左和右缓冲区以及辅助缓冲区。

方法一、保存为图片

QImage* img=new QImage(WINDOW_WIDTH,WINDOW_HEIGHT,QImage::Format_ARGB32);uchar* tmpBIT = img->bits();//从颜色缓冲区中读取数据int tmpPixelSize = WINDOW_WIDTH*WINDOW_HEIGHT * 4;char* tmpPixelsBuffer = (char*)malloc(tmpPixelSize);glReadPixels(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT,GL_RGBA, GL_UNSIGNED_BYTE, tmpPixelsBuffer);for (int y = WINDOW_HEIGHT-1; y >=0 ; y--){for (int x = 0; x < WINDOW_WIDTH; x++){//蓝色tmpBIT[0] = tmpPixelsBuffer[(y*WINDOW_WIDTH + x) * 4 + 2];//绿色tmpBIT[1] = tmpPixelsBuffer[(y*WINDOW_WIDTH + x) * 4 + 1];//红色tmpBIT[2] = tmpPixelsBuffer[(y*WINDOW_WIDTH + x) * 4 + 0];tmpBIT[3] = 100;//不起作用tmpBIT += 4;}}//从深度缓冲区读取数据int tmpPixelSize = WINDOW_WIDTH*WINDOW_HEIGHT;float* tmpPixelsBuffer = new float[ tmpPixelSize ];//GLfloat* tmpPixelsBuffer = new GLfloat[ tmpPixelSize ];//glReadBuffer(GL_NONE);//glReadBuffer(GL_BACK);glReadPixels(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT,GL_DEPTH_COMPONENT, GL_FLOAT, tmpPixelsBuffer);GLenum aaa = glGetError();for (int y = WINDOW_HEIGHT-1; y >=0 ; y--){for (int x = 0; x < WINDOW_WIDTH; x++){float iii=tmpPixelsBuffer[(y*WINDOW_WIDTH + x)  + 0];iii*=255;//蓝色tmpBIT[0] = iii;//绿色tmpBIT[1] = iii;//红色tmpBIT[2] = iii;tmpBIT[3] = 255;//不起作用tmpBIT += 4;}}img->save("a.jpg");

方法二、输出到纹理

1、配置FBO,使颜色、深度输出到纹理

    glGenFramebuffers(1, &m_fbo);// Создаем буфер глубиныglGenTextures(1, &m_shadowMap);glBindTexture(GL_TEXTURE_2D, m_shadowMap);glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, WindowWidth, WindowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,m_shadowMap, 0);//增加一个颜色缓冲区glGenTextures(1, &m_shadowColor);glBindTexture(GL_TEXTURE_2D, m_shadowColor);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WindowWidth, WindowHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,m_shadowColor, 0);glDrawBuffer(GL_COLOR_ATTACHMENT0);// 不允许读写颜色缓冲区,也会禁用片元着色器//glDrawBuffer(GL_NONE);//glReadBuffer(GL_NONE);GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER);if (Status != GL_FRAMEBUFFER_COMPLETE){printf("FB error, status: 0x%x\n", Status);return false;}return true;

2、在默认帧缓冲区(或其他帧缓冲区)使用纹理

    glActiveTexture(TextureUnit);glBindTexture(GL_TEXTURE_2D, m_shadowMap);

OpenGL:如何从缓存中读取颜色、深度信息【转】相关推荐

  1. OpenGL:关于获取渲染结果的深度信息的问题

    前面已经记录了从显存中获取渲染结果并保存为图像的方法 OpenGL:如何从缓存中读取颜色.深度信息[转]_六月的翅膀的博客-CSDN博客 并已经验证了上述方法可以完美的保存图像,但是保存深度信息部分还 ...

  2. OpenGL:关于获取渲染结果的深度信息的问题(二)

    前面记录了一下存在的问题和大致的解决方法 OpenGL:关于获取渲染结果的深度信息的问题_六月的翅膀的博客-CSDN博客 下面就验证一下 先定义一个指针变量和一个成员函数 GLfloat* depth ...

  3. mysql怎么直接显示对象信息_对象保存进MySQL数据库,从MySQL中读取出对象信息的源码...

    数据库名:db_file_test 表名:obj 实体类: package com.bean; import java.io.Serializable; public class User imple ...

  4. JDBC编程——从属性资源文件中读取数据库的信息

    JDBC连接数据库(通过类加载的方式注册驱动) 从属性资源文件中读取数据库的信息,这里首先是给大家介绍一下注册驱动的另一种方式--通过类加载的方式注册驱动,这种方式也是程序员经常使用的一种,因为类加载 ...

  5. php 获取照片信息,PHP中读取照片exif信息的方法

    这篇文章主要介绍了PHP中读取照片exif信息的方法,本文从什么是exif信息开始讲解,使用PHP需要什么扩展.及它的安装方法和使用代码示例等,需要的朋友可以参考下 先来了解什么是图片的Exif信息 ...

  6. Android中读取短信信息

    Android中读取的短信文件有 /*** 所有的短信*/public static final String SMS_URI_ALL = "content://sms/";/** ...

  7. java如何从缓存中读取数据_Java 缓存技术之 ehcache中读取出所有缓存名称列表数组...

    1. EHCache 的特点,是一个纯Java ,过程中(也可以理解成插入式)缓存实现,单独安装Ehcache ,需把ehcache-X.X.jar 和相关类库方到classpath中.如项目已安装了 ...

  8. c语言如何读取mp3歌曲信息,VC中读取mp3文件信息的方法

    标准格式的mp3文件中,都有一些自身描述的信息,比如歌曲名称.歌手.专辑名称等信息. 这些信息都记录在mp3文件中,而且格式是固定的.那么,我们就可以用编程的方式来获取这些信息.其实说简单一点,就是V ...

  9. 在asp.net中读取XML文件信息的4种方法

    方法一 :使用XML控件     <% @ Page Language="C#"%>  <html> <body>         <h3 ...

最新文章

  1. 18 个 Java8 日期处理的实践,太有用了!
  2. ScrollViewer滚动究竟来触发载入数据的Behavior
  3. opencv-从设备获取视频并且一帧一帧的保存下来
  4. TVS 击穿电压和钳位电压的区别
  5. Hadoop之MapTask工作机制
  6. 【渝粤题库】陕西师范大学202011 微观经济学 作业 (专升本、高起本)
  7. 达摩院里的女Leader,一面温柔似水一面灿烂如阳
  8. Spring Cloud —— Gateway 服务网关
  9. nlp论文-《Neural Machine Translation by Jointly Learning to Align and Translate》-基于联合学习对齐和翻译的神经机器翻译(一)
  10. java个人博客系统源码_Java基于SSM的个人博客系统(源码 包含前后台)
  11. linux初学者-软件安装与管理篇
  12. shell脚本:一次读取文件的一行,并输出
  13. 计算机操作系统第4版期末复习
  14. 《JavaScript DOM编程艺术》知识整理
  15. 《商用密码应用与安全性评估》第一章 密码基础知识-小结
  16. gitlab内网部署clone push速度快,网页反应慢
  17. 手机怎么识别图片上的文字
  18. [Android]APP中保持屏幕不自动灭屏的一种方法
  19. 全球及中国千兆路由器行业市场规模调研及投资风险预测报告2022-2028年
  20. flash,php上传文件

热门文章

  1. JEECG_3.7 权限开发视频正式发布
  2. UI标签库专题十三:JEECG智能开发平台 ckfinder(ckfinder插件标签)
  3. 再问数据中台 - 数据中台是什么?
  4. Express学习笔记(基本使用,中间件,模块化路由,请求处理)
  5. vi 编辑器命令 (share)
  6. activiti学习--08 连线
  7. 说一说技术和管理……
  8. mongo(四)索引
  9. mini2440-Openwrt启动信息
  10. 20140120收藏夹