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

2023-05-16

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);

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • stm32外部中断模式控制灯亮灭

    文章目录 前言一丶通过STMCube配置项目1 引脚配置如图2 配置EXIT3 配置SYS4 配置GPIO5 代码创建出勾上这个6 创建项目 二 通过KEil配置代码1 打开生成的项目 xff0c 找到stm32f1xx it c2 找到E
  • scrapy爬虫框架详解,爬取某网站小游戏案例实战

    文章目录 scrapy介绍名词介绍 xff1a scrapy工作流程 xff1a 使用方法 xff1a 项目实战 scrapy介绍 名词介绍 xff1a 引擎 xff08 engine xff09 scrapy的核心 xff0c 负责模块之
  • 3D Slicer 调试

    Windows 上的 C 43 43 调试 使用 Visual Studio 调试先决条件 xff1a 按照构建说明在调试中构建 3D slicer 要运行 Slicer xff0c 启动器需要设置某些环境变量 最简单的方法是使用启动器设置
  • centos7.6输入正确密码总是提示“Sorry, that didn‘t work. Please try again.”

    跟着老韩的视频顺利安装好了VM16和CentOs7 6 但最后卡在登录上了 xff0c 输入正确的用户名和密码后一直提示 Sorry that didn 39 t work Please try again 网上找了很多方法都没有解决 最后
  • Python 循环语句

    循环语句允许我们执行一个语句或语句组多次 xff0c 下面是在大多数编程语言中的循环语句的一般形式 xff1a While 循环语句 Python 编程中 while 语句用于循环执行程序 xff0c 即在某条件下 xff0c 循环执行某段
  • 关于Maven项目junit依赖出现版本号标红的解决方案

    关于Maven项目junit依赖出现版本号标红的解决方案 使用IDEA创建Maven项目时 xff0c pom里面的junit依赖的版本号出现标红 即版本号错误 xff09 xff0c 之前版本为4 10 解决方案 xff1a 找到本地仓库
  • 【C语言】单链表及插入(头插法、尾插法)

    目录 一 什么是单链表 二 单链表的插入 1 头插法 xff08 1 xff09 空链表情况 xff08 2 xff09 非空链表情况 2 尾插法 一 什么是单链表 链表是一种数据存储结构 xff0c 其存储地址并不连续 xff0c 数据元
  • Debian基础配置

    Debian的安装及基础配置 正文 debian基本介绍debian基本安装debian基本配置 结尾 本文介绍Debian的安装与基础配置 debian基本介绍 debian是一款稳定的基于Linux的操作系统 xff0c 它是由自由和开
  • OpenGL:配置glad

    GLAD库的作用 GLAD是一个开源的库 xff0c 它能解决我们上面提到的那个繁琐的问题 GLAD的配置与大多数的开源库有些许的不同 xff0c GLAD使用了一个在线服务 在这里我们能够告诉GLAD需要定义的OpenGL版本 xff0c
  • MySQL中ENGINE = InnoDB AUTO_INCREMENT = 200 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci的作用

    span class token keyword CREATE span span class token keyword TABLE span span class token punctuation 96 span permission
  • Docker数据管理,镜像创建与分层结构

    Docker数据管理 xff0c 镜像创建与分层结构 一 Docker的数据管理1 数据卷2 数据卷容器 二 容器互联 使用centos镜像 三 Docker 镜像的创建1 基于现有镜像创建2 基于本地模板创建3 基于Dockerfile
  • R语言——数据分析

    R语言 什么是数据分析 数据 数据 xff1a 是指对客观事件进行记录并可以鉴别的符号 xff0c 是对客观事物的性质 状态以及相互关系等进行记载的物理符号或这些物理符合的组合 为什么要做数据分析 我们可以通过数据分析的结果来指导决策 数据
  • CentOS 7 云服务器安装mysql5.7

    将mysql5 7的安装包上传到主机上 解压安装到 opt app 中 tar zxvf mysql 5 7 34 linux glibc2 12 x86 64 tar gz C opt app 修改目录名 mv opt app mysql
  • java求1000以内的完数及分析

    需求 一个数如果恰好等于它的因子之和 这个数就称为 完数 例如 6 61 1 43 2 43 3 编程找出 1000 以内的所有完数 分析 一千个数肯定跑不了循环的使用 xff0c 常用的循环有两个 xff0c 一个是for xff0c 一
  • 数据结构算法设计题汇总

    五 算法设计题 xff08 本题10分 xff09 34 二叉排序树的类型定义如下 xff1a typedef struct BSTNode 二叉排序树的结点结构 int data 数据域 struct BSTNode lchild rch
  • 初学node.js 对app.js的解释

    使用各种模块包 http errors模块包主要功能监视http请求过程的错误 中间件middleware xff0c 中间件本质上就是一个模块包 监听错误的中间件 var createError 61 span class token f
  • 什么是原码、反码和补码

    什么是原码 反码和补码 文章目录 什么是原码 反码和补码1 机器数2 原码3 反码4 补码5 总结 1 机器数 前言 一个数在计算机中的表示形式是二进制的话 xff0c 这个数其实就叫机器数 机器数通常是带有符号的 xff08 指有正数和负
  • ros找不到包的两种原因

    目前遇到的找不到包的两种情况是 没有设置环境变量而找不到包 解决方法1 xff0c 当前终端输入source 加包所在工作空间的devel set bash的绝对路径或相对命令行的路径 解决方法2 xff0c 打开用户目录 xff5e 的
  • Python 设计一个窗口程序,进行多种数学计算

    设计一个窗口程序 xff1a 想要实现四种功能 xff1a 1 设置按钮 x1f518 1 xff1a 点击 弹出三行输入框 输入函数表达式 显示其Latex数学表达式 输入三个函数 分别为 f 1 x f 2 x f 3 x 点击 run
  • OpenGL:如何从缓存中读取颜色、深度信息【转】

    GPU渲染完数据在显存 xff0c 回传内存的唯一方式glReadPixels函数 显存也被叫做显示内存 帧缓存 xff0c 它是用来存储显示芯片处理过或者即将读取的渲染数据 如同计算机的内存一样 xff0c 显存是用来存储图形数据的硬件