词条 | OpenGL |
释义 | OpenGL OpenGL是个专业的3D程序接口,是一个功能强大,调用方便的底层3D图形库。OpenGL的前身是SGI公司为其图形工作站开发的IRIS GL。IRIS GL是一个工业标准的3D图形软件接口,功能虽然强大但是移植性不好,于是SGI公司便在IRIS GL的基础上开发了OpenGL。OpenGL的英文全称是“Open Graphics Library”,顾名思义,OpenGL便是“开放的图形程序接口”。虽然DirectX在家用市场全面领先,但在专业高端绘图领域,OpenGL是不能被取代的主角。 § 概述 OpenGL是个与.硬件无关的软件接口,可以在不同的平台如Windows 95、Windows NT、Unix、Linux、MacOS、OS/2之间进行移植。因此,支持OpenGL的软件具有很好的移植性,可以获得非常广泛的应用。由于OpenGL是3D图形的底层图形库,没有提供几何实体图元,不能直接用以描述场景。但是,通过一些转换程序,可以很方便地将AutoCAD、3DS等3D图形设计软件制作的DFX和3DS模型文件转换成OpenGL的顶点数组。 在OpenGL的基础上还有Open Inventor、Cosmo3D、Optimizer等多种高级图形库,适应不同应用。其中,Open Inventor应用最为广泛。该软件是基于OpenGL面向对象的工具包,提供创建交互式3D图形应用程序的对象和方法,提供了预定义的对象和用于交互的事件处理模块,创建和编辑3D场景的高级应用程序单元,有打印对象和用其它图形格式交换数据的能力。 OpenGLOpenGL的发展一直处于一种较为迟缓的态势,每次版本的提高新增的技术很少,大多只是对其中部分做出修改和完善。1992年7月,SGI公司发布了OpenGL的1.0版本,随后又与微软公司共同开发了Windows NT版本的OpenGL,从而使一些原来必须在高档图形工作站上运行的大型3D图形处理软件也可以在微机上运用。1995年OpenGL的1.1版本面市,该版本比1.0的性能有许多提高,并加入了一些新的功能。其中包括改进打印机支持,在增强元文件中包含OpenGL的调用,顶点数组的新特性,提高顶点位置、法线、颜色、色彩指数、纹理坐标、多边形边缘标识的传输速度,引入了新的纹理特性等等。OpenGL 1.5又新增了“OpenGL Shading Language”,该语言是“OpenGL 2.0”的底核,用于着色对象、顶点着色以及片断着色技术的扩展功能。 OpenGL 2.0标准的主要制订者并非原来的SGI,而是逐渐在ARB中占据主动地位的3Dlabs。2.0版本首先要做的是与旧版本之间的完整兼容性,同时在顶点与像素及内存管理上与DirectX共同合作以维持均势。OpenGL 2.0将由OpenGL 1.3的现有功能加上与之完全兼容的新功能所组成(如图一)。借此可以对在ARB停滞不前时代各家推出的各种纠缠不清的扩展指令集做一次彻底的精简。此外,硬件可编程能力的实现也提供了一个更好的方法以整合现有的扩展指令。 目前,随着DirectX的不断发展和完善,OpenGL的优势逐渐丧失,至今虽然已有3Dlabs提倡开发的2.0版本面世,在其中加入了很多类似于DirectX中可编程单元的设计,但厂商的用户的认知程度并不高,未来的OpenGL发展前景迷茫。 OpenGL § 用Delphi进行OpenGL编程 ---- 在开发图形程序时,尤其是三维的图形程序,因为感觉OpenGL没有DirectX那么庞杂,所以选择了DelphiOpenGL,凭感觉而言,Delphi也没有C++那么繁杂而且更加人性化,于是选择Delphi+OpenGL进行工作。在这过程中,碰到(肯定会)一些问题,在此提出希望和朋友们能够进行交流。---- 首先是初始化。初始化时,有几项工作需要进行:①创建设备描述表(Device Context)。(注:关于DC,各种资料译文不尽相同如设备环境、设备描述表、设备上下文等,但好象都不太贴切。要是能有李善兰这样的翻译就好了。下文中的RC情形相同)②设置相应的象素格式(PIXELFORMAT DESCRIPTOR)。③创建着色描述表(Rendering Context)。 Delphi中有好几种获得或创建设备描述表的方法。最简单的就是直接获得画布对象(TCanvas)的句柄属性(Handle),如:DC:HDC; DC:=Canvas.Handle; 也可以用API函数GetDC获得设备描述表。如: DC:=GetDC(Handle,DC);---- 也可以用函数CreateCompatibleDC或者BeginPaint..EndPaint(需要注意它们之间的区别)等来获得设备描述表。但是设备描述表用完之后要记得释放或删除它,以解放资源的占用。拥有设备描述表的使用权后,就可以设置相应的象素格式。象素格式是个记录类型,其中有些字段或域是没什么用处的(至少现在是)。象素格式描述完成后,调用ChoosePixelFormat和SetPixelFormat函数将之与设备描述表进行匹配和设置。如下面代码: function SetupPixelFormat(var dc:HDC):Boolean; var ppfd:PPIXELFORMATDESCRIPTOR; npixelformat:Integer; begin New(ppfd); ppfd^.nSize:=sizeof(PIXELFORMATDESCRIPTOR); ppfd^.nVersion:=1; ppfd^.dwFlags:=PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER; ppfd^.dwLayerMask:=PFD_MAIN_PLANE; ppfd^.iPixelType:=PFD_TYPE_COLORINDEX; ppfd^.cColorBits:=8; ppfd^.cDepthBits:=16; ppfd^.cAccumBits:=0; ppfd^.cStencilBits:=0; npixelformat:=ChoosePixelFormat(dc, ppfd); if (nPixelformat=0) then begin MessageBox(NULL, 'choosePixelFormat failed', 'Error', MB_OK); Result:=False; Exit; end; if (SetPixelFormat(dc, npixelformat, ppfd)= FALSE) then begin MessageBox(NULL, 'SetPixelFormat failed', 'Error', MB_OK); Result:=False; Exit; end; Result:=True; Dispose(ppfd); end; 也可以向下面这样进行设置如: var pfd: PixelFormatDescriptor; nPixelFormat : Integer; begin FillChar(pfd,SizeOf(pfd),0); with pfd do begin nSize:=sizeof(pfd); nVersion:=1; dwFlags:=PFD_SUPPORT_OPENGL or PFD_DRAW_TO_BITMAP or PFD_DOUBLEBUFFER; iPixelType:=PFD_TYPE_RGBA; cColorBits:=32; cDepthBits:=32; iLayerType:=Byte(PFD_MAIN_PLANE); end; nPixelFormat:=ChoosePixelFormat(DC,@pfd); SetPixelFormat(DC,nPixelFormat,@pfd); { // 使用DescribePixelFormat检查象素格式是否设置正确 DescribePixelFormat(DC,nPixelFormat,SizeOf(pfd),@pfd); if (pfd.dwFlags and PFD_NEED_PALETTE) 0 then SetupPalette(DC,pfd); //SetupPalette是自定义函数 }end; ---- 上述工作完成以后,最好先运行一遍,并检查nPixelFormat的值。正常的话,该值应该是大于0的,否则就有问题。同样的代码,我在NT机器上能够得到正确的大于0的值而在PWIN97或98的机器上得不到正确值,但是编译时不会有问题,而且NT上编译后在PWIN97机器上也能够正确运行。现在可以创建着色描述表(RC)了。调用函数wglCreateContext、wglMakeCurrent,如下例示: RC:HGLRC; RC:=wglCreateContext(DC); wglMakeCurrent(DC,RC); 在程序结束之前,要记得释放所占用的资源。 wglMakeCurrent(0,0); if RCnull then wglDeleteContext(RC); if ghDCnull then ReleaseDC(Handle,DC); ---- 以下的代码是从C++Builder 4中OpenGL的例子改写过来的。编译后的程序大小为300K左右,而在C++Builder 4下编译后程序的大小为384K。 ---- 程序代码 Zip 3KB ---- 程序中的OpenGL函数及象素格式在Delphi中的MSHelp中有比较详细的解释,本文不敢多做解释。 § 一、OPENGL的功能 OPENGL原来是工作站上的一个图形软件库,由于它在商业、军事、医学、航天航空等领域的广泛应用,目前在低档电脑也可以开发出符合用户要求的图形。OPENGL不仅可以绘制基本图像,而且提供了大量处理图形图像的函数与过程 1、图形变换 是图形显示与制作的基础,动画设计和动画显示都离不开图形的变换,图形变换在数学上是由矩形的乘法来实现的,变换一般包括平移、旋转和缩放。按图形的显示性质来分:视点变换、模型变换、投影变换、剪裁变换和视口变换等。 2、光照效果 不发光的物体的颜色是由物体反射外界光所形成的,这是光照。在三维图形中,如果光照使用不当,三维图形就会失去真实的立体感,OPENGL把光照分为:辐射光、环境光、散射光、反射光等。 3、纹理映射 通过纹理映射可以在三维表面添加显示现实世界中的纹理。如:一个矩形它不能表示真实世界中的物体,如果填上"本质"纹理,就逼真了。 4、图形特效 混合函数、反走样函数和雾函数,可以处理三维图形听之任之物体的透明和半透明、使用线段理加光滑以及提供雾化的效果。 5、图像特效 处理位图的基本函数:图像绘制、图像拷贝和存储、映射和转移、图像的缩放等。位图操作函数可以人绘图原的低层说明中文字符的形成过程。 § 二、创建OPENGL应用程序 1、一般原则 A 有uses中添加OPENGL支持单元:OpenGL; B 在窗体的OnCreate事件过程中初始化OPENGL; C 在窗口的OnPaing 事件过程中初始化OPENGL; D 在窗口的OnResize事件过程中初始化OPENGL; E 在窗口的OnDestroy 事件过程中初始化 OPENGL; 2、简单实例 A 创建一个工程FILE->New Application B 在OnCreate事件中添加代码: procedure TfrmMain.FormCreate(Sender: TObject); var pfd:TPixelFormatDescriptor; //设置描述表 PixelFormat:Integer; begin ControlStyle:=ControlStyle+[csOpaque]; FillChar(pfd,sizeof(pfd),0); with pfd do begin nSize:=sizeof(TPixelFormatDescriptor); nVersion:=1; dwFlags:=PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER; iPixelType:=PFD_TYPE_RGBA; cColorBits:=24; cDepthBits:=32; iLayerType:=PFD_MAIN_PLANE; end; PixelFormat:=ChoosePixelFormat(Canvas.Handle,@pfd); SetPixelFormat(Canvas.Handle,PixelFormat,@pfd); hrc:=wglCreateContext(Canvas.Handle); w:=ClientWidth; h:=ClientHeight; end; C 在OnDestroy事件中的代码 procedure TfrmMain.FormDestroy(Sender: TObject); begin wglDeleteContext(hrc); end; D 在OnPaint事件中的代码 procedure TfrmMain.FormPaint(Sender: TObject); begin wglMakeCurrent(Canvas.Handle,hrc); glClearColor(1,1,1,1); glColor3f(1,0,0); glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); MyDraw; glFlush; SwapBuffers(Canvas.Handle); end; E 在OnResize事件中的代码 procedure TfrmMain.FormResize(Sender: TObject); begin glMatrixMode(GL_PROJECTION); glLoadIdentity; glFrustum(-1.0,1.0,-1.0,1.0,3.0,7.0); glViewPort(0,0,ClientWidth,ClientHeight); MyDraw; end; F 在MyDraw函数中的代码(用户在窗口类中声明) procedure TfrmMain.MyDraw; begin glPushMatrix; Sphere:=gluNewQuadric; gluQuadricDrawStyle(Sphere,GLU_LINE); gluSphere(Sphere,0.5,25,25); glPopMatrix; SwapBuffers(Canvas.handle); gluDeleteQuadric(Sphere); end; 附本程序原码: unit MainFrm; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, OpenGL; type TfrmMain = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormPaint(Sender: TObject); procedure FormResize(Sender: TObject); private { Private declarations } hrc:HGLRC; w,h:glFloat; Sphere:GLUquadricObj; public { Public declarations } procedure MyDraw; end; var frmMain: TfrmMain; implementation {$R *.dfm} procedure TfrmMain.FormCreate(Sender: TObject); var pfd:TPixelFormatDescriptor; PixelFormat:Integer; begin ControlStyle:=ControlStyle+[csOpaque]; FillChar(pfd,sizeof(pfd),0); with pfd do begin nSize:=sizeof(TPixelFormatDescriptor); nVersion:=1; dwFlags:=PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER; iPixelType:=PFD_TYPE_RGBA; cColorBits:=24; cDepthBits:=32; iLayerType:=PFD_MAIN_PLANE; end; PixelFormat:=ChoosePixelFormat(Canvas.Handle,@pfd); SetPixelFormat(Canvas.Handle,PixelFormat,@pfd); hrc:=wglCreateContext(Canvas.Handle); w:=ClientWidth; h:=ClientHeight; end; procedure TfrmMain.FormDestroy(Sender: TObject); begin wglDeleteContext(hrc); end; procedure TfrmMain.FormPaint(Sender: TObject); begin wglMakeCurrent(Canvas.Handle,hrc); glClearColor(1,1,1,1); glColor3f(1,0,0); glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); MyDraw; glFlush; SwapBuffers(Canvas.Handle); end; procedure TfrmMain.MyDraw; begin glPushMatrix; Sphere:=gluNewQuadric; gluQuadricDrawStyle(Sphere,GLU_LINE); gluSphere(Sphere,0.5,25,25); glPopMatrix; SwapBuffers(Canvas.handle); gluDeleteQuadric(Sphere); end; procedure TfrmMain.FormResize(Sender: TObject); begin glMatrixMode(GL_PROJECTION); glLoadIdentity; glFrustum(-1.0,1.0,-1.0,1.0,3.0,7.0); glViewPort(0,0,ClientWidth,ClientHeight); MyDraw; end; end. § 三、OPENGL变量和函数的约定 1、OPENGL的库约定 它共三个库:基本库、实用库、辅助库。在DELPHI中,基本库由OpenGL单元实现,在Windows环境中,一般不使用辅助库。 2、OPENGL常数约定 OPENGL常数均使用大写字母,以"GL"开头,词汇之间使用下划线分隔,如:GL_LINES,表示使用基本库绘制直线。 3、OPENGL函数的命名约定 A 第一部分以gl或wgl开头,如glColor3f中的gl。 B 第二部分是用英文表示的函数功能,单词的首字母大写出。 C 第三部分是数字,表示函数的参数。 D 第四部分是小写字母,表示函数的类型。 b 9位整数 s 16位整数 i 32位整数 f 32位浮点数 d 64位浮点数 ub 9位无符号整数 例:glVertex2f(37,40); {两个32位的浮点数作参数} glVertex3d(37,40,5); {三个64位的浮点数作参数} p[1..3]:array of glFloat; glVertes3fv(p); {3f表示三个浮点数,v表示调用一个数组作为顶点坐标输入} § 四、OPENGL的初始化 1、PIXELFORMATDESCRIPTOR结构 主要描述像素点的性质,如像素的颜色模式和红、绿、蓝颜色构成方式等。 tagPIXELFORMATDESCRIPTOR = packed record nSize: Word; nVersion: Word; dwFlags: DWORD; iPixelType: Byte; cColorBits: Byte; cRedBits: Byte; cRedShift: Byte; cGreenBits: Byte; cGreenShift: Byte; cBlueBits: Byte; cBlueShift: Byte; cAlphaBits: Byte; cAlphaShift: Byte; cAccumBits: Byte; cAccumRedBits: Byte; cAccumGreenBits: Byte; cAccumBlueBits: Byte; cAccumAlphaBits: Byte; cDepthBits: Byte; cStencilBits: Byte; cAuxBuffers: Byte; iLayerType: Byte; bReserved: Byte; dwLayerMask: DWORD; dwVisibleMask: DWORD; dwDamageMask: DWORD; end; TPixelFormatDescriptor = tagPIXELFORMATDESCRIPTOR; dwFlags代表点格式的属性: PFD_DRAW_TO_WINDOW 图形绘在屏幕或设备表面 PFD_DRAW_TO_BITMAP 在内存中绘制位图 PFD_SUPPORT_GDI 支持GDI绘图 PFD_SUPPORT_OPENGL 支持OPENGL函数 PFD_DOUBLEBUFFER 使用双缓存 PFD_STEREO 立体缓存 PFD_NEED_PALLETTE 使用RGBA调色板 PFD_GENERIC_FORMAT 选择GDI支持的格式绘图 PFD_NEED_SYSTEM_PALETTE 使用OPENGL支持的硬件调色板 iPixelType设置像素颜色模式:PFD_TYPE_RGBA或PFD_TYPE_INDEX.。 cColorBits设置颜色的位,如是9表示有256种颜色表示点的颜色。 cRedBits、cGreenBits、cBlueBits 使用RGBA时,三原色所使用的位数。 cRedShitfs、cGreenShifts、cBlueShifts 使用RGBA时,三原色可以调节的位数。 cAlphaBits、cAlphaShifts 使用RGBA时,Alpha使用的位数与可调节的位数。 cAccumBits设置累积缓存区的位面总数。 cAccumRedBits、cAccumGreenBits、cAccumBlueBits设置累积缓存区的三原色位面总数。 cAccumAlphaBits设置累积缓存区的Alpha位面总数。 cDepthBits设置浓度缓存的深度。 cStencilBits设置Stencil缓存的深度。 cAuxBuffers指辅助缓存的大小。 iLayerType指定层的类型。 bReserved不使用,必须是零。 dwLayerMask指定覆盖层的屏蔽。 dwDamageMask设置在相同的框架缓存下是否共用同一种像素模式。 2、OPENGL的初始化步骤 A 使用Canvas.Handle获得窗口句柄。 B 创建一个TPixelFormatDescriptor变量定义像素格式。 C 使用ChoosePixelFormat函数选择像素格式。 D 使用SetPixelFormat函数使用像素格式生效。 E 使用wglCreateContext函数建立翻译描述表。 F 使用wglMakeCurrent函数把建立的翻译描述表作为当前翻译描述表。 3、资源释放 A 使用wglDeleteContext过程删除像素描述表。 B 使用ReleaseDC过程释放窗口内存。 在窗口的OnDestroy事件中: begin if hrcnull then wglDeleteCurrent(hrc); if hdcnull then ReleaseDC(Handle,hdc); end; § 五、OPENGL基本图形的绘制 1、图形的颜色 注意底色的设置,颜色设置通常与像素描述变量有关,即与TPixelFormatDescriptor定义中的iPixelType成员有关。 iPixelType:=PFD_TYPE_COLORINDEX; 则只能使用glIndexd,glIndexf,glIndexi,glIndexs,glIndexv,glIndexfv,glIndexiv,glIndexsv过程设置图形颜色。 iPixelType:=PFD_TYPE_RGBA; 则只能使用 glColor3b,glColor3f,glColor4b,glColor4f,glColor4fv设置图形颜色。 A 图形底色:屏幕与窗口的颜色,即颜色缓冲区的颜色。改变图形底色首先应使用glClearColor过程设定底色,然后使用glClear过程以这种底色刷新窗口和屏幕。 procedure glClearColor(red:GLClampf,green:GLClampf,blue:GLClampf,alpha:GLClampf); procedure glClear(mask:GLBitField); red,green,blue,alpha是准备设置的底色,它们的取值是0到1。mask是刷新底色的方式。 例:将绘声绘色图窗口设置为绿色 glClearColor(0,1,0,1); glClear(GL_COLOR_BUFFER_BIT); mask的取值和意义: GL_COLOR_BUFFER_BIT 设置当前的颜色缓冲 GL_DEPTH_BUFFER_BIT 设置当前的深度缓冲 GL_ACCUM_BUFFER_BIT 设置当前的积累缓冲 GL_STENCIL_BUFFER_BIT 设置当前的STENCIL(模板)缓冲 绘图窗口设置为灰色 glClearColor(0.3,0.3,0.3,1); glClear(GL_COLOR_BUFFER_BIT); B 图形颜色 使用glClear3f与glClear4f可以设置图形的绘制颜色。若用三个参数,则分别指设置红、蓝、绿三色光。若用四个参数,则第四个表示RGBA值。 例设置当前的绘图颜色为蓝色: glColor3f(0,0,1); 设置绘图颜色为白色: glColor3f(1,1,1); 2、简单图形的绘制 在glBegin与glEnd过程之间绘制简单图形,如点、线、多边形等。 glBegin(mode:GLenum);{绘制过程}glEnd; mode的取值: GL_POINTS 画多个点 GL_LINES 画多条线,每两点绘制一条直线 GL_LINE_STRIP 绘制折线 GL_LINE_LOOP 绘制首尾相接的封闭多边形 GL_TRIANGLES 绘制三角形 GL_TRIANGLE_STRIP 绘制三边形,每三个点绘制绘制一个三边形 GL_TRIANGLE_FAN 绘制三角形 GL_QUADS 绘制四边形 GL_QUAD_STRIP 绘制四边条,每四点绘制一个四边条 GL_POLYGON 绘制多边形 例绘制三个点: begin glPushMatrix; glBegin(GL_POINT); glVertex2f(0.1,0.1); glVertex2f(0.5,0.5); glVertex2f(0.1,0.3); glEnd; SwapBuffers(Canvas.Handle); end; 如果将GL_POINT改为GL_LINES,则将画一条线.第三个点无效.在glVertex2f之前执行glColor3f(0,0,1)则将线条的颜色改为绿色. 如果将GL_LINES改为GL_LINE_STRIP则可以绘制两条直线. 使用glPointSize过程可以设置点的大小;使用glLineWidth过程可以设置线的宽度. 使用glLineStipple过程设置点划线的样板,使用glEnable(GL_LINE_STIPPLE)过程和对应参数使绘图能够绘制点划线.glDisable(GL_LINE_STIPPLE)过程和对应参数关闭点划线. procedure glLineStipple(factor:GLint,pattern:GLushort); 参数factor表示点划线样板Pattern的重复次数,factor取值1255,Pattern是二进制序列. glLineStipple(1,0,0x11C);{0x11C表示为10001110,0表示不画点,1表示画点} 例: begin glColor3f(1,0,0); glLineWidth(2); glLineStipple(1,$11C); glEnable(GL_LINE_STIPPLE); glBegin(GL_LINES); glVertex2f(-0.9,0.3); glVertex2f(0.9,0.3); glEnd; glDisable(GL_LINE_STIPPLE); glColor3f(1,0,1); glLineStipple(2,$11C); glEnable(GL_LINE_STIPPLE); glBegin(GL_LINES); glVertex2f(-0.9,0.1); glVertex2f(0.9,0.1); glEnd; glDisable(GL_LINE_STIPPLE); SwapBuffers(Canvas.Handle); end; 多边形绘制与点线相似,要改变参数为GL_POLYGON,GL_QUADS,GL_TRANGLES.在绘制时的注意事项: A 多边形的边与边只在顶点相交 B 多边形必须是凸多边形,如果是凹多边形,用户只有折成凸多边形,加快绘制速度. 例: glBegin(GL_POLYGON); glVertex2f(-0.9,0.3); glVertex2f(0.9,0.3); glVertex2f(0.9,-0.6); glVertex2f(0.5,-0.6); glVertex2f(-0.9,-0.2); glEnd; 多边形有正面与反面,与之相关的过程: glPolygonMode 控制多边形正,反面绘图模式 glFrontface 指定多边形的正面 glCullFace 显示多边形是设置消除面 glPolygonStripple 形成多边形填充的样式 3、简单二次曲面 圆柱,圆环和球都属于二次曲面. A 圆柱 gluCylinder(qobj:GLUquadricObj,baseRadius:GLdouble,topRadius:GLdouble,height:GLdouble, slices:GLint,stacks:GLint); qobj指定一个二次曲面,baseRadius为圆柱的底半径;topRadius为所绘制圆柱的上顶面半径;height为圆柱的高;slices为绕Z轴的分割线数;stacks为沿Z轴的分割线数. 如果baseRadius和topRadius不相等,则可以绘制锥台与圆锥. procedure TfrmMain.MyDraw; var qObj:GLUQuadricObj; begin glPushMatrix; glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glColor3f(1,0,0); qObj:=gluNewQuadric; gluQuadricDrawStyle(qObj,GLU_LINE); gluCylinder(qObj,0.5,0.1,0.2,10,10); end; B 圆环 gluDisk(qobj:GLUquadricObj,innerRadius:GLdouble,outerRadius:GLdouble,slices:GLint, loops:GLint); procedure TfrmMain.MyDraw; var qObj:GLUQuadricObj; begin glPushMatrix; glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glColor3f(1,0,0); qObj:=gluNewQuadric; gluQuadricDrawStyle(qObj,GLU_LINE); gluDisk(qObj,0.2,0.5,10,5); SwapBuffers(Canvas.Handle); end; C 半圆环 gluPartialDisk(qobj:GLUquadricObj,innerRadius:GLdouble,outerRadius:GLdouble,slices:GLint, loops:GLint,startAngle:GLdouble,sweepAngle:GLdouble); startAngle,sweepAngle是半圆环的起始角与终止角. procedure TfrmMain.MyDraw; var qObj:GLUQuadricObj; begin glPushMatrix; glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glColor3f(1,0,0); qObj:=gluNewQuadric; gluQuadricDrawStyle(qObj,GLU_LINE); gluPartialDisk(qObj,0.2,0.5,10,5,90,190); SwapBuffers(Canvas.Handle); end; D 球体 function gluSphere(qObj:GLUquadricObj,radius:GLdouble,slices:GLint,stacks:GLint); procedure TfrmMain.MyDraw; var qObj:GLUQuadricObj; begin glPushMatrix; glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glColor3f(1,0,0); qObj:=gluNewQuadric; gluQuadricDrawStyle(qObj,GLU_LINE); { silhouette[ silu(:)5et ]n.侧面影象, 轮廓} gluSphere(qObj,0.5,20,20); SwapBuffers(Canvas.Handle); end; E 关于二次曲面的过程 gluNewQuadric 创建一个新的二次曲面对象 gluDeleteQuadric 删除一个二次曲面对象 gluQuadricDrawStyle 指定要绘制的二次曲面类型 gluQuadricNormal 设置二次曲面的法矢量 gluQuadricOrientation 设置二次曲面是内旋还是外旋转 gluQuadricTexture 设置二次曲面是否使用纹理 F 绘制二次曲面的一般步骤 首先定义一个GLUquadricObj对象; 其次创建一个曲面对象gluNewQuadric; 再次设置二次曲面的特性(gluQuadricDrawStyle, gluQuadricTexture) 绘制二次曲面(gluCylinder,gluSphere,gluDisk, gluPartialDisk) § 六、OPENGL中的变换 变换是动画设计的基础,包括图形的平移,旋转,缩放等操作,在数学上是通过矩阵来实现的。 1 glLoadIdentity过程 能够把当前矩阵变为单位矩阵。 2 glLoadMatrix过程 能够把指定的矩阵设为当前矩阵。 procedure glLoadmatrixd(m:GLdouble); procedure glLoadmatrixf(m:GLfloat); m表示4X4矩阵,下面的代码定义并使之成为当前矩阵 M:array[1..4,1..4] of GLfloat; glLoadMatrix(@M); 3 glMultMatrix过程 能够将当前矩与指定矩阵相乘,并把结果作为当前矩. procedure glMultMatrixd(M:GLdouble); procedure glMultMatrixf(M:GLfloat); 4 glPushMatrix和glPopmatrix glPushMatrix能够把当前矩压入矩阵堆栈, glPopMatrix能够把当前矩弹出矩阵堆栈. glPushMatrix能够记忆矩阵当前位置,glPopmatrix能够返回以前所在的位置. 注:glPushMatrix与glPopMatrix必须放在glBegin与glEnd之外. 5 投影变换 A glOrtho能够创建一个正投影矩阵,把当前矩乘以该正投影矩阵,其结果作为当前矩阵. function glOrtho(left:GLdouble,right:GLdouble,bottom:GLdouble,top:GLdouble, near:GLdouble,far:GLdouble); procedure TfrmMain.FormResize(Sender: TObject); var nRange:GLfloat; begin nRange:=50.0; w:=clientWidth; h:=clientHeight; if h=0 then h:=1; glViewPort(0,0,w,h); if wnull then wglDeleteContext(hrc); end; end. 七、OPENGL的光照与纹理 都是增强三维立体效果和色彩效果的手段,光照能够增加图形的亮度和三维效果,纹理能够使用图形更加趋近现实。通过使用光照,可以将物体的外观很强列的表现出来,纹理则可以使物体显示多种多样的外观。 1 光照和光源过程及应用 A glIndex过程能够使颜色索引表中的某一种颜色成为当前颜色。 procedure glIndexd(c:GLdouble); procedure glIndexf(c:GLdouble); procedure glIndexi(c:GLdouble); procedure glIndexs(c:GLdouble); 参数C为索引值,如果使用glIndex过程,则TPiexlFormatDescriptor结构中的iPixelType成员设置为PFD_TYPE_COLORINDEX。 B glShadeModel过程 glShadeModel过程设置填充模式,取值:GL_SMOOTH. procedure glShadeModel(mode:GLenum); 注:以上两个过程只能在glBegin.....glEnd之外使用。 C glLight过程定义光源 procedure glLightf(light:GLenum,pname:GLenum,param:GLfloat); procedure glLighti(light:GLenum,pname:GLenum,param:GLfloat); 参数light定义光源,其值可取:GL_LIGHT0.....GL_LIGHTN,N值小于GL_MAX_LIGHT. 参数pname指定光源参数: GL_AMBIENT 环境光的分量强度 GL_DIFFUSE 散射光的分量强度 GL_SPECULAR 反射光的分量强度 GL_POSITION 光源位置 GL_SPOT_DIRECTION 光源的聚光方向 GL_SPOT_EXPONENT 光源的聚光指数 GL_SPOT_CUTOFF 光源的聚光方向 GL_CONSTANT_ATTENUATION 光常数衰退因子 GL_LINEAR_ATTENUATION 光二次衰减因子 启用和关闭光源使用glEnable()与glDisable()过程 glEnable(GL_LIGHTING); //启用光源 glDisable(GL_LIGHTING); //关闭光源 glEnable(GL_LIGHT0); //启用第0个光源 glDisable(GL_LIGHT0); //关闭第0个光源 设置光源的实例: var sdirection:Array[1..4] of GLfloat:={0.0,1.0,0.0,0.0}; glLightfv(GL_LIGHT0,GL_SPOT_CUTOFF,60); glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,sdirection); 2 材质和光照模型 A glMaterial过程设置材质参数 procedure glMaterialf(face:GLenum,pname :GLenum,param:GLfloat); procedure glMateriali(face:GLenum,pname :GLenum,param:GLfloat); procedure glMaterialfv(face:GLenum,pname :GLenum,param:GLfloat); procedure glMaterialiv(face:GLenum,pname :GLenum,param:GLfloat); 参数face指定物体表面,它的取值:GL_FRONT,GL_BACK,GL_FRONT_BACK. pname,param本资料没作介绍. B glLightModel过程 procedure glLightModelf(pname:GLenum,param:GLfloat); 参数pname为光源模型参数,可以取值GL_LIGHT_MODEL_AMBIENT, GL_LIGHT_MODEL_LOCAL_VIEWER,GL_LIGHT_MODEL_TWO_SIDE. 实例代码: procedure TfrmMain.SetLighting; var MaterialAmbient:array[1..4] of GLfloat; MaterialDiffuse:Array[1..4] of GLfloat; MaterialSpecular:Array[1..4] of GLfloat; AmbientLightPosition:Array[1..4] of GLfloat; LightAmbient:Array[1..4] of GLfloat; MaterialShininess:GLfloat; begin MaterialAmbient[1]:=0.5; MaterialAmbient[2]:=0.8; MaterialAmbient[1]:=0.2; MaterialAmbient[1]:=1.0; MaterialDiffuse[1]:=0.4; MaterialDiffuse[2]:=0.8; MaterialDiffuse[3]:=0.1; MaterialDiffuse[4]:=1.0; MaterialSpecular[1]:=1.0; MaterialSpecular[2]:=0.5; MaterialSpecular[3]:=0.1; MaterialSpecular[4]:=1.0; materialShininess:=50.0; AmbientLightPosition[1]:=0.5; AmbientLightPosition[2]:=1.0; AmbientLightPosition[3]:=1.0; AmbientLightPosition[4]:=0.0; LightAmbient[1]:=0.5; LightAmbient[2]:=0.2; LightAmbient[3]:=0.8; LightAmbient[4]:=1.0; glMaterialfv(GL_FRONT,GL_AMBIENT,@MaterialAmbient); glMaterialfv(GL_FRONT,GL_DIFFUSE,@MaterialDiffuse); glMaterialfv(GL_FRONT,GL_SPECULAR,@MaterialSpecular); glMaterialfv(GL_FRONT,GL_SHININESS,@MaterialShininess); glLightfv(GL_LIGHT0,GL_POSITION,@AmbientLightPosition); glLightModelfv(GL_LIGHT_MODEL_AMBIENT,@LightAmbient); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); GLShadeModel(GL_SMOOTH); end; 3 纹理的应用 A glTexImage1D定义一维纹理映射. procedure glTexImage1D(target:GLenum,level:GLint,components:GLint,width:GLsizei, border:GLint,format:GLenum,type:GLenum,pixels:GLvoid); 参数targer值为GL_TEXTURE_1D,定义为纹理映射,level为多级分辨率的纹理图像的等级,width为纹理宽,值为2n,n取值为32,64,129等.border为纹理的边界,其值为0或1,Pixel为纹理在内存中的位置.Component指定RGBA的混合和调整: 1 选择B成分 2 选择B,A成分 3 选择R,G,B成分 4 选择R,G,B,A成分 B glTexImage2D定义二维纹理映射 procedure glTexImage2D(target:GLenum,level:GLint,components:GLint,width:GLsizei, border:GLint,format:GLenum,type:GLenum,pixels:GLvoid); 若参数target为GL_TEXTURE_2D,意义为二维纹理映射,height为纹理的高,函数中的其它参数与glTexImage1D相同.component参数取值同上. 实例代码: procedure TfrmMain.SetTextures; var bits:Array[1..64,1..64,1..64] of GLubyte; bmp:TBitmap; i,j:Integer; begin bmp:=TBitmap.Create; bmp.LoadFromFile('d:dsoft11191logon.bmp'); for i:=1 to 64 do for j:=1 to 64 do begin bits[i,j,1]:=GLbyte(GetRValue(bmp.Canvas.Pixels[i,j])); bits[i,j,2]:=GLbyte(GetRValue(bmp.Canvas.Pixels[i,j])); bits[i,j,3]:=GLbyte(GetRValue(bmp.Canvas.Pixels[i,j])); bits[i,j,4]:=255; end; {0代表为单色着色水平,GL_RGBA表示混合值 64X64代表纹理的高和宽,0表示无边界, GL_RGBA代表纹理类型,GL_UNSIGNED_TYPE代表数据类型,@代对象地址} glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,64,64,0,GL_RGBA, GL_UNSIGNED_BYTE,@bits); glEnable(GL_TEXTURE_2D); end; C glTexParameter过程设置纹理参数 procedure glTexParameterf(target:GLenum,pname:GLenum,param:GLfloat); procedure glTexParameteri(target:GLenum,pname:GLenum,param:GLfloat); 参数target代表GL_TEXTURE_1D或GL_TEXTURE_2D,param为纹理值. D glTexEnv函数设置纹理的环境参数 function glTexEnvf(target:GLenum,pname:GLenum,param:GLfloat); function glTexEnvi(target:GLenum,pname:GLenum,param:GLfloat); 参数target为GL_TEXTURE_ENV, 参数pname为纹理参数值,取值为GL_TEXTURE_ENV_MODE 参数param为环境值,取值为GL_MODULATE,GL_DECAL和GL_BLEND. 本程序示例代码: unit MainFrm; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, OpenGL, ExtCtrls; type TfrmMain = class(TForm) Timer1: TTimer; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormPaint(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormResize(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } hrc:HGLRC; w,h:Integer; latitude,longitude:GLfloat; radius:GLdouble; public { Public declarations } procedure SetLighting; procedure SetTextures; procedure MyDraw; procedure InitializeGL(var width:GLsizei;height:GLsizei); end; var frmMain: TfrmMain; implementation {$R *.dfm} procedure TfrmMain.FormCreate(Sender: TObject); var pfd:TPixelFormatDescriptor; PixelFormat:Integer; begin ControlStyle:=ControlStyle+[csOpaque]; FillChar(pfd,sizeof(pfd),0); with pfd do begin nSize:=sizeof(TPixelFormatDescriptor); nVersion:=1; dwFlags:=PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER; iPixelType:=PFD_TYPE_RGBA; cColorBits:=24; cDepthBits:=32; iLayerType:=PFD_MAIN_PLANE; end; PixelFormat:=ChoosePixelFormat(Canvas.Handle,@pfd); SetPixelFormat(Canvas.Handle,PixelFormat,@pfd); hrc:=wglCreateContext(Canvas.Handle); w:=ClientRect.Right; h:=ClientRect.Bottom; InitializeGL(w,h); end; procedure TfrmMain.FormDestroy(Sender: TObject); begin wglDeleteContext(hrc); end; procedure TfrmMain.FormPaint(Sender: TObject); begin wglMakeCurrent(Canvas.Handle,hrc); glClearColor(1,1,1,1); glColor3f(1,0,0); glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); SetTextures; MyDraw; SetLighting; glFlush; end; procedure TfrmMain.MyDraw; var qObj:GLUQuadricObj; begin glPushMatrix; glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glColor3f(1,0,0); glRotated(0.5,0.0,1.0,0.0); glRotated(-latitude,1.0,0.0,0.0); glrotated(longitude,0.0,0.0,1.0); qObj:=gluNewQuadric; gluQuadricDrawStyle(qObj,GLU_LINE); gluSphere(qObj,0.5,20,20); SwapBuffers(Canvas.Handle); SetLighting; SetTextures; end; {procedure TfrmMain.FormResize(Sender: TObject); var nRange:GLfloat; begin nRange:=50.0; w:=clientWidth; h:=clientHeight; if h=0 then h:=1; glViewPort(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity; if wnull then wglDeleteContext(hrc); end; procedure TfrmMain.SetLighting; var MaterialAmbient:array[1..4] of GLfloat; MaterialDiffuse:Array[1..4] of GLfloat; MaterialSpecular:Array[1..4] of GLfloat; AmbientLightPosition:Array[1..4] of GLfloat; LightAmbient:Array[1..4] of GLfloat; MaterialShininess:GLfloat; begin MaterialAmbient[1]:=0.5; MaterialAmbient[2]:=0.8; MaterialAmbient[1]:=0.2; MaterialAmbient[1]:=1.0; MaterialDiffuse[1]:=0.4; MaterialDiffuse[2]:=0.8; MaterialDiffuse[3]:=0.1; MaterialDiffuse[4]:=1.0; MaterialSpecular[1]:=1.0; MaterialSpecular[2]:=0.5; MaterialSpecular[3]:=0.1; MaterialSpecular[4]:=1.0; materialShininess:=50.0; AmbientLightPosition[1]:=0.5; AmbientLightPosition[2]:=1.0; AmbientLightPosition[3]:=1.0; AmbientLightPosition[4]:=0.0; LightAmbient[1]:=0.5; LightAmbient[2]:=0.2; LightAmbient[3]:=0.8; LightAmbient[4]:=1.0; glMaterialfv(GL_FRONT,GL_AMBIENT,@MaterialAmbient); glMaterialfv(GL_FRONT,GL_DIFFUSE,@MaterialDiffuse); glMaterialfv(GL_FRONT,GL_SPECULAR,@MaterialSpecular); glMaterialfv(GL_FRONT,GL_SHININESS,@MaterialShininess); glLightfv(GL_LIGHT0,GL_POSITION,@AmbientLightPosition); glLightModelfv(GL_LIGHT_MODEL_AMBIENT,@LightAmbient); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); GLShadeModel(GL_SMOOTH); end; procedure TfrmMain.SetTextures; var bits:Array[1..64,1..64,1..64] of GLubyte; bmp:TBitmap; i,j:Integer; begin bmp:=TBitmap.Create; bmp.LoadFromFile('d:dsoft11192logon.bmp'); for i:=1 to 64 do for j:=1 to 64 do begin bits[i,j,1]:=GLbyte(GetRValue(bmp.Canvas.Pixels[i,j])); bits[i,j,2]:=GLbyte(GetRValue(bmp.Canvas.Pixels[i,j])); bits[i,j,3]:=GLbyte(GetRValue(bmp.Canvas.Pixels[i,j])); bits[i,j,4]:=255; end; glPixelStorei(GL_UNPACK_ALIGNMENT,4); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); {0代表为单色着色水平,GL_RGBA表示混合值 64X64代表纹理的高和宽,0表示无边界, GL_RGBA代表纹理类型,GL_UNSIGNED_TYPE代表数据类型,@代对象地址} glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,64,64,0,GL_RGBA, GL_UNSIGNED_BYTE,@bits); glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL); end; end. § 参考资料 |
随便看 |
百科全书收录594082条中文百科知识,基本涵盖了大多数领域的百科知识,是一部内容开放、自由的电子版百科全书。