`
hereson3
  • 浏览: 162969 次
  • 性别: Icon_minigender_2
  • 来自: 广州
社区版块
存档分类
最新评论

OpenGL的帧缓冲对象和浮点纹理

阅读更多



接下来准备实现光照贴图的打包和预计算了。因为想实现HDR,光照贴图准备存储为 RGBE或浮点格式。为了渲染浮点格式的光照贴图,就需要解决两个问题,一是如何让OpenGL能够真正地处理浮点格式的纹理,而不是把他们截断到 [0,1]区间内;二是如何将场景渲染到浮点格式的纹理中,以便对这个纹理进行Tone mapping 和Bloom等操作。

今天花了一晚上的时间在网上搜索资料,学习了Frame Buffer Object的用法。FBO是目前实现RTT和GPGPU算法最好的解决方案,因为它的接口设计相对合理,避免了显存到内存之间的数据交换。

FBO相当于各类帧缓冲,是一个渲染对象。在传统的渲染管线中,渲染后的数据输出到各种帧缓冲中,如颜色缓冲,深度缓冲等。有了FBO之后,就可以把数据渲染到已粘附到FBO的纹理中。稍后将会给出具体的代码,结合代码和分析你将很容易掌握FBO的用法。

现在先讨论一下OpenGL的浮点纹理。我们先来看一下OpenGL的glTexImage2D函数原型。

void glTexImage2D(

       GLenum target,
      GLint level,
      GLint internalformat,
      GLsizei width,
      GLsizei height,
      GLint border,
      GLenum format,
      GLenum type,
      const GLvoid *pixels
    );

 

以前,我们向纹理对象提供数据时是这样做的:

glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,pixels);

我们为Type参数提供的值是GL_UNSIGNED_BYTE表示我们的数据在内存中的存储格式为无符号字节型整数。现在我们的纹理格式为浮点型,我们会很自然地想到,能不能把上述函数调用改为:

glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,GL_FLOAT,pixels);

来让OpenGL接收浮点纹理呢?答案是不可以。使用GL_FLOAT调用该函数后,glTexImage确实能够接收浮点数据,但type参数表示的仅仅是象素数据在主内存中的存储格式,一个象素在显存里如何储存仅由 internalformat参数决定。这里internalformat如果设置为GL_RGBA,则表示象素存储为8位整数的RGBA格式。这样一来,当函数在接收数据时,会自动把浮点类型的象素数据截断到[0,255]的整数区间内,然后再放到显存中去,这就丢失了浮点数据。

GL_ARB_texture_float扩展解决了这个问题。这个扩展为我们提供了一些新的内部数据类型,包括GL_RGB16F_ARB, GL_RGBA16F_ARB, GL_RGB32F_ARB, GL_RGBA32F_ARB等。其中16F表示半精度浮点数。半精度浮点数占用两个字节,包括1位的符号位,5位的指数位(Exponent)和10位的尾数位(Mantissa)。要注意一些老的显卡可能不支持对GL_RGBA32F_ARB和GL_RGB32F_ARB等32位浮点纹理进行双线性纹理过滤(如我以前使用的GeForce 6200)。同时考虑到空间因素,目前主要还是使用16F的纹理。当我们把纹理内部数据类型指定为这些浮点类型时,OpenGL就不会再把我们提供的纹理数据截断到[0.0,1.0]区间上了。如果我们指定的是16F格式的纹理,OpenGL会自动将我们提供的32bit浮点数据转换为16Bit的数据格式。因此我们唯一要做的事情就是把函数调用改成这样以支持Floating Point纹理:

glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA16F_ARB,width,height,0,GL_RGBA,GL_FLOAT,pixels);

好了,现在通过一段代码解释FBO的用法。下面的这段代码是我探索FBO时写的。这里贴出来解释一下。前面的初始化代码就省略了。

    这个代码所作的事情就是,创建一个浮点纹理,然后使用这个浮点纹理向FBO绘制一个矩形,

    再把FBO中的数据读回内存。

    glEnable(GL_TEXTURE_2D);
    // 首先我们创建一个纹理,然后用这个纹理渲染一个QUAD。
    glGenTextures(1,&texid);
    
    glBindTexture(GL_TEXTURE_2D,texid);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

    随便创建一个浮点型的数组,代表我们的浮点纹理。

    float *tex = new float[1024*4];
    for (int i=0;i<32;i++)
        for (int j=0; j<32;j++)
        {
            tex[i*32*4+j*4] = 1000.3f;
            tex[i*32*4+j*4+1] = 1900.3f;
            tex[i*32*4+j*4+2] = 1099.3f;
            tex[i*32*4+j*4+3] = 1.0f;
        }


    //把纹理格式设置为半精度浮点,然后传入一个事先生成的浮点型数组。

    glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA16F_ARB,32,32,0,GL_RGBA,GL_FLOAT,tex);
    if (glGetError()!=GL_NO_ERROR )
    {
        ui->Console->PrintString(HString("Error Occured."));
    }
    
    // 注意,HFBO是我自己封装的OpenGL函数库,其中fbo.xxx相当于glxxxEXT函数。
    // 如fbo.GenFramebuffers就相当于glGenFramebuffersEXT。
    HFBO fbo;

    首先,创建一个帧缓冲对象:


    GLuint fboid;
    fbo.GenFramebuffers(1,&fboid);

    然后绑定这个对象:

    fbo.BindFramebuffer(GL_FRAMEBUFFER_EXT,fboid);

    接着创建一个纹理,然后把这个纹理粘附到FBO中,这样渲染后的颜色缓冲就会被写入这个纹理:

    GLuint texColorBuf;
    glViewport(0,0,32,32);
    glGenTextures(1,&texColorBuf);
    glBindTexture(GL_TEXTURE_2D,texColorBuf);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

    现在创建的是32Bit浮点纹理,指定相应的格式:

    glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA32F_ARB,32,32,0,GL_RGBA,GL_FLOAT,0);

    接下来是重点。glFramebufferTexture2DEXT函数将一个纹理对象粘附到当前绑定的FBO中。
    注意第二参数指定了帮定点。一个FBO可以有多个帮定点,这样数据可以同时写入到多个纹理对象中。
    因为我们目前只有一个纹理对象,所以将绑定点设置为GL_COLOR_ATTACHMENT0_EXT。
    fbo.FramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,

        GL_TEXTURE_2D, texColorBuf, 0);

    接下来glCheckFramebufferStatus函数检查当前的帧缓冲对象是否准备就绪。如果就绪,

    函数返回GL_FRAMEBUFFER_COMPLETE_EXT。

    if (fbo.CheckFramebufferStatus(GL_FRAMEBUFFER_EXT)!=GL_FRAMEBUFFER_COMPLETE_EXT)
        PrintString("Frame buffer not ready.");
    
    现在我们渲染场景。渲染后的颜色数据将写入到当前绑定的FBO对象中。如果不需要向FBO中写入数据,

    而直接绘制到屏幕缓冲区,则调用glBindFramebuffer(GL_FRAMEBUFFER_EXT,0);以取消帧缓冲对象。

    BeginUIDrawing();
        glBindTexture(GL_TEXTURE_2D,texid);
        glColor4ub(255,255,255,255);
        glBegin(GL_QUADS);
            glTexCoord2i(0,0);
            glVertex2i(0,0);
            glTexCoord2i(0,1);
            glVertex2i(0,32);
            glTexCoord2i(1,1);
            glVertex2i(32,32);
            glTexCoord2i(1,0);
            glVertex2i(32,0);
        glEnd();
    EndUIDrawing();

    现在我们创建一个浮点数组,然后试着从刚才已粘附到FBO中的纹理对象读取数据。

    看看这些数据是否和我们的预期相符。    

    float *datar = new float[32*32*4];
    glBindTexture(GL_TEXTURE_2D,texColorBuf);
    
    glReadPixels(0,0,32,32,GL_RGBA,GL_FLOAT,datar);
    glGetTexImage(GL_TEXTURE_2D,0,GL_RGBA,GL_FLOAT,datar);
    
    如果你愿意,可以在此设置一个断点,观察一下datar中的值。    

    程序到此结束,执行清理。

    glDeleteTextures(1,&texColorBuf);
    glDeleteTextures(1,&texid);
    fbo.DeleteFramebuffers(1,&fboid);
    delete [] datar;
    delete [] tex;

如果你还想了解更多关于FBO以及GPGPU的知识,可以参考这篇文章:GPU深度发掘, 作者:Rob 'phantom' Jones 译者:华文广。

分享到:
评论

相关推荐

    OpenGL ES 纹理实例

    OpenGL ES 3.0引入了更多的特性,如浮点纹理支持、帧缓冲对象(FBOs)和顶点数组对象(VAOs),使得处理纹理和其他图形元素变得更加高效和灵活。 在实际开发中,你可能需要考虑纹理压缩,以减少内存占用和提高性能...

    OpenGL教程第36课渲染到纹理.rar

    OpenGL教程第36课主要讲解的是“渲染到纹理”(Render To Texture,简称RTT)这一高级技术。渲染到纹理是计算机图形学中...在实际编程中,你可能还需要考虑多纹理、MIP贴图、浮点纹理等高级特性,以满足更复杂的需求。

    OPENGL ES 3.0编程指南.pdf

    1. **着色语言GLSL ES 3.00**:OpenGL ES 3.0引入了GLSL ES 3.00版本的着色语言,增加了对浮点纹理、更多数据类型、混合函数、矩阵操作以及计算着色器的支持。开发者可以利用这些特性创建更复杂的着色效果。 2. **...

    OpenGL4.2规范及说明

    OpenGL 4.2的核心特性包括对现代硬件的优化支持,改进的着色器语言(GLSL 4.20),以及对纹理和缓冲对象的增强功能。 1. **核心模式与兼容模式**:OpenGL 4.2区分了核心模式和兼容模式。核心模式只包含现代OpenGL...

    OPENGL ES 3.0编程指南 原书第2版 .rar

    1. **着色器语言(GLSL ES)**:OpenGL ES 3.0引入了GLSL ES 3.00,这是一种用于编写顶点和片段着色器的语言,支持更多的数据类型,如浮点纹理和双精度浮点计算,以及更高级的数学函数,使得图形处理能力显著提升。...

    OpenGL ES编程指南

    5. **帧缓冲对象**(Frame Buffer Objects, FBO):FBO是OpenGL ES 2.0中的一种重要特性,允许开发者创建自定义的渲染目标,例如多重渲染或后期处理效果。 6. **顶点数组和顶点缓冲对象**(Vertex Array Objects, ...

    opengles3.0游戏开发(上

    利用GLSL ES 3.00的浮点纹理和着色器,可以创建复杂的光照模型和实时阴影。 2. **粒子系统** 利用统一缓冲对象,可以高效地管理大量粒子的状态,创建出逼真的火焰、烟雾和爆炸效果。 3. **高级渲染技术** MSAA...

    OPENGL2.0完整开发库

    3. **纹理和浮点纹理**:OpenGL 2.0支持纹理和浮点纹理,使开发者能够存储和处理浮点数值,这对于科学可视化和图像处理应用非常有用。 4. **顶点数组对象**(Vertex Array Objects, VAOs):VAOs简化了顶点数据的...

    OPENGL ES 3.0编程指南

    新的顶点着色器和片段着色器语言GLSL ES 3.00提供了更多的数据类型,如浮点纹理和浮点常量,以及对向量和矩阵操作的增强支持。这使得开发者能够实现更为复杂的光照、阴影和纹理效果。同时,计算着色器的引入允许在...

    opengl es 3.x

    3. **帧缓冲对象(FBO)增强**:FBO在3.x中支持更多的附件类型,包括浮点纹理,这使得离屏渲染和后期处理效果更加灵活。 4. **纹理立方体贴图阵列**:新的纹理类型支持纹理立方体贴图阵列,这对于环境映射和空间...

    OpenGL-1.2.zip

    3. **浮点纹理**:引入了对浮点纹理的支持,允许在纹理中存储浮点数据,这对于科学可视化和后期处理特效非常有用。 4. **FBO(帧缓冲对象)**:虽然FBO是在OpenGL 1.4中正式引入的,但1.2版本可能包含了基础的雏形...

    opengles3-book_opengl_

    4. **浮点纹理**:OpenGL ES 3支持浮点纹理,使得可以存储和处理浮点数值,这对于科学可视化、光照计算和后期处理效果至关重要。 5. **多重纹理**:OpenGL ES 3支持多重纹理采样,可以在同一片元操作中结合多个纹理...

    OpenGL ES 3.0

    该章提供了创建纹理、加载纹理数据以及纹理渲染的细节,描述了纹理包装模式、纹理过滤、纹理格式、压缩纹理、采样器对象、不可变纹理、像素解包缓冲区对象和Mip贴图。该章介绍了OpenGL ES 3.0支持的所有纹理类型:2D...

    OpenGL3.3_HDR.rar

    1. **浮点纹理支持**:OpenGL 3.3引入了对浮点纹理的全面支持,这意味着纹理可以存储为浮点数,而不是传统的8位或16位整数。这使得纹理可以表示更广泛的色彩和亮度范围,是实现HDR的基础。 2. **颜色缓冲区格式**:...

    富士通半导体推出新版CGI Studio可支持OpenGL ES 3.0.pdf

    2. **浮点纹理支持**:OpenGL ES 3.0引入了浮点纹理,允许使用浮点数值来存储纹理数据,这对于科学可视化、图像处理和高级光照效果等应用非常有用。 3. **帧缓冲对象扩展**:增强了帧缓冲对象(Framebuffer Object,...

    opengl_es 3.0 Demo

    1. **浮点纹理和颜色缓冲**:OpenGL ES 3.0支持浮点纹理和颜色缓冲,允许更精确的颜色表示和更复杂的计算着色器。 2. **多采样抗锯齿(MSAA)**:提高了图像质量,减少了边缘的锯齿现象,使得画面更加平滑。 3. **...

    Sample6_4.rar_OpenGL ES 4.0_opengl es 2.0

    2. **纹理和帧缓冲对象**:OpenGL ES 4.0增加了对多级渐远纹理(Mipmapping)、浮点纹理、立方体贴图阵列和深度/ stencil纹理的支持。此外,通用帧缓冲对象(Framebuffer Objects)允许开发者将多个渲染目标绑定到...

    OpenGL ES 3D绘图基本概念

    OpenGL ES 3.0支持浮点纹理,允许在纹理中存储和处理浮点数据,增强了图像处理和计算图形的灵活性。 6. **多重采样抗锯齿(Multisample Anti-Aliasing, MSAA)** 提供了硬件加速的抗锯齿功能,可以显著改善边缘的...

    Wright - OpenGL SuperBible 4e-1262.pdf

    在OpenGL中,帧缓冲区可以被用来实现双缓冲、累积缓冲、浮点缓冲等技术。 纹理映射 纹理映射是一种将图像应用于3D模型的技术。它可以用于实现各种图形效果,如木纹、石纹、金属纹等。在OpenGL中,纹理映射可以被...

Global site tag (gtag.js) - Google Analytics