首页 OpenGL介绍和使用

OpenGL介绍和使用

举报
开通vip

OpenGL介绍和使用 第一章 OpenGL介绍 OpenGL 是近几年发展起来的一个性能卓越的三维图形标准,它是在 SGI 等多家世界闻名的计 算机公司的倡导下,以 SGI的 GL三维图形库为基础制定的一个通用共享的开放式三维图形标准。 目前,包括Microsoft、SGI、IBM、DEC、SUN、HP等大公司都采用了 OpenGL做为三维图形标准, 许多软件厂商也纷纷以 OpenGL 为基础开发出自己的产品,其中比较著名的产品包括动画制作软件 Soft Image 和 3D Studio MAX、仿真软件 Open Invent...

OpenGL介绍和使用
第一章 OpenGL介绍 OpenGL 是近几年发展起来的一个性能卓越的三维图形标准,它是在 SGI 等多家世界闻名的计 算机公司的倡导下,以 SGI的 GL三维图形库为基础制定的一个通用共享的开放式三维图形标准。 目前,包括Microsoft、SGI、IBM、DEC、SUN、HP等大公司都采用了 OpenGL做为三维图形标准, 许多软件厂商也纷纷以 OpenGL 为基础开发出自己的产品,其中比较著名的产品包括动画制作软件 Soft Image 和 3D Studio MAX、仿真软件 Open Inventor、VR 软件 World Tool Kit、CAM 软件 ProEngineer、GIS软 ARC/INFO等等。 第一节 OpenGL特点及功能 OpenGL实际上是一个开放的三维图形软件包,它独立于窗口系统和操作系统,以它为基础开发 的应用程序可以十分方便地在各种平台间移植;OpenGL可以与 Visual C++紧密接口,可保证算法的 正确性和可靠性;OpenGL使用简便,效率高。它具有七大功能: 1. 建模 OpenGL图形库除了提供基本的点、线、多边形的绘制函数外,还提供了复杂的三维物体(球、 锥、多面体、茶壶等)以及复杂曲线和曲面(如 Bezier、Nurbs等曲线或曲面)绘制函数。 2. 变换 OpenGL图形库的变换包括基本变换和投影变换。基本变换有平移、旋转、变比镜像四种变换, 投影变换有平行投影(又称正射投影)和透视投影两种变换。其变换方法与机器人运动学中的坐标 变换方法完全一致,有利于减少算法的运行时间,提高三维图形的显示速度。 3. 颜色模式设置 OpenGL颜色模式有两种,即 RGBA模式和颜色索引(Color Index)。 4. 光照和材质设置 OpenGL 光有辐射光(Emitted Light)、环境光(Ambient Light)、漫反射光(Diffuse Light)和镜面光 (Specular Light)。材质是用光反射率来 关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf 示。场景(Scene)中物体最终反映到人眼的颜色是光的红绿蓝 分量与材质红绿蓝分量的反射率相乘后形成的颜色。 5. 纹理映射(Texture Mapping) 利用 OpenGL纹理映射功能可以十分逼真地表达物体表面细节。 6. 位图显示和图象增强 图象功能除了基本的拷贝和像素读写外,还提供融合(Blending)、反走样(Antialiasing)和雾(fog) 的特殊图象效果处理。以上三条可是被仿真物更具真实感,增强图形显示的效果。 7. 双缓存(Double Buffering)动画 双缓存即前台缓存和后台缓存,简而言之,后台缓存计算场景、生成画面,前台缓存显示后台 缓存已画好的画面。此外,利用 OpenGL还能实现深度暗示(Depth Cue)、运动模糊(Motion Blur)等特 殊效果。从而实现了消隐算法。 第二节 OpenGL的图形库 OpenGL图形库一共有 100多个函数。其中核心函数有 115个,它们是最基本的函数,其前缀是 gl,OpenGL实用库(OpenGL utility library ,GLU)的函数功能更高一些,如绘制复杂的曲线曲面、高 级坐标变换、多边形分割等,共有43个,前缀为glu;OpenGL辅助库(OpenGL auxiliary library ,GLAUX) 的函数是一些特殊的函数,包括简单的窗口管理、输入事件处理、某些复杂三维物体绘制等函数, 共有 31个,前缀为 aux。 此外,还有六个 WGL函数非常重要,专门用于 OpenGL和 Windows 窗口系统的联接,其前缀 为 wgl,主要用于创建和选择图形操作描述表(rendering contexts)以及在窗口内任一位置显示字符位 图。 另外,还有五个Win32函数用来处理像素格式(pixel formats)和双缓存。由于它们是对Win32系 统的扩展,因此不能应用在其它 OpenGL平台上。 第二章 VC++6.0中使用 OpenGL OpenGL for Windows 的设计与 OpenGL for UNIX的程序设计有一点小区别,关键就在于如何将 OpenGL 与不同的操作系统下的窗口系统联系起来。如果调用 OpenGL 辅助库窗口管理函数,则不 用考虑这些问题。 第一节 初始化设置 1. 图形操作描述 在Windows下,窗口程序必须首先处理设备描述表(Device Contexts, DC),DC包括许多如何在 窗口上显示图形的信息,既指定画笔和刷子的颜色,设置绘图模式、调色板、映射模式以及其它图 形属性。同样,OpenGL for Windows的程序也必须使用 DC,这与其它Windows程序类似。但是, OpenGL for Windows必须处理特殊的 DC图形操作描述表,这是 DC中专为 OpenGL使用的一种。 一个OpenGL应用图形操作描述表内有OpenGL与Windows 窗口系统相关的各种信息。一个OpenGL 应用首先必须创建一个图形操作描述表,然后再启动它,最后在所定义的窗口内按常规方式调用 OpenGL函数绘制图形。 OpenGL的图形操作描述表不同于其它 DC,其它 DC调用每个 GDI函数都需要一个句柄,而图 形操作描述表方式下只需一个句柄就可以任意调用 OpenGL 函数。也就是说,只要当前启用了某个 图形操作描述表,那么在未删除图形操作描述表之前可以调用任何 OpenGL函数,进行各种操作。 2. 像素格式 在创建一个图形操作表之前,首先必须设置像素格式。像素格式含有设备绘图界面的属性,这 些属性包括绘图界面是用 RGBA模式还是颜色表模式,像素缓存是用单缓存还是双缓存,以及颜色 位数、深度缓存和模板缓存所用的位数,还有其它一些属性信息。 3. 像素格式结构 OpenGL 显示设备都支持一种指定的像素格式。一般用一个名为 PIXELFORMATDESCRIPTOR 的结构来表示某个特殊的像素格式,这个结构包含 26个属性信息。如下所示: typedef struct tagPIXELFORMATDESCRIPTOR { // pfd WORD nSize; WORD nVersion; DWORD dwFlags; BYTE 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; DWORD dwLayerMask; DWORD dwVisibleMask; DWORD dwDamageMask; } PIXELFORMATDESCRIPTOR; 4. 初始化 PIXELFORMATDESCRIPTOR结构 PIXELFORMATDESCRIPTOR 结构中每个变量值的具体含义和设置可以参考有关资料,下面举 出一个对 PIXELFORMATDESCRIPTOR 进行初始化的例子来简要说明相关变量的意义。定义 PIXELFORMATDESCRIPTOR结构的 pfd如下: PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd 1, PFD_DRAW_TO_WINDOW | // support window PFD_SUPPORT_OPENGL | // support OpenGL PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 24, // 24-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 0, // no alpha buffer 0, // shift bit ignored 0, // no accumulation buff 0, 0, 0, 0, // accum bits ignored 32, // 32-bit z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored }; 该结构前两个变量的含义十分明显。第三个变量 dwFlags 的值是 PFD_DRAW_TO_WINDOW |PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER,表明应用程序使用 OpenGL函数来绘制窗口。第 四个变量表明当前采用 RGBA 颜色模式。第五个变量采用 24 位真彩色,如果是 256 色系统则自动 实现颜色抖动。因为没有使用 alpha 缓存和累计缓存,所以从变量 cAlphaBits 到 cAccumAlphaBits 都设置为 0。深度缓存设置为 32位,这个缓存能解决三维场景的消隐问题。变量 cAuxBuffers设为 0, Windows 下不支持辅助缓存。Windows 下变量 ilayerType 只能设置为 PFD_MAIN_PLANE,但在其 它平台也许支持 PFD_MAIN_PLANE或 PFD_MAIN_UNDERLAYPLANE。接下来 bReserved变量只 能设为 0,而最后三个变量Windows都不支持,故全设置为 0。 5. 设置像素结构 初始化 PIXELFORMATDESCRIPTOR结构后,要设置像素格式。下面举例说明设置像素格式。 CClientDC clientDC(this); int PixelFormat = ChoosePixelFormat(clientDC.m_hDC,&pfd); BOOL result=SetPixelFormat(clientDC.m_hDC,PixelFormat,&pfd); 第一行语句得到一个应用窗口客户区的设置描述表。 第一行调用 ChoosePixelFormat()选择一个像素格式,并将像素格式索引号返回给 pixelFormat 变 量 ; 函 数 中 第 一 个 参 数 是 选 择 像 素 格 式 的 设 备 描 述 表 的 句 柄 , 第 二 个 参 数 是 PIXELFORMATDESCRIPTOR结构的地址。如果调用失败则返回 0;否则返回像素格式索引号。 第三行调用 SetPixelFormat()设置像素格式,三个参数分别是设备描述表的句柄、像素格式索引 号和 PIXELFORMATDESCRIPTOR结构的地址。如果调用成功则返回 TRUE,否则返回 FALSE。 6. 创建图形操作描述表 必须创建并启用图形操作描述表后,才能调用 OpenGL 函数在窗口内进行各种图形操作。一般 来说,利用 MFC 中增补的管理图形操作描述表方法来编程比较方便。即在视类(CView)的消息 OnCreat()中创建图形操作描述表。 第二节 编程实例 该实例将建立一个视窗程序,以说明 OpenGL 图形的最小需求。这一任务将分 5 步来进行:设 置窗口像素的格式;建立 RC;使 RC设为当前;创建视口和矩阵模型;画一个立方体和一个茶壶。 1. 打开 VisualC++,建立一个单文档的项目。 2. 在项目中加进所有必需的 OpenGL文件和库。在菜单中选择 BuildSettings,点击 LINK按钮, 在 Object/Library栏中键入 OpenGL32.lib; GLu32.lib; glaux.lib并确定。打开文件 stdafx.h插入如下行: #include #include #include 3. 编辑 OnPreCreate 函数,指定窗口类型。OpenGL 仅能在具有 WS_CLIPCHILDREN 和 WS_CLIPSIBLINGS类型的窗口显示图形。 BOOLCOPView :: PreCreateWindow ( CREATESTRUCT &cs ) { cs.style |= ( WS_CLIPCHILDREN | WS_CLIPSIBLINGS ) ; return CView :: PreCreateWindow ( cs ) ; } 4. 定义窗口的像素格式。首先建立一个受保护的成员函数 SetWindowPixelFormat。如下所示: BOOL COPView :: SetWindowPixelFormat ( HDC hDC ) { PIXELFORMATDESCRIPTOR pixelDesc ; pixelDesc.nSize = sizeof ( PIXELFORMATDESCRIPTOR ) ; pixelDesc.nVersion = 1 ; pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_SUPPORT_GDI | PFD_STEREO_DONTCARE ; pixelDesc.iPixelType = PFD_TYPE_RGBA ; pixelDesc.cColorBits = 32 ; pixelDesc.cRedBits = 8 ; pixelDesc.cRedShift = 16 ; pixelDesc.cGreenBits = 8 ; pixelDesc.cGreenShift = 8 ; pixelDesc.cBlueBits = 8 ; pixelDesc.cBlueShift = 0 ; pixelDesc.cAlphaBits = 0 ; pixelDesc.cAlphaShift = 0 ; pixelDesc.cAccumBits = 64 ; pixelDesc.cAccumRedBits = 16 ; pixelDesc.cAccumGreenBits = 16 ; pixelDesc.cAccumBlueBits = 16 ; pixelDesc.cAccumAlphaBits = 0 ; pixelDesc.cDepthBits = 32 ; pixelDesc.cStencilBits = 8 ; pixelDesc.cAuxBuffers = 0 ; pixelDesc.iLayerType = PFD_MAIN_PLANE ; pixelDesc.bReserved = 0 ; pixelDesc.dwLayerMask = 0 ; pixelDesc.dwVisibleMask = 0 ; pixelDesc.dwDamageMask = 0 ; m_GLPixelIndex = ChoosePixelFormat( hDC , &pixelDesc ) ; if ( m_GLPixelIndex == 0 ) { return FALSE ; } if ( SetPixelFormat ( hDC , m_GLPixelIndex , &pixelDesc) == FALSE ) { return FALSE ; } return TRUE; } 5. 加入一个成员变量到视类中: int m_GLPixelIndex ; //protected 6. 在 ClassWizard中加入函数 OnCreate来响应消息WM_CREATE,函数如下: int COPView :: OnCreate ( LPCREATESTRUCT lpCreateStruct ) { if ( CView :: OnCreate ( lpCreateStruct ) == -1 ) return -1 ; HWND hWnd = GetSafeHwnd ( ) ; HDC hDC = :: GetDC ( hWnd ) ; if ( SetWindowPixelFormat ( hDC ) == FALSE ) return 0 ; if ( CreateViewGLContext ( hDC ) == FALSE ) return 0 ; return 0 ; } 7. 建立 RC,并置为当前 RC。在视类中加入保护函数 CreateViewGLContext ( HDC hDC )和变量 HGLRC m_hGLContext。 BOOL COPView :: CreateViewGLContext (HDC hDC) { m_hGLContext = wglCreateContext ( hDC ) ; if ( m_hGLContext == NULL ) { return FALSE ; } if ( wglMakeCurrent ( hDC , m_hGLContext ) == FALSE ) { return FALSE ; } return TRUE ; } 8. 加入函数 OnDestroy来响应WM_DESTROY: voidCOPView :: OnDestroy ( ) { if ( wglGetCurrentContext ( ) != NULL ) { wglMakeCurrent ( NULL , NULL ) ; } if ( m_hGLContext != NULL ) { wglDeleteContext ( m_hGLContext ) ; m_hGLContext = NULL ; } CView :: OnDestroy( ) ; } 9. 编辑 COPView类构造函数: COPView::COPView() { m_hGLContext = NULL ; m_GLPixelIndex = 0 ; } 10. 建立视点和矩阵模型。用 ClassWizard在视类中加入函数 OnSize响应WM_SIZE。 void COPView :: OnSize ( UINT nType , int cx , int cy ) { CView :: OnSize ( nType , cx , cy ) ; GLsizei width , height ; GLdouble aspect; width = cx ; height = cy ; if ( cy == 0 ) aspect = ( GLdouble ) width ; else aspect = ( GLdouble ) width / ( GLdouble ) height ; glViewport ( 0 , 0 , width , height ) ; glMatrixMode ( GL_PROJECTION ) ; glLoadIdentity ( ) ; gluPerspective ( 45 , aspect , 1 , 10.0 ) ; glMatrixMode ( GL_MODELVIEW ) ; glLoadIdentity ( ) ; } 11. 加入函数 OnPaint: void COPView :: OnPaint ( ) { CPaintDC dc ( this ) ; COPDoc *pDoc = GetDocument ( ) ; pDoc -> RenderScene ( ) ; } 12. 在文档类中加入公共函数 RenderScene(): void COPDoc :: RenderScene ( void ) { glClear( GL_COLOR_BUFFER_BIT ) ; glFlush ( ) ; } 13. 在文档类中加一个枚举变量 GLDisplayListNames: enum GLDisplayListNames {ArmPart1 , ArmPart2 } ; 为将来建立显示列表用。 14. 编辑函数 OnNewDocument ( ): BOOL COPDoc :: OnNewDocument ( ) { if( ! CDocument :: OnNewDocument ( ) ) return FALSE ; glNewList ( ArmPart1 , GL_COMPILE ) ; GLfloat RedSurface [ ] = { 1.0f , 0.0f , 0.0f , 1.0f } ; GLfloat GreenSurface [ ] = { 0.0f , 1.0f , 0.0f , 1.0f } ; GLfloat BlueSurface [ ] = {0.0f , 0.0f , 1.0f , 1.0f } ; GLfloat LightAmbient [ ] = { 0.1f , 0.1f , 0.1f , 0.1f } ; GLfloat LightDiffuse [ ] = { 0.7f , 0.7f , 0.7f , 0.7f } ; GLfloat LightSpecular [ ] = { 0.0f , 0.0f , 0.0f , 0.1f } ; GLfloat LightPosition [ ] = { 5.0f , 5.0f , 5.0f , 0.0f } ; glLightfv ( GL_LIGHT0 , GL_AMBIENT , LightAmbient ) ; glLightfv ( GL_LIGHT0 , GL_DIFFUSE , LightDiffuse ) ; glLightfv ( GL_LIGHT0 , GL_SPECULAR , LightSpecular ) ; glLightfv( GL_LIGHT0 , GL_POSITION , LightPosition ) ; glEnable ( GL_LIGHT0 ) ; glMaterialfv ( GL_FRONT_AND_BACK , GL_AMBIENT , RedSurface ) ; glBegin ( GL_POLYGON ) ; glNormal3d ( 1.0 , 0.0 , 0.0 ) ; glVertex3d ( 1.0 , 1.0 , 1.0 ) ; glVertex3d ( 1.0 , -1.0 , 1.0 ) ; glVertex3d ( 1.0 , -1.0 , -1.0 ) ; glVertex3d ( 1.0 , 1.0 , -1.0 ) ; //画第一个面 glEnd ( ) ; glBegin ( GL_POLYGON ) ; glNormal3d ( -1.0 , 0.0 , 0.0 ) ; 此处同上画第二个面。 立方体的中心为坐标原点。 glEnd ( ) ; glMaterialfv ( GL_FRONT_AND_BACK , GL_AMBIENT , GreenSurface ) ; 此处同上画第三、四个面,注意平面法向和坐标。 glMaterialfv (GL_FRONT_AND_BACK , GL_AMBIENT , BlueSurface ) ; 此处同上画第五、六个面。 glEndList ( ) ; glNewList ( ArmPart2 , GL_COMPILE ) ; glMaterialfv ( GL_FRONT_AND_BACK , GL_AMBIENT , GreenSurface ) ; auxSolidTeapot ( 1.0 ) ; //用辅助库函数画茶壶。 glEndList ( ) ; return TRUE ; } 15. 显示。编辑 RenderScene函数: void COPDoc :: RenderScene ( void ) { double m_angle1 = 60.0 ; double m_angle2 = 30.0 ; glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ; glPushMatrix ( ) ; glTranslated ( 3.0 , 0.0 , -8.0 ) ; glRotated ( m_angle1 , 0 , 0 , 1 ) ; glRotated ( m_angle2 , 0 , 1 , 0 ) ; glCallList ( ArmPart1); glPopMatrix ( ) ; glPushMatrix ( ) ; glTranslated ( 0.0 , 0.0 , -8.0 ) ; glCallList ( ArmPart2 ) ; glPopMatrix ( ) ; glFlush ( ) ; } VC中 OpenGL编程的步骤: 1.使用 AppWizard创建应用程序框架,在文档和视结构中,视负责窗口中内容的显示,因此所 有的 OpenGL绘制工作应放在视类进行; 2.利用 ClassWizard给视类添加如下成员函数: 重载 PreCreateWindow函数; 响应WM_CREATE消息的 OnCreate函数; 响应WM_SIZE消息的 OnSize函数; 响应WM_ERASEBKGND消息的 OnEraseBKgnd函数; 响应WM_DESTROY消息的 OnDestroy函数; 重载 OnInitialUpdate函数 3.在 PreCreateWindow函数中加入如下语句: cs.style=cs.style|WS_CLIPSIBLINGS|WS_CLIPCHILDREN; 窗口必须设置以上属性,否则像素格式就不能正确设置; 4.设置像素格式,创建绘制描述表。这一过程放在响应WM_CREATE消息的 OnCreate函数中。 WM_CREATE消息窗口被创建时产生。 像素格式定义显示设备的三十特性,比如颜色位平面的数量和组织方式(RGB 模式还是索引模 式),是否采用双缓存模式等等。OpenGl 和 GDI(Windows 的图形设置接口)的像素格式不同,而 Windows应用中窗口的缺省设置是 GDI像素格式,所以需要为执行 OpenGL绘制任务的窗口专门指 定像素格式。对每个窗口,像素格式只能设置一次。 绘制描述表与设置描述表类似,但包含了更多有关 OpenGL绘制信息。OpenGL依赖绘制描述表 操作显示硬件,因此调用 OpenGL命令前,必须创建描述表并使其成为当前的绘制描述表。 设置像素格式、创建绘制描述是每个窗口进行OpenGl绘制前必不可少的步骤,所以放在OnCreate 函数中最为合适。 5.响应WM_SIZE消息。当视窗的大小改变时,需发送WM_SIZE消息。在WM_SIZE的消息 响应函数中可以获知改变后窗口的大小,因此在其中可以调用 glViewport 对场景的窗口变换进行更 改以后适应窗口大小的改变,还可通过 glFrustum等函数重新设置投影变换,使得当窗口的大小发生 改变时,显示在窗口中的场景不会发生扭曲。 6.响应WM_ERASEBKGND消息。当需要重新设置窗口背景时,产生WM_ERASEBKGND消 息。处理该消息的缺省操作是用当前背景色填充整个窗口。处理函数做适当改变:注释掉 OnEraseBKgnd函数所有的语句,添加 returnTRUE,使该函数不执行操作,仅返回 TRUE值。 7.重载 OnInitUpdate 函数。OnInitUpdate 函数为视对象专有,在视第一次显示之前,文档和视 的结构刚刚被建起之后调用,此时,从视对象中可以获得与之相连的文档对象中的信息。根据文档 和视的关系,OpenGL 的绘制信息一般通过文档对象存取,通过视对象,因此,在 OnInitUpdate 中 适合做 OpenGL的绘制前的初始化工作。初始化工作包括创建列表(显示列表索引作为视类对象的成 员变量保存)。设置光照参数,装载纹理映射贴图,确定融合方式及参数,设置雾化参数以及其它绘 制场景前需完成的工作。必要时可设置时钟,程序在以后的运行中将定时接收到WM_TIMER消息, 只要在该消息的响应函数中有规律地改变场景设置,并使视图重新绘制,就可以在窗口中形成动画 效果。 8.在 OnDraw函数中绘制 OpenGL场景。所有的绘制工作都应放在 OnDraw函数中。 9.响应 WM_TIMER 消息。WM_TIMER 消息由程序中设定的时钟产生。若未设定时钟,则不 用响应WM_TIMER消息。在WM_TIMER的消息处理函数中,更新场景,然后发送WM_PAINT消 息或直接调用 OnDraw函数,使窗口中显示改变后的场景。如此反复,形成动画。 10.响应 WM_DESTROY 消息。WM_DESTROY 消息在窗口销毁时产生。在 WM_DESTROY 的消息的处理函数中删除描述表。 必要时重载基本应用框架中应用程序类的 OnIdle 函数。OnIdle 函数在程序的消息队列为空时被 调用,该函数执行的功能与 gluIdleFunc函数设定的空闲回调函数的功能相似,即执行一些后台任务。 用 VisualC++6实现 OpenGL编程 一、OpenGL简介 众所周知,OpenGL原先是 SiliconGraphicsIncorporated(SGI公司)在他们的图形工作站上 开发高质量图像的接口。但最近几年它成为一个非常优秀的开放式三维图形接口。实际上它是图形 软件和硬件的接口,它包括有 120多个图形函数,"GL"是"GRAPHICLIBRARY"的缩写,意思是“图 形库”。OpenGL 的出现使大多数的程序员能够在 PC 机上用 C 语言开发复杂的三维图形。微软在 VisualC++5中已提供了三个 OpenGL的函数库(glu32.lib,glau.lib,OpenGL32.lib),可以使我们方便地编 程,简单、快速地生成美观、漂亮的图形。例如,WindowsNT中的屏幕保护程序中的花篮和迷宫等 都给人们留下了深刻的印象。 二、生成 OpenGL程序的基本步骤和条件 本文将给出一个例子,这个例子是一个用 OpenGL显示图像的 Windows程序,通过这个程 序我们也可以知道用 OpenGL编程的基本要求。我们知道,GDI是通过设备句柄(DeviceContext以 下简称"DC")来绘图,而 OpenGL则需要绘制环境(RenderingContext,以下简称"RC")。每一个 GDI 命令需要传给它一个 DC,与 GDI不同,OpenGL使用当前绘制环境(RC)。一旦在一个线程中指定了 一个当前 RC,所有在此线程中的 OpenGL命令都使用相同的当前 RC。虽然在单一窗口中可以使用 多个 RC,但在单一线程中只有一个当前 RC。本例将首先产生一个 OpenGLRC并使之成为当前 RC, 分为三个步骤:设置窗口像素格式;产生 RC;设置为当前 RC。 1、首先创建工程 用 AppWizard 产生一个 EXE 文件,选择工程目录,并在工程名字中输入"GLSample1",保 持其他的不变;第一步、选单文档(SDI);第二步、不支持数据库;第三步、不支持 OLE;第四步、 不选中浮动工具条、开始状态条、打印和预览支持、帮助支持的复选框(选中也可以,本文只是说 明最小要求),选中三维控制(3DControls);第五步、选中产生源文件注释并使用MFC为共享动态库; 第六步、保持缺省选择。按 Finish结束,工程创建完毕。 2、将此工程所需的 OpenGL文件和库加入到工程中 在工程菜单中,选择"Build"下的"Settings"项。单击"Link"标签,选择"General"目录,在 Object/LibraryModules的编辑框中输入"OpenGL32.libglu32.libglaux.lib"(注意,输入双引号中的内容, 各个库用空格分开;否则会出现链接错误),选择"OK"结束。然后打开文件"stdafx.h",将下列语句 插入到文件中(划下划线的语句为所加语句): #defineVC_EXTRALEAN//Excluderarely-usedstufffromWindowsheaders #include//MFCcoreandstandardcomponents #include//MFCextensions #include #include #ifndef_AFX_NO_AFXCMN_SUPPORT #include//MFCsupportforWindows95CommonControls #endif//_AFX_NO_AFXCMN_SUPPORT 3、改写 OnPreCreate函数并给视类添加成员函数和成员变量 OpenGL需要窗口加上WS_CLIPCHILDREN(创建父窗口使用的Windows风格,用于重绘 时裁剪子窗口所覆盖的区域)和WS_CLIPSIBLINGS(创建子窗口使用的Windows风格,用于重绘 时剪裁其他子窗口所覆盖的区域)风格。把 OnPreCreate改写成如下所示: BOOLCGLSample1View::PreCr-eateWindow(CREATESTRUCT&cs) { cs.style|=(WS_CLIPCHI-LDREN|WS_CLIPSIBLINGS); returnCView::PreCreate-Window(cs); } 产生一个 RC的第一步是定义窗口的像素格式。像素格式决定窗口着所显示的图形在内存中 是如何表示的。由像素格式控制的参数包括:颜色深度、缓冲模式和所支持的绘画接口。在下面将 有对这些参数的设置。我们先在 CGLSample1View 的类中添加一个保护型的成员函数 BOOLSetWindowPixel-Format(HDChDC)(用鼠标右键添加),并编辑其中的代码,见程序 1。 BOOLCGLSample1View::SetWindowPixelFormat(HDChDC) { PIXELFORMATDESCRIPTORpixelDesc; pixelDesc.nSize=sizeof(PIXELFORMATDESCRIPTOR); pixelDesc.nVersion=1; pixelDesc.dwFlags=PFD_DRAW_TO_WINDOW| PFD_DRAW_TO_BITMAP| PFD_SUPPORT_OpenGL| PFD_SUPPORT_GDI| PFD_STEREO_DONTCARE; pixelDesc.iPixelType=PFD_TYPE_RGBA; pixelDesc.cColorBits=32; pixelDesc.cRedBits=8; pixelDesc.cRedShift=16; pixelDesc.cGreenBits=8; pixelDesc.cGreenShift=8; pixelDesc.cBlueBits=8; pixelDesc.cBlueShift=0; pixelDesc.cAlphaBits=0; pixelDesc.cAlphaShift=0; pixelDesc.cAccumBits=64; pixelDesc.cAccumRedBits=16; pixelDesc.cAccumGreenBits=16; pixelDesc.cAccumBlueBits=16; pixelDesc.cAccumAlphaBits=0; pixelDesc.cDepthBits=32; pixelDesc.cStencilBits=8; pixelDesc.cAuxBuffers=0; pixelDesc.iLayerType=PFD_MAIN_PLANE; pixelDesc.bReserved=0; pixelDesc.dwLayerMask=0; pixelDesc.dwVisibleMask=0; pixelDesc.dwDamageMask=0; m_GLPixelIndex=ChoosePixelFormat(hDC,&pixelDesc); if(m_GLPixelIndex==0)//Let'schooseadefaultindex. {m_GLPixelIndex=1; if(DescribePixelFormat(hDC,m_GLPixelIndex, sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)==0) {returnFALSE; } } if(SetPixelFormat(hDC,m_GLPixelIndex,&pixelDesc)==FALSE) {returnFALSE; } returnTRUE; } 接着用鼠标右键在 CGLSample1View中添加保护型的成员变量: intm_GLPixelIndex; 4、用 ClassWizard添加WM_CREATE的消息处理函数 OnCreate 添加 OnCreate函数后如程序 1所示。 至此,OpenGL 工程的基本框架就建好了。但如果你现在运行此工程,则它与一般的 MFC 程序看起来没有什么两样。 5、代码解释 现在我们可以看一看 Describe-PixelFormat提供有哪几种像素格式,并对代码进行一些解释: PIXELFORMATDESCRIPTOR包括了定义像素格式的全部信息。 DWFlags定义了与像素格式兼容的设备和接口。 通常的 OpenGL发行版本并不包括所有的标志(flag)。wFlags能接收以下标志: PFD_DRAW_TO_WINDOW使之能在窗口或者其他设备窗口画图; PFD_DRAW_TO_BITMAP使之能在内存中的位图画图; PFD_SUPPORT_GDI使之能调用 GDI函数(注:如果指定了 PFD_DOUBLEBUFFER,这个 选项将无效); PFD_SUPPORT_OpenGL使之能调用 OpenGL函数; PFD_GENERIC_FORMAT假如这种象素格式由WindowsGDI函数库或由第三方硬件设备驱 动程序支持,则需指定这一项; PFD_NEED_PALETTE告诉缓冲区是否需要调色板,本程序假设颜色是使用 24或 32位色, 并且不会覆盖调色板; PFD_NEED_SYSTEM_PALETTE这个标志指明缓冲区是否把系统调色板当作它自身调色板 的一部分; PFD_DOUBLEBUFFER指明使用了双缓冲区(注:GDI不能在使用了双缓冲区的窗口中画 图); PFD_STEREO指明左、右缓冲区是否按立体图像来组织。 PixelType 定义显示颜色的方法。PFD_TYPE_RGBA 意味着每一位(bit)组代表着红、绿、蓝 各分量的值。PFD_TYPE_COLORINDEX 意味着每一位组代表着在彩色查找表中的索引值。本例都 是采用了 PFD_TYPE_RGBA方式。 ●cColorBits定义了指定一个颜色的位数。对 RGBA来说,位数是在颜色中红、绿、蓝各分 量所占的位数。对颜色的索引值来说,指的是表中的颜色数。 ●cRedBits、cGreenBits、cBlue-Bits、cAlphaBits用来表明各相应分量所使用的位数。 ●cRedShift、cGreenShift、cBlue-Shift、cAlphaShift 用来表明各分量从颜色开始的偏移量所 占的位数。 一旦初始化完我们的结构,我们就想知道与要求最相近的系统象素格式。我们可以这样做: m_hGLPixelIndex=ChoosePixelFormat(hDC,&pixelDesc); ChoosePixelFormat 接 受 两 个 参 数 : 一 个 是 hDc , 另 一 个 是 一 个 指 向 PIXELFORMATDESCRIPTOR 结构的指针&pixelDesc;该函数返回此像素格式的索引值。如果返回 0 则表示失败。假如函数失败,我们只是把索引值设为 1 并用 DescribePixelFormat 得到像素格式描 述。假如你申请一个没得到支持的像素格式,则 Choose-PixelFormat 将会返回与你要求的像素格式 最接近的一个值。一旦我们得到一个像素格式的索引值和相应的描述,我们就可以调用 SetPixelFormat设置像素格式,并且只需设置一次。 现在像素格式已经设定,我们下一步工作是产生绘制环境(RC)并使之成为当前绘制环境。 在 CGLSample1View 中加入一个保护型的成员函数 BOOLCreateViewGLContext(HDChDC),使之如 下所示: BOOLCGLSample1View::CreateViewGLContext(HDChDC) {m_hGLContext=wglCreateContext(hDC);//用当前 DC产生绘制环境(RC) if(m_hGLContext==NULL) {returnFALSE; } if(wglMakeCurrent(hDC,m_hGLContext)==FALSE) {returnFALSE; } returnTRUE; } 并加入一个保护型的成员变量 HGLRCm_hGLContext;HGLRC是一个指向 renderingcontext 的句柄。 在 OnCreate函数中调用此函数: intCGLSample1View::OnCreate(LPCREATESTRUCTlpCreateStruct) { if(CView::OnCreate(lpCreateStruct)==-1) return-1; HWNDhWnd=GetSafeHwnd(); HDChDC=::GetDC(hWnd); if(SetWindowPixelFormat(hDC)==FALSE) return0; if(CreateViewGLContext(hDC)==FALSE) return0; return0; } 添加WM_DESTROY的消息处理函数 Ondestroy(),使之如下所示: voidCGLSample1View::OnDestroy() { if(wglGetCurrentContext()!=NULL) {//maketherenderingcontextnotcurrent wglMakeCurrent(NULL,NULL); } if(m_hGLContext!=NULL) {wglDeleteContext(m_hGLContext); m_hGLContext=NULL; } //NowtheassociatedDCcanbereleased. CView::OnDestroy(); } 最后,编辑 CGLSample1View的构造函数,使之如下所示: CGLTutor1View::CGLTutor1View() {m_hGLContext=NULL; m_GLPixelIndex=0; } 至此,我们已经构造好了框架,使程序可以利用 OpenGL 进行画图了。你可能已经注意到了, 我们在程序开头产生了一个 RC,自始自终都使用它。这与大多数的 GDI程序不同。在 GDI程序中, DC在需要时才产生,并且是画完立刻释放掉。实际上,RC也可以这样做;但要记住,产生一个 RC 需要很多处理器时间。因此,要想获得高性能流畅的图像和图形,最好只产生 RC 一次,并始终用 它,直到程序结束。 CreateViewGLContex产生 RC并使之成为当前 RC。WglCreateContext返回一个 RC的句柄。 在你调用 CreateViewGLContex 之前,你必须用 SetWindowPixelFormat(hDC)将与设备相关
本文档为【OpenGL介绍和使用】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_462695
暂无简介~
格式:pdf
大小:415KB
软件:PDF阅读器
页数:16
分类:互联网
上传时间:2011-03-16
浏览量:33