个人感觉,OpenGL最让人蛋疼的是,不开源!只有接口文档,却很少能详细讲解底层机制的文章出现。并且接口的设计和使用让初学者感到很费解,就算你一直在用它,经常看文档,很多地方仍然是知其然而不知其所以然。最近玩了一下一个很牛逼的工具--Graphics API Debugger,可以看到安卓上OpenGL的对象结构和状态变化,对理解OpenGL底层实现非常有帮助!
GAPID图如下:
左边是OpenGL命令,中间是framebuffer的预览图,右边是OpenGL的状态,我们主要看左边和右边。点击左边的某条命令,右边的state栏下的内容就会起相应的变化。
Objects
OpenGL中资源基本上都是以Objects(对象)形式管理的,如framebuffer buffer object(FBO), vertext buffer object(VBO)等, 可以理解为C++对象。在GAPID的右边栏下,我们可以看到有Objects项,下面就有OpenGL中所有的对象。主要研究下以下几个:
//Objects
GeneratedNames;
Buffers;
Framebuffers;
Renderbuffers;
TextureUnits;
Textures;
VertexArrays;
GeneratedNames
点击GeneratedNames项的三角形,展开如下:
GeneratedNames实际上就是用OpenGL命令glGen~生成的名称,如看下glGenBuffer的官方API解释:
glGenBuffers
returns n
buffer object names in buffers
. There is no guarantee that the names form a contiguous set of integers; however, it is guaranteed that none of the returned names was in use immediately before the call to glGenBuffers
.
No buffer objects are associated with the returned buffer object names until they are first bound by calling [glBindBuffer]。
由上可知,glGenBuffers返回n个buffer object names,注意调用glGenBuffers并不会生成buffer objects(你可以GAPID中观察,仅点击glGenBuffers命令,Objects下的Buffers数组不会增加新的元素)。
glGenBuffer对应的就是GeneratedNames下的Buffers,你可以把它理解为一个数组,当你调用一次glGenBuffer生成一个新的name时,Buffers将新增加一个元素,如下图:
1是返回的name的id。其他如glGenTexture, glGenFramebuffers等也同理,当你调用后,会在GeneratedNames下的Textures,Framebuffers数组中看到新添加的元素的id。
Buffers
接着看Objects下的Buffers,Buffers从名字看它像是一块内存数据,其实不是,它只是一个Object,但可以推测,它一定有某个成员变量的指针指向一块内存地址。
上面也提到,glGenBuffer只是返回name,并不会生成buffer object,要生成buffer object需要调用glBindBuffer接口。我们在GAPID中点击一个glBindBuffer命令,会看到Buffers下多了一个元素,如下图:
从图中我们也可以看到Buffer对象的数据结构,其中有id,还有刚说的Data指针,指向真正的存储数据的内存,现在它还是nil,这是因为glBindBuffer只是创建了Buffer对象,并不会为它分配内存,而分配内存需要调用glBufferData接口。在GAPID中点击一条glBufferData命令,可以看到Buffer对象的Data有了数据,如下图:
Texture
Texture等objects和Buffer类似,不再赘述。
Framebuffer
Framebuffer可以说是OpenGL中最重要的一个对象了。对于它的描述可以参看前面的文章《OpenGL文档翻译:FBO》。简而言之,你可以把它当做是一次渲染的目的地,Framebuffer对象中有多个ColorAttachments,一个DepthAttachments和一个StencilAttachments,渲染的最后步骤就是把颜色内容存到绑在ColorAttachments上的texture或renderbuffer上,把深度内容存到DepthAttachments绑定的...上,把模板内容存到StencilAttachments绑定的...上。
在GAPID中执行glGenFramebuffers和glBindFramebuffer命令后,可以看到右边的Objects下的Framebuffers数组新增一个元素1(注意id0在OpenGL中都是保留的),如下图:
我们可以看到一个famebuffer对象有ColorAttachments,DepthAttachments和StencilAttachments成员,可以把他们看成是数组,只是DepthAttachments和StencilAttachments的元素只有一个,而ColorAttachments可以有多个元素。
我们把一个texture绑定到ColorAttachments上看看会发生什么,调用glFramebufferTexture2D命令,如下图:
可以看到,把一个texture绑定到GL_COLOR_ATTACHMENT0上后,右边的ColorAttachments的0元素的Type变成了GL_TEXTURE,对比没有绑定任何texture的1元素,它的Type为GL_NONE.
网友评论