« 成员函数指针使用小感伺机而动,设计模式之观察者(Observer) »

联结FBO与Texture Array

 glFramebufferTextureLayerEXT,一个我曾经花去差不多一天的时间去证明它是“错误”的OPENGL 2.0 API函数,一个在整个在校周里我所认为的Cascading Shadow MAPs算法的坎。它在今天以其压倒性的“囧气”告诫ZwqXin:别怀疑!我乃是正确的!有时候,不清晰的稀少的GOOGLE结果会迷惑你,有时候,真正的错误会让你错怪他者好让他自身得以永远藏身。如果不是这强迫性的最后一道执念,我也许就会放弃这个函数,转求其他未知的复杂之法——难以再信任它。glFramebufferTextureLayerEXT,对不起,是我错了。——ZwqXin.com

本文来源于 ZwqXin (http://www.zwqxin.cn/), 转载请注明
      原文地址:http://www.zwqxin.cn/archives/opengl/link-fbo-and-texture-array.html

glFramebufferTextureLayerEXT是什么API?习惯性地google一下,它会出现在两种地方:第一种,是opengl 2.0规范的函数列表中,以及讲述Texture Array拓展使用的规范里。第二种,抱怨“glFramebufferTextureLayerEXT doesn't work! ”的外国论坛帖子里(虽然为数不多)。而今天我得在此增加第三种:一个讲述opengl与ZwqXin的故事的中文博客里,讲述glFramebufferTextureLayerEXT的一点使用以及为它澄清——至少在NVIDIA 9series的显卡里,它能正常被使用(注意,我不是说9series以下的就不行,因为我没在其他机器上测试过)。

glFramebufferTextureLayerEXT目的在于联系FBO与Texture Array,这一点从其名字就能明白。关于Texture Array,可以参考我写的这篇文章:学一学, Texture Array纹理数组 ,它目的在于让我们可在一个纹理单元内存储多幅纹理图,形成一个数组般的数据结构(但是用法不同的哦,注意,详见该文章);关于FBO,也可以参考我写的这篇文章:学一学,FBO ,它的目的在于建立一个缓存区用作离屏渲染(渲染的结果的颜色深度蒙板等都可以放入里面),这个缓存区可以是renderbuffer,也可以是纹理。好了,如果有人希望把离屏渲染结果渲染(或者说,保存)到一个纹理数组对象中,可以吗?opengl实在没有理由在这点小要求上限制我们,但是你必然想到opengl在进行此等操作的时候会先问你一句:你是想保存到这个纹理数组中的哪个纹理图上呢?你要怎么回答呢?

void glFramebufferTextureLayerEXT(enum target, enum attachment, uint texture, int level, int layer),这跟连接FBO与纹理的API:glFramebufferTextureEXT( GLenum target, GLenum attachment, GLuint texture, GLint level ) 基本是一样的,独特之处在于最后多了一个参数layer。在学一学, Texture Array纹理数组里说过了,“层(layer)”这个概念在文理数组中相当于“数组下标”,它检索以0开始的数组内的各个纹理。你就是要在这里回答:我要把离屏渲染结果保存到第layer层的那个纹理图上。

这可以在预处理阶段就联结好它们:FBO与某个纹理图。但是如果这样的话,用纹理数组还有啥意义呢?要关联多个纹理,何不把FBO与多个单一的纹理图联结?反正GL_COLOR_ATTACHMENTi_EXT一般至少系统给了你4个(日后还可能增加呢~)。当然方便是其中之一,节省资源是其中之二(MS~)。我们可以在运行期间就改变FBO与纹理数组中具体某个纹理图的关联。以下是预处理,我们分别建立两者:

  1. //我们建立FBO,但不给它绑定些什么。
  2. glGenFramebuffersEXT(1, &fbo_id);
  3. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id);
  4. glDrawBuffer(GL_NONE);
  5. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  6.  
  7. //另外再建立一个纹理数组,注意,现在FBO与texture array没有任何关联
  8. glGenTextures(1, &depth_tex_ar);
  9. glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, tex_array_id);
  10. glTexImage3D(.....)
  11. glTexParameteri......

以下是渲染阶段,按CSM的算法,我要把不同Crop矩阵下(对应光源视野远近,范围)的场景深度各自保存到各一张的文理图上。glFramebufferTextureLayerEXT可以简单完成这工作:注意,下面它在运行期间不断改变FBO与纹理数组中的各个纹理图的关联:

  1. GenShadowMap()//处于渲染阶段前期
  2. {
  3. ......
  4. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id);
  5.  
  6.   for(int i=0; i<纹理图数目; i++)
  7.   {
  8.   glFramebufferTextureLayerEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texture_arrray_id, 0, i );
  9.  
  10.   .....(改变当前光源的crop矩阵)
  11.   glClear(GL_DEPTH_BUFFER_BIT);//清除上次渲染到纹理后的残余像素格式
  12.   RenderObjects();
  13.   ....
  14.   }
  15. .....
  16. }

很简单吧?结果就是纹理数组里面各个纹理图都有了所需要的不同的场景深度信息,目的达成,接下来在fragment shader里按texture array处理各个纹理图的方式去完成应用就可以了。好吧,想象不用glFramebufferTextureLayerEXT时那工作量,那fragment shader的处理,那效率......

对不起,glFramebufferTextureLayerEXT,是我错怪了你,而且还讨厌了你五天之久......真正罪过的,是我这白痴的粗心大意,在两个地方把(X,Y,Z)笔误成(X,X,Z)!

本文来源于 ZwqXin (http://www.zwqxin.cn/), 转载请注明
      原文地址:http://www.zwqxin.cn/archives/opengl/link-fbo-and-texture-array.html

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

IE下本页面显示有问题?

→点击地址栏右侧【兼容视图】←

日历

Search

网站分类

最新评论及回复

最近发表

Powered By Z-Blog 1.8 Walle Build 100427

Copyright 2008-2024 ZwqXin. All Rights Reserved. Theme edited from ipati.