OpenGL 基础 计算机科学与技术系
OpenGL简介 OpenGL(Open Graphics Library,开放图形库),是一个三维的计算机图形和模型库,是一种专业的图形软件接口 SGI公司1992发布的1.0版,目前为4.2版本 OpenGL是与硬件无关的软件接口,跨平台
OpenGL应用平台 在Windows 98/2000/XP/7/8、Unix、MacOS、OS/2之间进行移植 Android系统平台OpenGL ES(OpenGL for Embedded System),是 OpenGL 三维图形 API 的子集,针对手机、PDA和游戏主机等嵌入式设备而设计子集 Web平台的WebGL,是一种3D绘图标准,标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,为HTML5 Canvas提供硬件3D加速渲染。
OpenGL简介 OpenGL可用的编程语言: OpenGL使用简便,效率高 不是编程语言,而是一种API C/C++ Java C#.NET Python OpenGL使用简便,效率高 不是编程语言,而是一种API OpenGL提供了一组功能强大但又非常基本的函数,有700多个函数
OpenGL函数库 OpenGL函数库相关的API:核心库(gl)、实用库(glu)、辅助库(aux)、实用工具库(glut)、窗口库(glx、agl、wgl)和扩展函数库 gl是核心,glu是对gl的部分封装。glx、agl、wgl 是针对不同窗口系统的函数。glut是为跨平台的OpenGL程序的工具包,比aux功能强大。扩展函数库是硬件厂商为实现硬件更新利用OpenGL的扩展机制开发的函数。
相关的库文件 函数库 头文件 链接库文件 动态库文件 GL(核心库) gl.h Opengl32.lib Opengl32.dll GLU(工具库) glu.h Glu32.lib Glu32.dll GLUT(工具库) glut.h Glut32.lib Glut32.dll AUX(辅助库) glaux.h Glaux.lib Glaux.dll
Glut实用工具库 Glut( The OpenGL Utility Toolkit) 是OpenGL的跨平台工具库,使OpenGL应用程序结构能够真正独立于窗口系统 目的是隐藏不同窗口系统API带来的复杂性 包括了gl、glu的函数 图元函数:有2D多边形,3D实体等 观察函数:OpenGL提供以虚拟的摄像机,观察图元 控制函数:启动OpenGL的特性,如消隐,纹理 查询函数:允许特定系统的性能以及OpenGL状态变量的取值 输入与窗口函数:用于交互设计
如何创建一个OpenGL程序 使用OpenGL准备文件(http://www.opengl.org/resources/libraries/glut/glutdlls37beta.zip) glut32.dll glut.dll glut32.lib glut.h glut.lib
如何创建一个OpenGL程序-环境配置 Windows XP系统(32位) Visual C++6.0 glut32.dll 和glut.dll放到System32里面 Visual C++6.0 glut32.lib 和glut.lib里边放到你所用IDE中专门放静态链接库的文件夹下,如 C:\Program Files\Microsoft Visual Studio \VC98 \Lib glut.h 放到你所用IDE中专门放头文件的文件夹下 ,如: C:\Program Files\Microsoft Visual Studio \VC98 \include\GL
如何创建一个OpenGL程序-环境配置 Windows 7系统(64位) VS2008或VS2013以上 - glut32.dll 和glut.dll SysWoW64(Windows 7) VS2008或VS2013以上 - glut32.lib 和glut.lib里边放到你所用IDE中专门放静态链接库的文件夹下,如 (VS2008) C:\Program File(x86)\Microsoft Visual Studio 9.0\VC\lib (VS2013) C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\lib glut.h 放到你所用IDE中专门放头文件的文件夹下 ,如 (VS2008) C:\Program File(x86)\Microsoft Visual Studio 9.0\VC\include\GL Studio 12.0\VC\include\GL
OpenGL编程 例:画一个黄色线框三角形 (4,-4) (-4,-4) (0,4)
如何创建一个Win32 Console Application 的OpenGL程序 新建一个工程(VC++6.0)
如何创建一个OpenGL程序
如何创建一个OpenGL程序(VS2013)
如何创建一个OpenGL程序
OpenGL程序结构 void display() { . . . } #include <GL/glut.h> // glut.h includes gl.h and glu.h An OpenGL utility library built on top of gl void display() { . . . } void init() { . . . } int main( int argc, char **argv) { . . . }
int main( int argc, char **argv) { glutInit( &argc, argv); // Initialize GLUT function callings // Set window position, from the left and top corner of the screen, in numbers of pixels glutInitWindowPosition( 200, 100); // Set window size (width, height) in number of pixels glutInitWindowSize( 500, 500); // Specify a window creation event glutCreateWindow( "Triangles"); // Specify the drawing function that is called when the window glutDisplayFunc( display); // is created or re-drew init(); // Invoke this function for initialization glutMainLoop(); // Enter the event processing loop return 0; // Indicate normal termination }
Glut程序的回调函数(Callbacks) 回调函数就是一个通过函数指针调用的函数 glutMainLoop(); Event insertion: Window creation, moving, maximizing, closing, etc. 事件队列 截获一个事件 处理事件 19
OpenGL回调函数(callback) glutDisplayFunc(display) 每当Glut确定一个窗口的内容需要显示时,通过这个函数注册的回调函数就会被执行。 void glutReshapeFunc(void (*func)(int width, int height)); 指定当窗口的大小改变时调用的函数 void glutKeyboardFunc(void (*func)(unsigned char key, int x, int y)); 注册当前窗口的键盘回调函数 void glutMouseFunc(void (*func)(int button, int state, int x, int y)); 注册当前窗口的鼠标回调函数
绘制过程 void draw_triangle(){ glBegin(GL_LINE_LOOP); glVertex2f(0.0, 4.0); glVertex2f(4.0, -4.0); glVertex2f(-4.0, -4.0); glEnd(); } void display() { glClear( GL_COLOR_BUFFER_BIT); // Clear the frame buffer glLoadIdentity(); glColor3f(1.0, 1.0, 0.2); draw_triangle(); glFlush(); // Force to display the new drawings immediately
OpenGL 基本图元 三类基本图元:点、直线段和多边形 每种图元都有自己的特性,如绿色线段
OpenGL基本命令格式
OpenGL 基本图元 点 glPointSize(2.0); glBegin(GL_POINTS); glColor3f(1.0, 1.0, 1.0); glVertex2f(-0.5, -0.5); glColor3f(1.0, 0.0, 0.0); glVertex2f(-0.5, 0.5); glColor3f(0.0, 0.0, 1.0); glVertex2f(0.5, 0.5); glColor3f(0.0, 1.0, 0.0); glVertex2f(0.5, -0.5); glEnd();
直线 glColor3f(0.0, 1.0, 0.0); glBegin(GL_LINES); glVertex2f(-0.5, -0.5); glVertex2f(-0.5, 0.5); glVertex2f(0.5, 0.5); glVertex2f(0.5, -0.5); glEnd(); glColor3f(0.0, 1.0, 0.0); glBegin(GL_LINE_STRIP); glVertex2f(-0.5, -0.5); glVertex2f(-0.5, 0.5); glVertex2f(0.5, 0.5); glVertex2f(0.5, -0.5); glEnd(); glColor3f(0.0, 1.0, 0.0); glBegin(GL_LINE_LOOP); glVertex2f(-0.5, -0.5); glVertex2f(-0.5, 0.5); glVertex2f(0.5, 0.5); glVertex2f(0.5, -0.5); glEnd();
多边形 glBegin()和glEnd()之间 glBegin(GL_POLYGON) glBegin(GL_TRIANGLE) glBegin(GL_TRIANGLE_STRIP) glBegin(GL_TRIANGLE_FAN) glBegin(GL_QUADS) glBegin(GL_QUAD_STRIP)
初始化场景 void init() { glMatrixMode(GL_PROJECTION); //将当前矩阵指定为投影矩阵 glLoadIdentity(); //把矩阵设为单位矩阵 //创建一个正交平行的视景体(观察体) glOrtho(-10.0, 10.0, -10.0, 10.0, -1.0, 10); //设置完成后开始画图,需要切换到模型视图矩阵,才能正确画图 glMatrixMode(GL_MODELVIEW); // Set the clear color to black glClearColor(0.0, 0.0, 0.0, 0.0); //black }
场景重绘 void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-10.0, 10.0, -10.0*(GLfloat)h / (GLfloat)w, 10.0*(GLfloat)h / (GLfloat)w, -1.0, 10.0); else glOrtho(-10.0*(GLfloat)w / (GLfloat)h, 10.0*(GLfloat)w / (GLfloat)h, -10.0, 10.0, -1.0, 10.0); glMatrixMode(GL_MODELVIEW); }
坐标系与变换 使用两个坐标系:世界(用户)坐标系和屏幕坐标系 世界坐标系,建模使用的,单位任意 屏幕坐标系,显示模型,单位为像素 绘制时,OpenGL将世界坐标转换到屏幕坐标系 OpenGL需要的坐标变换有两个矩阵确定 1.模型视图矩阵(GL_MODELVIEW) 2.投影矩阵(GL_PROJECTION)
执行顺序 首先, glutMainLoop() 从队列中获取一个 <window creation>事件, 生成窗口,并调用 display()函数. 当窗口中标识 按钮被点击时,将一个 <stop>事件插入到队列中. 当这事件被处理之后,程序中止执行。 Clicking button glutInit(); Event Queue Functions that specify a new window 开始 main() init(); glutDisplayFunc(display); glutMainLoop() 结束 display()
运行结果
Glew扩展库 Glew(The OpenGL Extension Wrangler Library )是一个跨平台的C++扩展库,基于OpenGL图形接口。 GLEW能自动识别平台所支持的全部OpenGL高级扩展函数,即使用gl, glu, glext, wgl, glx的全部函数 Glew支持目前流行的各种操作系统,包括 Windows, Linux, Mac OS X, FreeBSD, Irix, and Solaris 资源: 项目主页: http://glew.sourceforge.net/ 文档地址: http://glew.sourceforge.net/install.html 下载地址: https://sourceforge.net/project/downloading.php?group_id=67586&filename=glew-1.5.1-src.zip
GLFW Glut太老了,最后一个版本还是90年代的。freeglut完全兼容glut,算是glut的代替品,功能齐全,但是bug太多。稳定性也不好,GLFW应运而生 GLFW 用C语言写的,一个支持多平台的开源库,支持 X 窗口系统,如Windows, OS X ,Linux and FreeBSD. 资源: http://www.glfw.org/
建立一个VC MFC框架的OpenGL程序 1. 创建一个基于单文档新工程
建立一个VC MFC框架的OpenGL程序
OpenGL绘制图形的机制 GDI是通过设备句柄(Device Context,DC)来绘图,而OpenGL则需要绘制环境(Rendering Context,RC) 每一个GDI命令需要传给它一个DC OpenGL使用当前绘制环境(RC)。一旦在一个线程中指定了一个当前RC,在此线程中其后所有的OpenGL命令都使用相同的当前RC 这将分为三个步骤:设置窗口像素格式;产生RC;设置为当前RC 在GDI程序中,DC在需要时才产生,并且是画完立刻释放掉。但产生一个RC需要很多处理器时间。因此,要想获得高性能流畅的图像和图形,最好只产生RC一次,并始终用它,直到程序结束。
设置绘制环境 2.添加OpenGL库 3.添加OpenGL头文件 菜单中选择Project Setting Link Object/Library Module 加入:opengl32.lib glu32.lib glaux.lib 3.添加OpenGL头文件 在文件Stdafx.h中,添加如下: #include <gl/gl.h> #include <gl/glu.h> #include <gl/glaux.h>
设置绘制环境 4. 改写OnPreCreate函数并给视图类添加成员函数和成员变量 BOOL COpenGLDemoView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CView::PreCreateWindow(cs); } cs.style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS); WS_CLIPCHILDREN: 用于重绘时裁剪子窗口所覆盖的区域 WS_CLIPSIBLINGS: 创建子窗口使用的Windows风格,用于重绘时剪裁其他子窗口所覆盖的区域
设置绘制环境 5. 产生一个RC (1)定义窗口的像素格式 像素格式决定窗口着所显示的图形在内存中是如何表示的。 在XXXView.CPP文件中,添加成员函数 BOOL CMFCOpenGLView::SetWindowPixelFormat(HDC hDC) {//定义窗口的像素格式 PIXELFORMATDESCRIPTOR pixelDesc= {} } 在XXXView.h文件中,添加保护成员变量 int m_GLPixelIndex;
(2)产生绘制环境(RC)并使之成为当前绘制环境 设置绘制环境 (2)产生绘制环境(RC)并使之成为当前绘制环境 在XXXView.CPP文件中,添加成员函数 BOOL CMFCOpenGLView::CreateViewGLContext(HDC hDC) { return TRUE; } 在XXXView.h文件中,添加保护成员变量 HGLRC m_hGLContext;//HGLRC是一个指向rendering context的句柄
(3)启动绘制环境,在XXXView.CPP文件中, 添加消息处理函数OnCreate( ) int COpenGLDemoView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; // TODO: Add your specialized creation code here //设置像素格式 //启动绘制环境 return 0; } (4)释放环境,添加消息处理函数OnDestroy( ) void COpenGLDemoView::OnDestroy() { CView::OnDestroy(); }
设置绘制环境 (5)编辑CMFCOpenGLView的构造函数 CMFCOpenGLView::CMFCOpenGLView() { // TODO: add construction code here this->m_GLPixelIndex = 0; this->m_hGLContext = NULL; }
绘制图形 在XXXView.CPP文件中,添加消息处理函数OnSize( ) void COpenGLDemoView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); glViewport(0,0,width,height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,500.0*aspect,0.0,500.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } nitializeOpenGL()
绘制图形 在XXXView.CPP文件中,添加消息处理函数OnPaint( ) void COpenGLDemoView::OnPaint() { CPaintDC dc(this); // device context for painting glLoadIdentity(); glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_POLYGON); glColor4f(1.0f,0.0f,0.0f,1.0f); glVertex2f(100.0f,50.0f); glColor4f(0.0f,1.0f,0.0f,1.0f); glVertex2f(450.0f,400.0f); glColor4f(0.0f,0.0f,1.0f,1.0f); glVertex2f(450.0f,50.0f); glEnd(); glFlush(); } RenderScene
定义像素格式和 可用的RC WM_CREATE 获取一个DC句柄 创建一个OpenGL可用的RC 消息循环 WM_PAINT 绘制图形 WM_DESTROY 消除OpenGL可用的RC 删除DC句柄