文档简述: 随着显卡的飞速发展,更快的速度以及越来越多的新功能为硬件所支持,硬件的进步使得图形程序开发人员可以创造出更加绚丽的视觉效果,现在,电影级动画的实时渲染已不再是梦想。我们怎么在OpenGL中利用显卡的新特性呢?答案就是OpenGL扩展。 注:如不作特别说明,本站文章中的显卡均指面向普通用户的非专业显卡。 文档目录: OpenGL扩展 显卡差异 顶点/片断编程 Cg/RenderMonkey/及其他 文档内容: OpenGL扩展(OpenGL Extensions)OpenGL和Direct3D比较起来,最大的一个长处就是其扩展机制。硬件厂商开发出一个新功能,可以针对新功能开发OpenGL扩展,软件开发人员通过这个扩展就可以使用新的硬件功能。所以虽然显卡的发展速度比OpenGL版本更新速度快得多,但程序员仍然可以通过OpenGL使用最新的硬件功能。而Direct3D则没有扩展机制,硬件的新功能要等到微软发布新版DirectX后才可能支持。 OpenGL扩展也不是没有缺点,正因为各个硬件厂商都可以开发自己的扩展,所以扩展的数目比较大,而且有点混乱,有些扩展实现的相同的功能,可因为是不同厂商开发的,接口却不一样,所以程序中为了实现这个功能,往往要为不同的显卡写不同的程序。这个问题在OpenGL 2.0出来后可能会得到解决,OpenGL 2.0的一个目标就是统一扩展,减少扩展数目。
扩展名
GL_ARB_multitexture 第一段GL,用来表示针对OpenGL哪部分开发的扩展,有以下几个值:
第二段ARB,用来表示是谁开发的这个扩展,常见以下几个值:
第三段multitexture就是真正的扩展名了,如multitexture就是多重纹理扩展。
使用OpenGL扩展 要使用一个OpenGL扩展,首先必须检查显卡是否支持这个扩展,以下代码可以获取一个显卡支持的的OpenGL扩展: "GL_ARB_imaging GL_ARB_multitexture GL_ARB_point_parameters ……"
OpenGL扩展往往都会新增一些函数,在Windows平台上,这些函数不是通过.lib库连接到程序里的,而要在运行时动态获得函数的指针。我们以GL_ARB_point_parameters扩展为例看看怎么获得函数指针。
首先要定义函数指针类型,
typedef void (APIENTRY * PFNGLPOINTPARAMETERFARBPROC)(GLenum pname, GLfloat param); 这个工作SGI已经为我们做好,它提供了一个头文件 glext.h ,里面有目前绝大多数扩展的常量和函数指针定义,下载下来放到编译器的include/GL文件夹下面,然后在程序里面加上:
#include <GL/glext.h> 就可以在程序中使用常量和函数指针类型了。
然后要定义函数指针:
PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB;
int hasPointParams = isExtensionSupported("GL_ARB_point_parameters"); 如果支持,就可以用wglGetProcAddress函数获取扩展函数的指针: if (hasPointParams) { if (hasPointParams) {
WGL扩展glGetString( GL_EXTENSIONS )取得的扩展字符串中并不包括针对Windows平台的WGL扩展,WGL扩展串要通过WGL_ARB_extensions_string扩展来获得,以下代码演示了如何获得WGL扩展串:
定义WGL_ARB_extensions_string扩展新增函数wglGetExtensionsStringARB的函数指针类型,同样这个工作SGI已经为我们做好,只不过不在glext.h中,而在它提供的另外一个头文件 wglext.h 中:
typedef const char *(APIENTRY * PFNWGLGETEXTENSIONSSTRINGARBPROC)( HDC hdc);
定义函数指针: PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;
检查是否支持WGL_ARB_extensions_string扩展,如果不支持,表示这个显卡不支持WGL扩展,如果支持,则得到wglGetExtensionsStringARB函数的指针,并调用它得到WGL扩展串: int hasWGLext = isExtensionSupported("WGL_ARB_extensions_string"); if (hasWGLext) { wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) / wglGetProcAddress( "wglGetExtensionsStringARB" ); const char *wglExt = wglGetExtensionsStringARB( hdc ); …… }
OpenGL版本一些常用的OpenGL扩展会在新版的OpenGL中加到OpenGL核心中去,成为OpenGL标准的一部分,可以简化程序开发,程序员使用这些功能时不必做繁琐的扩展初始化工作。比如多重纹理功能,在OpenGL1.2.1加入到OpenGL核心中,以前要使用多重纹理,要先检查是否支持GL_ARB_multitexture扩展,然后初始化glActiveTextureARB等函数,很麻烦,而OpenGL1.2后,则可以直接使用glActiveTexture函数。 不过,这种简化只有Mac/Unix/Linux程序员才能享受到,在Windows平台上没有这么简单。微软为了维护Direct3D,对OpenGL的支持很消极,其OpenGL实现仍然是1.1。由于Windows上的OpenGL程序最终都会动态链接到微软的OpenGL32.dll,可OpenGL32.dll只支持OpenGL 1.1,使我们不能直接使用新版OpenGL,仍然要用扩展访问OpenGL1.1以来新增的功能。
OpenGL扩展资料 All About OpenGL Extensions : OpenGL Extension Registry : OpenGL Hardware Registry :
|
nVIDIA | ATI | |||
芯片代号 | 显卡型号 | 芯片代号 | 显卡型号 | |
NV1 NV2 NV3 NV4 NV5 | NV1 Riva 128 Riva 128ZX Riva TnT Riva TnT2 | RAGE(?) | RAGE PRO RAGE 128 RAGE 128 PRO | |
NV10 NV11 NV15 NV17 NV18 | GeForce 256 GeForce2 MX * GeForce2 * GeForce4 MX * GeForce4 MX AGP8X * | R100 RV200 | RADEON 7000 RADEON RADEON 7200 RADEON 7500 | |
NV20 NV25 NV28 | Geforce3 Ti200 GeForce3 GeForce3 Ti500 GeForce4 Ti * GeForce4 Ti AGP 8X * | RV250 R200 RV280 | RADEON 9000 RADEON 8500 RADEON 9100 RADEON 9200 AGP 8X | |
NV34 NV31 NV30 NV35 | GeForce FX 5200 GeForce FX 5600 GeForce FX 5800 GeForce FX 5900 | RV300 RV350 R300 R350 | RADEON 9500 RADEON 9600 RADEON 9700 RADEON 9800 |
·其中标注 * 的是产品系列,型号还会细分
·通常大家习惯用芯片代号的主版本号来统称一代芯片,例如用NV20统称NV20/NV25/NV28,用R200统称RV250/R200/RV280
·虽然ATI RADEON 7500的芯片型号是RV200,但实际属于R100档次的产品
我们来看一个执行路径的例子,idSoftware即将推出的Doom3的执行路径。
Doom3一共有6条执行路径:
-
ARB:几乎不使用扩展,没有镜面高光效果,没有顶点编程(vertex program),保证程序能在低端显卡上运行
-
NV10:支持所有功能,每帧需要渲染5个pass(five rendering passes,指一个对象多次送入渲染管道,比如第一次渲染漫射光diffuse,第二次渲染镜面高光specular ……,各次渲染结果通过glBlend混合在一起形成最终效果),没有顶点编程
-
NV20:支持所有功能,2或3个pass
-
NV30:支持所有功能,1个pass
-
R200:支持所有功能,大部分情况下只需1个pass
-
ARB2:支持所有功能,浮点片断编程(fragment program),1个pass
nVIDIA显卡可能执行ARB / NV10 / NV20 / NV30 / ARB2 五条路径,其中NV10 / NV20 / NV30 专门针对不同档次的nVIDIA显卡开发的。
ATI显卡可能执行 ARB / R200 / ARB2 三条路径,其中R200是专门针对ATI开发的。
而其他显卡则根据档次高低执行ARB或ARB2路径。ARB用于低端显卡,ARB2用于高端显卡。
顶点/片断编程
1999年底,nVIDIA推出GeForce 256,并开始使用GPU(Graphics Processing Unit)来称呼显卡芯片(也有厂商叫VPU(Visual Processing Unit),是一回事)。GeForce 256最大卖点是硬件T&L(Transform&Lighting,变换和光照),这意味着变换和光照计算可以在GPU中进行,大大减轻了CPU的压力,显卡开始成为独立于CPU的一个处理器。
硬件T&L后,GPU最激动人心的进步就是引入了可编程能力。我们知道,OpenGL和Direct3D都有固定的渲染管线,定义光源,送入顶点位置、法线、纹理坐标等,就可以给你渲染出一幅图像来,程序员对具体的渲染过程无法控制。而OpenGL扩展和DirectX8给渲染管线引入可编程能力,图形软件开发人员可以编写运行于显卡芯片的汇编程序来控制具体的渲染过程,这给予图形软件开发更大的灵活性,并且由于硬件的支持,获得这些灵活性并不会牺牲性能。GPU的可编程能力对实时图形渲染会产生深远的影响。
OpenGL支持两种可编程模型:
-
顶点编程Vertex Program,对应于Direct3D中的Vertex Shader,提供可编程的T&L能力,代替了传统渲染流水线中的T&L,处理顶点的变换、光照计算
-
片断编程Fragment Program,对应于Direct3D的Pixel Shader,提供可编程的光栅化操作,代替了传统流水线中的纹理映射、逐像素颜色及雾效处理
目前顶点编程相关的扩展有:
-
GL_NV_vertex_program:nVIDIA NV10档次显卡用软件模拟,NV20及以上档次显卡上硬件支持
-
GL_NV_vertex_program1_1:nVIDIA NV10档次显卡用软件模拟,NV20及以上档次显卡上硬件支持
-
GL_EXT_vertex_shader:在ATI R200及以上档次显卡上支持
-
GL_ARB_vertex_program:由上面三个扩展发展而来,支持上面三个扩展的显卡安装最新的驱动程序后都会支持此扩展,所以程序中不必支持上面三个扩展,只支持此扩展就可以了。此扩展不支持分支循环
-
GL_NV_vertex_program2:在nVIDIA NV30及以上档次显卡上支持,支持分支循环,估计会成为GL_ARB_vertex_program2扩展的原型
-
实际上ATI R300级别的显卡已经在顶点编程中支持分支循环(硬件支持DirectX9的vs2.0),但并没有开发扩展提供给OpenGL程序员使用,估计是在等支持分支循环的GL_ARB_vertex_program2扩展出台
可见现在使用OpenGL的vertex program,只需支持GL_ARB_vertex_program和GL_NV_vertex_program2两个扩展。
目前片断编程相关的扩展有:
-
GL_NV_register_combiners:在nVIDIA NV10及以上档次显卡上支持,处理逐像素颜色及雾效计算
-
GL_NV_register_combiners2:在nVIDIA NV20及以上档次显卡上支持,对GL_NV_register_combiners作了个简单的扩展,支持两个常量寄存器在每级combiner都可以有不同的值
-
GL_NV_texture_shader / GL_NV_texture_shader2 / GL_NV_texture_shader3:在nVIDIA NV20及以上档次显卡上支持,提供多种功能强大的纹理提取操作
-
GL_ATI_fragment_shader:在ATI R200及以上档次显卡上支持
以上扩展提供的功能不是编写运行于GPU的汇编码,而是通过函数调用的方式实现,不如编写汇编码直观方便。下面几个扩展则可以通过编写汇编码来实现片断编程
-
GL_ATI_text_fragment_shader:实际上就是GL_ATI_fragment_shader的汇编码版本,到现在还没看到在PC上的支持信息,看来只会在苹果机上支持
-
GL_ARB_fragment_program:在nVIDIA NV30 / ATI R300及以上档次显卡上支持
-
GL_NV_fragment_program:在nVIDIA NV30及以上档次显卡上支持,比GL_ARB_fragment_program更强大
与顶点编程相比,片断编程要复杂得多:
-
在NV10系列上,只能使用GL_NV_register_combiners提供的部分片断编程能力
-
在NV20系列上,则可以使用register combiners和texture shader实现片断编程
-
在NV30系列上,可以使用GL_ARB_fragment_program和GL_NV_fragment_program
-
在ATI R200系列上,使用GL_ATI_fragment_shader
-
在ATI R300系列上,使用GL_ARB_fragment_program
看到这里我们不难理解为什么Doom3会将渲染执行路径分成ARB、NV10、NV20、NV30、R200、ARB2几条了:
-
ARB既没有顶点编程也没有片断编程
-
NV10没有用到顶点编程(虽然NV10支持顶点编程,但是是软件模拟,而显卡硬件并不支持),但用到register combiners实现凹凸贴图(Bump Mapping)
-
NV20使用顶点编程,并用register combiners和texture shader实现片断编程
-
NV30使用顶点编程,并用GL_NV_fragment_program实现片断编程
-
R200使用顶点编程,并用GL_ATI_fragment_shader实现片断编程
-
ARB2使用顶点编程,并用GL_ARB_fragment_program实现片断编程
附表:
nVIDIA显卡顶点、片断编程支持情况
芯片代号 | 纹理单元数 | Register Combiner | Texture Shader | Vertex Program | Fragment Program |
NVX | 2 | X | X | X | X |
NV10 | 2 | 2级 | X | NVvp1.1/ARBvp1.0 | RC |
NV20 | 4 | 8级 | 支持 | NVvp1.1/ARBvp1.0 | RC/TS |
NV30 | 4 | 8级 | 支持 | NVvp2.0/ARBvp1.0 | ARBfp1.0/NVfp |
ATI显卡顶点、片断编程支持情况
芯片代号 | 纹理单元数 | Vertex Program | Fragment Program |
RAGE | 2 | X | X |
R100 | 3 | X | X |
R200 | 6 | EXTvp/ARBvp1.0 | ATIfp |
R300 | 8 | EXTvp/ARBvp1.0 | ARBfp1.0 |
直接使用扩展编写vertex program和fragment program不太方便,要么是函数调用,要么是汇编码,相当于用x86汇编编写PC程序,而现在已经有了面向vertex program和fragment program的高级语言,称为HLSL(高级着色语言,High Level Shading Language)。
Cg是nVIDIA提出的一种高级着色语言,它的语法和C语言类似,可以大大简化vertex program和fragment program的编写。用它写的程序可以:
-
编译成GL_NV_vertex_program / GL_NV_vertex_program1_1 / GL_ARB_vertex_program / GL_NV_vertex_program2 的汇编码
-
编译成GL_ARB_fragment_program / GL_NV_fragment_program的汇编码
-
编译成用于nvParse的RC(Register Combiners)及TS(Texture Shader)脚本
-
直接在程序中调用Cg提供的API,运行Cg程序
-
编译成DirectX的 vertex shader / pixel shader
我们可以看到Cg只是对nVIDIA的产品支持比较好,而其他厂商的产品只有支持GL_ARB_vertex_program/GL_ARB_fragment_program时才能从Cg获得好处,不支持这两个ARB扩展的显卡则不能运行Cg编写的程序,大大降低了Cg的实用性。虽然Cg提供接口,使其他厂商可以对Cg进行扩展,以支持各个厂商自己的OpenGL扩展,不过Cg毕竟是一个企业的产品,别的厂商不会支持,所以如果要写通用的图形程序,Cg并不合适。
况且OpenGL的HLSL——GLslang(OpenGL Shading Language)规范已经被ARB审核通过,估计不久就可以使用GLslang编写vertex program和fragment program,到时Cg的位置应该会相当尴尬,因为OpenGL和DirectX都已经有了自己的HLSL。不过话说回来,Cg可以同时支持OpenGL和DirectX,这也算是它的一个优势。
RenderMonkey
RenderMonkey并不是一种语言,而是ATI推出的一个编写调试vertex program和fragment program的集成开发环境,目前只支持DirectX的vertex shader / pixel shader / HLSL,不过ATI正在和3Dlabs合作,不日RenderMonkey也会支持OpenGL vertex program / fragment program / GLslang。另外,RenderMonkey不仅仅是为程序员设计的,美工也可以使用。
nvParse
nvParse是nVIDIA公司推出的一个库,可以简化RC(Register Combiners)及TS(Texture Shader)的开发。使用GL_NV_register_combiners和GL_NV_texture_shader扩展实现片断编程全是函数调用的形式,很不方便,而nVIDIA为了简化RC和TS程序开发,建立了一种脚本格式,用简单的脚本代替复杂的GL_NV_register_combiners和GL_NV_texture_shader函数调用,nvParse则提供API用于解释执行RC和TS脚本。
模拟NV30
并非所有程序员都有一块NV30显卡,但nVIDIA最新的雷管驱动程序(version 40.41及以后)支持软件模拟NV30架构,只不过很慢,但对没有NV30显卡的程序员已经是个福音了,只要我们有一块GeForce级的显卡,安装最新的雷管驱动程序,然后下载一个NVEmulate.exe (52 KB),运行它,打开NV30模拟,你的显卡就支持NV30的所有功能了,这样就算没有NV30显卡同样可以针对NV30开发程序。要注意的是,不需要NV30模拟的时候要记得关掉它,毕竟是软件模拟,速度很慢。
后记
写这些只是希望为后来的朋友指一个方向,写得很简略,因为我自己也在学习,hoho,更多的东西还是需要大家自己多看多写 :) 我将来也会慢慢放上一些详细的文章以及源码,希望能对大家有所帮助。关于这篇文章的问题或建议,可以写信给我,我的联系方式。