计算机图形学OpenGL(第三版)第二章_第1页
计算机图形学OpenGL(第三版)第二章_第2页
计算机图形学OpenGL(第三版)第二章_第3页
计算机图形学OpenGL(第三版)第二章_第4页
计算机图形学OpenGL(第三版)第二章_第5页
已阅读5页,还剩45页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 前一页 休息1本章内容本章内容l编写图形程序编写图形程序l学习学习OpenGL程序的基本组成程序的基本组成l开发绘制点、直线、折线和多边形的基开发绘制点、直线、折线和多边形的基本图形工具本图形工具l学会用鼠标和键盘控制程序学会用鼠标和键盘控制程序 前一页 休息22.0 vc opengl 编程编程 指导例子指导例子l熟悉代码,多次练习熟悉代码,多次练习l见图形学第二课见图形学第二课opengl-console.doc,创建创建一个控制台的应用程序,本书采用的编一个控制台的应用程序,本书采用的编程方式程方式l见图形学第二课见图形学第二课opengl-nehe-win.doc,创创建一个建一个w

2、in32的应用程序,的应用程序,nehe教程(共教程(共48课)采用的编程方式课)采用的编程方式l见图形学第三课见图形学第三课opengl-nehe-mfc.doc,创创建一个建一个mfc的应用程序,本人推荐采用的的应用程序,本人推荐采用的编程方式,需要学习编程方式,需要学习vc和和mfc。 前一页 休息32.1 生成图像初步生成图像初步l通过练习(编写和测试各种不同图形的程序)可以通过练习(编写和测试各种不同图形的程序)可以很快掌握计算机图形学。先从简单的任务开始,一很快掌握计算机图形学。先从简单的任务开始,一旦掌握,就试着变变花样,看看有哪些变化,试着旦掌握,就试着变变花样,看看有哪些变化

3、,试着进一步绘制更复杂的场景。最好的学习办法是认真、进一步绘制更复杂的场景。最好的学习办法是认真、仔细地学习每行代码或等式。当你这么做时,就能仔细地学习每行代码或等式。当你这么做时,就能理解每个新概念。理解每个新概念。l每个图形程序都以一些初始化工作为开始,由此建每个图形程序都以一些初始化工作为开始,由此建立程序所需要的显示模型和坐标系。立程序所需要的显示模型和坐标系。 前一页 休息42.1 生成图像初步生成图像初步l初始化时,将显示器设置为初始化时,将显示器设置为“图形模式图形模式”,并且建,并且建立了坐标系,坐标立了坐标系,坐标x和和y以像素为单位,以像素为单位,x向右递增,向右递增,y向

4、下递增。向下递增。 前一页 休息52.1.1 设备无关的编程设备无关的编程 和和OpenGLlOpenGL程序可以在不同的图形环境里编译和运行,程序可以在不同的图形环境里编译和运行,即它是与设备无关的编程。即它是与设备无关的编程。OpenGL是一个开源图形是一个开源图形库,可在库,可在下载。下载。OpenGL常被常被称为应用程序接口(称为应用程序接口(API)。这个接口是程序员可以)。这个接口是程序员可以调用的例程,先从调用的例程,先从OpenGL绘制简单的二维物体开始,绘制简单的二维物体开始,然后学习绘制三维图形。然后学习绘制三维图形。 前一页 休息6

5、2.1.2 窗口的编程窗口的编程l事件驱动编程:事件包括单击鼠标,按下键盘上的事件驱动编程:事件包括单击鼠标,按下键盘上的按键,或者重新调整窗口的大小。程序员将程序组按键,或者重新调整窗口的大小。程序员将程序组织成回调函数的集合,这些回调函数一有事件发生织成回调函数的集合,这些回调函数一有事件发生就执行。即什么也不做,等待事件发生,事件发生就执行。即什么也不做,等待事件发生,事件发生后再做指定的事。后再做指定的事。OpenGL有一个有一个GLUT库,它用来库,它用来打开窗口,管理菜单和处理事件等。打开窗口,管理菜单和处理事件等。l注册回调函数:有一种方法将每种类型的事件与要注册回调函数:有一种

6、方法将每种类型的事件与要求的回调函数关联起来,这个方法称之为注册回调求的回调函数关联起来,这个方法称之为注册回调函数。程序中用到的每一个事件类型都必须用回调函数。程序中用到的每一个事件类型都必须用回调函数注册,该回调函数的名字和定义由程序员选择。函数注册,该回调函数的名字和定义由程序员选择。 前一页 休息72.1.2 窗口的编程窗口的编程l下面是使用下面是使用GLUT库,名为库,名为myMouse的回调函数例的回调函数例子,它方便地注册了与鼠标关联的事件:子,它方便地注册了与鼠标关联的事件: glutMouseFunc(myMouse);); glutMouseFunc是是GLUT库的固有函数

7、,但是回调函库的固有函数,但是回调函数数myMouse是程序员定义的,并由程序员编写代码,是程序员定义的,并由程序员编写代码,处理每个可能感兴趣的鼠标动作。处理每个可能感兴趣的鼠标动作。 4种主要的种主要的OpenGL库:库:1)基本)基本GL库,库,OpenGL库的基础。它提供库的基础。它提供OpenGL的的基本函数。每个基本函数。每个OpenGL函数都以字符函数都以字符GL开头。开头。 前一页 休息82.1.2 窗口的编程窗口的编程l2)GLUT库:库:GL实用工具包。它用来打开窗口,开实用工具包。它用来打开窗口,开发和管理菜单,以及管理事件等。发和管理菜单,以及管理事件等。l3)GLU库

8、:库:GL实用库,它提供高级例程,处理矩实用库,它提供高级例程,处理矩阵操作和绘制二次曲面如球和圆柱体;阵操作和绘制二次曲面如球和圆柱体;l4)GLUI库:用户接口库,提供控制工具和菜单。库:用户接口库,提供控制工具和菜单。glutDisplayFunc(myDisplay):重绘窗口调用重绘窗口调用myDisplay回调函数;回调函数;glutReshapeFun(myReshape):对屏幕窗口的形状):对屏幕窗口的形状进行调整;进行调整;void main()glutDisplayFunc(myDisplay); / 注册重绘函数注册重绘函数glutReshapeFunc(myResha

9、pe); / 注册改变窗口形状函数注册改变窗口形状函数glutMouseFunc(myMouse); / 注册鼠标动作函数注册鼠标动作函数glutMotionFunc(myMouse); / 注册鼠标移动函数注册鼠标移动函数glutKeyboardFunc(myKeyboard); / 注册键盘动作函数注册键盘动作函数/可能初始化其他工作可能初始化其他工作glutMainLoop(); / 进入主循环等待事件发生进入主循环等待事件发生 前一页 休息102.1.3 如何打开一个窗口画图如何打开一个窗口画图 lglutInit:该函数初始化工具包:该函数初始化工具包lglutDisplayMode

10、(GLUT_SINGLE | GLUT_RGB): 分分配单个显示缓存配单个显示缓存lglutInitWindowSize(640,480): 该函数指定屏幕的初该函数指定屏幕的初始尺寸,宽始尺寸,宽640像素,高像素,高480像素。像素。lglutCreateWindow(“my first attempt”):该函):该函数打开并显示屏幕窗口吗,并显示标题。数打开并显示屏幕窗口吗,并显示标题。代码如下:代码如下:void main(int argc, char* argv)glutInit(&argc, argv); / 初始化工具包初始化工具包glutInitDisplayMod

11、e(GLUT_SINGLE | GLUT_RGB); / 设置显示模式设置显示模式glutInitWindowSize(640,480); / 设置窗口大小设置窗口大小glutInitWindowPosition(100, 150); / 设置窗口在屏幕上的位置设置窗口在屏幕上的位置glutCreateWindow(my first attempt); / 打开屏幕窗口打开屏幕窗口/ 注册回调函数注册回调函数glutDisplayFunc(myDisplay);glutReshapeFunc(myReshape);glutMouseFunc(myMouse);glutKeyboardFunc(

12、myKeyboard);myInit(); / 必要的其他初始化工作必要的其他初始化工作glutMainLoop(); / 进入循环进入循环 前一页 休息132.2 OpenGL的基本图形元素的基本图形元素l屏幕坐标系:宽为屏幕坐标系:宽为640,高为,高为640。x坐标从左边界坐标从左边界0增加到右边界增加到右边界639,y坐标从坐标从0增加到上边的增加到上边的479。绘制三个点:绘制三个点:glBegin(GL_POINTS);glVertex2i(100, 50);glVertex2i(100, 130);glVertex2i(150, 130);glEnd();或者用浮点值代替整数值:

13、或者用浮点值代替整数值:glBegin(GL_POINTS);glVertex2d(100.0, 50.0);glVertex2d(100.0, 130.0);glVertex2d(150.0, 130.0);glEnd();OpenGL数据类型:数据类型:命令后缀和参数数据类型命令后缀和参数数据类型OpenGL状态:状态:OpenGL是由许多状态变量组成的状态机,这些状态包括点的大是由许多状态变量组成的状态机,这些状态包括点的大小、绘图的颜色额屏幕窗口大小等,点的大小可以用小、绘图的颜色额屏幕窗口大小等,点的大小可以用glPointSize()来设置,画图的颜色用这条语句设置:()来设置,画

14、图的颜色用这条语句设置: glColor3f(red,green,blue););坐标系的建立:坐标系的建立:void myInit(void)glMatrixMode(GL_PROJECTION);glLoadIdentity();gluOrtho2D(0, 640.0, 0, 480.0);myInit设置坐标系,设置透视投影变换。设置坐标系,设置透视投影变换。gluOrtho2D设置正交投影。设置正交投影。组合在一起:建立起一个完整的组合在一起:建立起一个完整的OpenGL程序程序glFlush()函数保证所有的数据被完全处理并显()函数保证所有的数据被完全处理并显示。示。 前一页 休息

15、172.2.1 几个点丛绘制的例子几个点丛绘制的例子l点丛是由大量点组成的某种图案。下面有几个点丛点丛是由大量点组成的某种图案。下面有几个点丛例子。例子。例子例子2.2.1 北斗星群北斗星群 见计算机图形学课件见计算机图形学课件2016计算机图形学(计算机图形学(Opengl版第三版版第三版)书书源代码源代码word版版2.2.1-threeDots.doc例子例子2.2.2 Sierpinski(塞平斯基)垫片(塞平斯基)垫片见计算机图形学课件见计算机图形学课件2016计算机图形学(计算机图形学(Opengl版第三版版第三版)书源书源代码代码word版版2.2.1-threeDots.doc

16、算法如下:第算法如下:第k个点表示为个点表示为P(k)=(x(k),),y(k),每一个),每一个点都依赖于前一个点点都依赖于前一个点P(k-1),过程如下:),过程如下:(1)选择三个固定的点)选择三个固定的点T0,T1,T2,构成一个三角形,称为每,构成一个三角形,称为每个个Sierpinski垫片的父三角形;垫片的父三角形;(2)随机选择父三角形顶点)随机选择父三角形顶点T0,T1,T2中的一点作为要绘制的中的一点作为要绘制的初始点初始点P0。 迭代下面的(迭代下面的(3)(5)步,直到图案填充完毕。)步,直到图案填充完毕。(3)随机选择)随机选择T0,T1,T2中的一点,称为中的一点,

17、称为T。(4)构造下一个点)构造下一个点P(k),作为),作为T和前一个已建好的点和前一个已建好的点P(k-1)之间的之间点,即之间的之间点,即P(k)=(P(k-1)+T)/2(5)用)用drawDot()绘制()绘制P(k)。)。例子例子2.2.2 Sierpinski(塞平斯基)垫片(塞平斯基)垫片/初始值初始值P(0),在在for循环外面循环外面GLintPoint point = Tindex; / 初始值初始值drawDot(point.x, point.y); / 画初始点画初始点for(int i = 0; i 1000; i+) /画画1000点点index = rand()

18、%3;/P(k)=(P(k-1)+T)/2point.x = (point.x + Tindex.x) / 2;point.y = (point.y + Tindex.y) / 2;drawDot(point.x,point.y);例子例子2.2.3 用点集绘制函数用点集绘制函数 见计算机图形学课件见计算机图形学课件2016计算机图形学(计算机图形学(Opengl版第三版版第三版)书书源代码源代码word版版2.2.1-threeDots.doc绘制某个数学函数绘制某个数学函数f(x),当),当x在在04变化时的曲线。当绘制曲线变化时的曲线。当绘制曲线时,因为时,因为04之间的之间的x值位于屏

19、幕窗口左下角的前值位于屏幕窗口左下角的前4个像素上,个像素上,而且而且f(.)的负值位于窗口的下面,根本看不到。需要进行平移的负值位于窗口的下面,根本看不到。需要进行平移和缩放使曲线正好出现在合适的屏幕窗口。将世界坐标系转换和缩放使曲线正好出现在合适的屏幕窗口。将世界坐标系转换为为窗口坐标系。窗口坐标系。x方向缩放:假定屏幕窗口为方向缩放:假定屏幕窗口为screenWidth,单位为像素,现在,单位为像素,现在x的的范围为范围为04,故,故sx = x * screenWidth /4.0;y方向缩放:假定屏幕窗口为方向缩放:假定屏幕窗口为screenHeight,单位为像素,单位为像素,f(

20、x) 的的 取值在取值在1.0 和和 1.0之间之间,缩放缩放screenHeight / 2 ,平移为,平移为 screenHeight / 2,sy = (y + 1.0) * screenHeight / 2.0;sx,sy为屏为屏幕坐标,幕坐标,x,y为窗口坐标;转换方程为:为窗口坐标;转换方程为: sx= A * x + B sy =C * y + Dconst int screenWidth = 640; / width of screen window in pixelsconst int screenHeight = 480; / height of screen window

21、 in pixelsGLdouble A, B, C, D; / values used for scaling and shiftingvoid myInit(void)glClearColor(1.0,1.0,1.0,0.0); / background color is whiteglColor3f(0.0f, 0.0f, 0.0f); / drawing color is blackglPointSize(2.0); / a dot is 2 by 2 pixelsglMatrixMode(GL_PROJECTION); / set camera shapeglLoadIdentity

22、();gluOrtho2D(0.0, (GLdouble)screenWidth, 0.0, (GLdouble)screenHeight);A = screenWidth / 4.0; / x方向的缩放量方向的缩放量AB = 0.0; /x方向的平移量方向的平移量BC = D = screenHeight / 2.0;/ y方向的缩放量方向的缩放量C和平移量和平移量Dvoid myDisplay(void)glClear(GL_COLOR_BUFFER_BIT); / clear the screenglBegin(GL_POINTS);for(GLdouble x = 0; x 4.0 ;

23、 x += 0.005)Gldouble func = exp(-x) * cos(2 * 3.14159265 * x);/sx= A * x + B, sy =C * y + DglVertex2d(A * x + B, C * func + D);glEnd();glFlush(); / send all output to display例子例子2.2.3 用点集绘制函数用点集绘制函数 见计算机图形学课件见计算机图形学课件2016计算机图形学(计算机图形学(Opengl版第三版版第三版)书源代码书源代码word版版2.2.1-threeDots.doc f(x)=sin(x),f(x)

24、=sin(2x),x从从-到到,y从从-1到到1A = screenWidth / 6.28;/ x方向的缩放量方向的缩放量A,屏幕宽度,屏幕宽度/x方向的变化范围方向的变化范围 B = screenWidth/2.0; /x方向的平移量方向的平移量B,屏幕宽度的一半,屏幕宽度的一半 C = screenHeight / 2.0;/ y方向的缩放量方向的缩放量C,屏幕高度,屏幕高度/y方向的变化范围方向的变化范围 D = screenHeight / 2.0;/ y方向的平移量方向的平移量D,屏幕的高度的一半屏幕的高度的一半for(GLdouble x = -3.14; x 3.14 ; x

25、+= 0.005)Gldouble func = sin(x);Gldouble func 1= sin(2x);/sx= A * x + B, sy =C * y + DglVertex2d(A * x + B, C * func + D);glVertex2d(A * x + B, C * func 1+ D); 前一页 休息232.3 OpenGL中的直线绘制中的直线绘制l绘制线段绘制线段glBegin(GL_LINES); / use constant GL_LINES here glVertex2i(40, 100); glVertex2i(202, 96);glEnd();或者编写

26、一个函数或者编写一个函数void drawLineInt(GLint x1, GLint y1, GLint x2, GLint y2)glBegin(GL_LINES);glVertex2i(x1, y1);glVertex2i(x2, y2);glEnd();2.3.1 绘制折线和多边形绘制折线和多边形折线就是一系列头尾相连的线段的集合,也称为线带。折线就是一系列头尾相连的线段的集合,也称为线带。glBegin(GL_LINE_STRIP); / draw an open polyline glVertex2i(20,10); glVertex2i(50,10); glVertex2i(2

27、0,80); glVertex2i(50,80);glEnd();glFlush();绘制多边形,只需要用绘制多边形,只需要用GL_LINE_LOOP替换替换GL_LINE_STRIP 即可,即是闭合的。即可,即是闭合的。 f(x) = 300 - 100 cos(2p x/100) + 30 cos(4p x/100) + 6 cos(6p x/100)glBegin(GL_LINE_STRIP);for(x = 0; x = 300; x += 3)glVertex2d(A * x + B, C * f(x) + D);glEnd();glFlush;例子例子2.3.2 绘制存储在文件中的

28、折线绘制存储在文件中的折线 见计算机图形学课件见计算机图形学课件2016计算机图形学(计算机图形学(Opengl版第三版版第三版)书源代码书源代码word版版2.2.1-threeDots.doc,文件文件dino.dat:21 /文件中折线的数量文件中折线的数量4 / 第一条折线的点数第一条折线的点数169 118 / /第一条折线的第一个点第一条折线的第一个点174 120 /179 124178 1265 / 第二条折线的点数第二条折线的点数298 86 / 第二条折线的第一个点第二条折线的第一个点304 92310 104314 114314 1192932 43510 439. .

29、. 等等等等 例子例子2.3.3 参数化图形参数化图形 void hardwiredHouse(void) glBegin(GL_LINE_LOOP);/ 绘制房子外形绘制房子外形glVertex2i(40, 40); glVertex2i(40, 90); glVertex2i(70, 120); glVertex2i(100, 90); glVertex2i(100, 40);glEnd();glBegin(GL_LINE_STRIP); /绘制烟囱绘制烟囱glVertex2i(50, 100);glVertex2i(50, 120);glVertex2i(60, 120); glVert

30、ex2i(60, 110);glEnd();. . . / 绘制门绘制门. . . / 绘制窗户绘制窗户void parameterizedHouse(GLintPoint peak, GLint width, GLint height)/ 房子的顶点由房子的顶点由peak给定,房子的大小由给定,房子的大小由width和和height给定给定glBegin(GL_LINE_LOOP);glVertex2i(peak.x, peak.y); / 绘制房子外形绘制房子外形glVertex2i(peak.x + width / 2, peak.y - 3 * height /8);glVertex2

31、i(peak.x + width / 2 peak.y - height);glVertex2i(peak.x - width / 2, peak.y - height);glVertex2i(peak.x - width / 2, peak.y - 3 * height /8);glEnd();draw chimney in the same fashiondraw the doordraw the window第一个方法将由几条折线组成的简易房子的每个端点位置被强制写入代码中,第一个方法将由几条折线组成的简易房子的每个端点位置被强制写入代码中,而第二种方法则是利用参数来绘制,用参数指定房屋

32、顶点的位置和房子的而第二种方法则是利用参数来绘制,用参数指定房屋顶点的位置和房子的宽度和高度,比较灵活。宽度和高度,比较灵活。 例子例子2.3.4 构造一个折线绘图器构造一个折线绘图器 一些应用程序需要用一个列表存储折线的顶点。这个列表可能是一些应用程序需要用一个列表存储折线的顶点。这个列表可能是数组或者链表,可以采用类或者结构体保存数组,对于大量数数组或者链表,可以采用类或者结构体保存数组,对于大量数据,据,c+ STL(标准模板库)容器可能是一个安全的数据结构。(标准模板库)容器可能是一个安全的数据结构。struct GLintPointGLint x,y;class GLintPoint

33、Arrayconst int MAX_NUM = 100;public:int num;GLintPoint ptMAX_NUM;void drawPolyLine(GlintPointArray poly, int closed)glBegin(closed ? GL_LINE_LOOP : GL_LINE_STRIP);for(int i = 0; i poly.num; i+)glVertex2i(poly.pti.x, poly.pti.y);glEnd();glFlush(); 2.3.2 使用使用moveTo()和()和lineTo()绘制线段绘制线段 OpenGL绘制线段很容易。

34、可以用一组命令绘制线段很容易。可以用一组命令GL_LINES,.,GL_END,也可以用也可以用drawLine()函数。()函数。moveTo和和lineTo函数可以管理一个虚拟画笔,它的位置叫当前位置或函数可以管理一个虚拟画笔,它的位置叫当前位置或CP(current position)。)。CP像一个像一个OpenGL的状态变量,如画的状态变量,如画画的颜色和背景一样,它在程序的控制之下。画的颜色和背景一样,它在程序的控制之下。moveTo(x,y)/设定设定CP到(到(x,y)lineTo(x,y)/在在CP和(和(x,y)之间画一条线,更新)之间画一条线,更新CP。使用。使用下面的代

35、码,容易绘制基于点的列表下面的代码,容易绘制基于点的列表(x0, y0), (x1, y1), . , (xn-1, yn-1)的折线。的折线。moveto(x0, y0);for(int i = 1; i n; i+)lineto(xi, yi);可以直接在可以直接在OpenGL建立建立moveTo和和lineTo这两个函数,并保持这两个函数,并保持CP moveTo和和lineTo函数实现为:函数实现为: GLintPoint CP; / 全局位置变量全局位置变量/void moveto(GLint x, GLint y)CP.x = x; CP.y = y; / 更新更新CP/void

36、lineto(GLint x, GLint y)glBegin(GL_LINES); / 绘制曲线绘制曲线glVertex2i(CP.x, CP.y);glVertex2i(x, y);glEnd();glFlush();CP.x = x; CP.y = y; / 更新更新 CP 2.3.3 绘制边校正的矩形 多边形的特例是边校正的矩形,因为它的边与坐标轴平行,多边形的特例是边校正的矩形,因为它的边与坐标轴平行,OpenGL提供了提供了一个现成的函数一个现成的函数glRecti()。()。 glRecti(GLint x1, GLint y1, GLint x2, GLint y2); / 以

37、对角点以对角点(x1, y1) and (x2, y2)绘制矩形绘制矩形该函数基于两个给定点绘制边校正矩形,并以当前颜色填充矩形。该函数基于两个给定点绘制边校正矩形,并以当前颜色填充矩形。glClearColor(1.0,1.0,1.0,0.0); / 白色背景白色背景glClear(GL_COLOR_BUFFER_BIT); / 清除清除glColor3f(0.6,0.6,0.6); / 浅灰浅灰glRecti(20,20,100,70);glColor3f(0.2,0.2,0.2); / 深灰深灰glRecti(70, 50, 150, 130);glFlush();a)随机生成的矩形雪花

38、)随机生成的矩形雪花b)不同灰度等级的棋盘)不同灰度等级的棋盘void drawFlurry(int num, int numColors, int Width, int Height)/ draw num random rectangles in a Width by Height rectanglefor (int i = 0; i num; i+)GLint x1 = random(Width); / place corner randomlyGLint y1 = random(Height);GLint x2 = random(Width); / pick the size so it

39、 fitsGLint y2 = random(Height);GLfloat lev = random(10)/10.0; / random value, in range 0 to 1glColor3f(lev,lev,lev); / set the gray levelglRecti(x1, y1, x2, y2); / draw the rectangleglFlush();练习练习练习练习2.3.1 画棋盘画棋盘写出例程写出例程checkerboard(int size),这),这64个正方形的边个正方形的边长都设为长都设为size个像素。为这些正方形选择两种好看的个像素。为这些正方形

40、选择两种好看的颜色。颜色。解:第解:第ij个正方形的左下角位于个正方形的左下角位于(i*size, j*size)处(处( i =0,.,7 ; j = 0.7). 使用下面的代码,可以将颜色在使用下面的代码,可以将颜色在(r1, g1, b1) 和和(r2, g2, b2) 间变换。间变换。if(i + j)%2 =0) / 如果如果i + j 是偶数是偶数 glColor3f( r1, g1, b1);else glColor3f(r2, g2, b2);练习练习练习练习2.3.1 画棋盘画棋盘写出例程写出例程checkerboard(int size),这),这64个正方形的边个正方形的

41、边长都设为长都设为size个像素。为这些正方形选择两种好看的个像素。为这些正方形选择两种好看的颜色。颜色。解:第解:第ij个正方形的左下角位于个正方形的左下角位于(i*size, j*size)处(处( i =0,.,7 ; j = 0.7). 使用下面的代码,可以将颜色在使用下面的代码,可以将颜色在(r1, g1, b1) 和和(r2, g2, b2) 间变换。间变换。if(i + j)%2 =0) / 如果如果i + j 是偶数是偶数 glColor3f( r1, g1, b1);else glColor3f(r2, g2, b2);2.3.5 填充多边形填充多边形 OpenGL支持用图案

42、或色彩填充一般的多边形,那么这个多边形支持用图案或色彩填充一般的多边形,那么这个多边形是凸的。是凸的。 凸多边形:如果多边形中任意两点的连线完全位于多边凸多边形:如果多边形中任意两点的连线完全位于多边形内部,那么这个多边形是凸的。形内部,那么这个多边形是凸的。要绘制凸多边形,使用顶点列表,把顶点列表放要绘制凸多边形,使用顶点列表,把顶点列表放在在glBegin(GL_POLYGON)和)和glEnd()之()之间。可以用点画线图案填充多边形,会把图像间。可以用点画线图案填充多边形,会把图像贴在多边形上,作为应用纹理的。贴在多边形上,作为应用纹理的。C,E,F是凸的多边形。是凸的多边形。2.3.

43、6 OpenGL中的其他图形元素中的其他图形元素 除了点、线和多边形,除了点、线和多边形,OpenGL还支持绘制五种其他元素还支持绘制五种其他元素/ 使用鼠标指定一个矩形使用鼠标指定一个矩形static GLintPoint corner2;static int numCorners = 0; / initial value is 0if(button = GLUT_LEFT_BUTTON & state = GLUT_DOWN)cornernumCorners.x = x;cornernumCorners.y = screenHeight - y; / flip y coordina

44、tenumCorners+; / have another pointif(numCorners = 2)glRecti(corner0.x, corner0.y, corner1.x, corner1.y);numCorners = 0; / back to 0 cornerselse if(button = GLUT_RIGHT_BUTTON & state = GLUT_DOWN)glClear(GL_COLOR_BUFFER_BIT); / clear the windowglFlush();2.4 与鼠标和键盘的交互与鼠标和键盘的交互当用户按下或释放鼠标按钮、移动鼠标或者松开

45、或按下键盘时,当用户按下或释放鼠标按钮、移动鼠标或者松开或按下键盘时,就会产生一个相关事件。程序员可以用每类事件注册一个回调就会产生一个相关事件。程序员可以用每类事件注册一个回调函数函数 glutMouseFunc(myMouse) :利用按下或者鼠标按钮时发生事件来注册利用按下或者鼠标按钮时发生事件来注册 myMouse() glutMotionFunc(myMovedMouse) 利用鼠标移动注册函数利用鼠标移动注册函数 myMovedMouse() glutKeyboardFunc(myKeyboard) 利用按下或者松开键盘按键时注册函数利用按下或者松开键盘按键时注册函数 myKeyB

46、oard() 2.4.1 用鼠标交互用鼠标交互注册一个函数到注册一个函数到glutMouseFunc(myMouse),),myMouse()的()的名字可以任意,有四个参数:名字可以任意,有四个参数:void myMouse(int button, int state, int x, int y);button的值如下:的值如下:GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, 或或 GLUT_RIGHT_BUTTON;而而state的值可能为:的值可能为:GLUT_UP 或或GLUT_DOWN。x和和y为事件发生时鼠标的位置。为事件发生时鼠标的位置。2.4.1 用

47、鼠标绘制点用鼠标绘制点当用户每次按下鼠标时,就会在屏幕窗口上鼠标所在的位置绘制当用户每次按下鼠标时,就会在屏幕窗口上鼠标所在的位置绘制出一个点。由于鼠标位置的出一个点。由于鼠标位置的y值是距离屏幕顶端的像素值,故值是距离屏幕顶端的像素值,故不在不在(x, y), 而是在而是在 (x,screenHeight y)上绘制,其中上绘制,其中screenHeight 为屏幕的高度。为屏幕的高度。void myMouse(int button, int state, int x, int y)if(button = GLUT_LEFT_BUTTON & state = GLUT_DOWN)dr

48、awDot(x, screenHeight -y);else if(button = GLUT_RIGHT_BUTTON & state = GLUT_DOWN)exit(-1); 2.4.2 用鼠标指定一个矩形用鼠标指定一个矩形想让用户画尺寸大小由鼠标输入的长方形。用户在两个点上单击想让用户画尺寸大小由鼠标输入的长方形。用户在两个点上单击鼠标,指定边校正矩形的两个角点,就可以画出矩形。用户右鼠标,指定边校正矩形的两个角点,就可以画出矩形。用户右键点击鼠标即可清屏。键点击鼠标即可清屏。/ 使用鼠标指定一个矩形使用鼠标指定一个矩形static GLintPoint corner2;sta

49、tic int numCorners = 0; / initial value is 0if(button = GLUT_LEFT_BUTTON & state = GLUT_DOWN)cornernumCorners.x = x;cornernumCorners.y = screenHeight - y; / flip y coordinatenumCorners+; / have another pointif(numCorners = 2)glRecti(corner0.x, corner0.y, corner1.x, corner1.y);numCorners = 0; / b

50、ack to 0 cornerselse if(button = GLUT_RIGHT_BUTTON & state = GLUT_DOWN)glClear(GL_COLOR_BUFFER_BIT); / clear the windowglFlush();2.4.3 用鼠标控制用鼠标控制Sierpinski垫片垫片使用户用鼠标指定初始三角形的三个顶点,并置于数组使用户用鼠标指定初始三角形的三个顶点,并置于数组corners中,代码为中,代码为static GLintPoint corners3;static int numCorners = 0;if(button = GLUT_LE

51、FT_BUTTON & state = GLUT_DOWN)cornernumCorners.x = x;cornernumCorners.y = screenHeight - y; / flip y coordinateif(+numCorners = 3) Sierpinski(corners); / draw the gasketnumCorners = 0; / back to 0 corners 鼠标移动鼠标移动鼠标移动会产生一个鼠标事件:鼠标移动会产生一个鼠标事件:glutMotionFunc(myMovedMouse);注册函数注册函数myMovedMouse(int x

52、, int y);有两个参数,即事有两个参数,即事件发生时鼠标所在的位置。件发生时鼠标所在的位置。glutPassiveMotionFunc(myPassiveMotion);这个函数是没有按下鼠标按钮的情况下,鼠标在窗口内这个函数是没有按下鼠标按钮的情况下,鼠标在窗口内移动时调用。该函数可以绘制并显示橡皮矩形:随着移动时调用。该函数可以绘制并显示橡皮矩形:随着用户移动鼠标,矩形将相应地变大或变小。用户移动鼠标,矩形将相应地变大或变小。下面的程序是用户单击鼠标建立矩形的一个角点,然后下面的程序是用户单击鼠标建立矩形的一个角点,然后不按下鼠标时移动鼠标,调用不按下鼠标时移动鼠标,调用myPass

53、iveMotion(int x, int y),这决定了矩形的第二个角点。,这决定了矩形的第二个角点。glutPostRedisplay()调用调用myDisplay()函数。()函数。 代码见代码见见计算机图形学课件见计算机图形学课件2016计算机图形学计算机图形学(Opengl版第三版版第三版)书源代码书源代码word版版2.2.1-threeDots.doc2.4.2 键盘交互键盘交互按下键盘上的某个按键时就会产生一个键盘事件,并放入消息队按下键盘上的某个按键时就会产生一个键盘事件,并放入消息队列。回调函数列。回调函数myKeyboard()通过()通过glutKeyboardFunc(

54、myKeyboard)来注册这种事件,该函数的原来注册这种事件,该函数的原型为:型为:void myKeyboard(unsigned int key, int x, int y); key 值就是键的值就是键的ASCII 值,值, x 和和y为鼠标所在的位置。实例代码为:为鼠标所在的位置。实例代码为:void myKeyboard(unsigned char theKey, int mouseX, int mouseY)GLint x = mouseX;GLint y = screenHeight - mouseY; / 反转反转y的值的值switch(theKey)case p:drawD

55、ot(x, y); / draw a dot at the mouse positionbreak;case GLUT_KEY_LEFT: List+last.x = x; / add a pointList last.y = y;break;case E:exit(-1); /terminate the programdefault:break; / do nothing 前一页 休息412.5 程序中的菜单设计与使用程序中的菜单设计与使用l如果一个图形程序能够提供菜单功能,对用户来说,如果一个图形程序能够提供菜单功能,对用户来说,使用就比较方便了。建议使用使用就比较方便了。建议使用vc。

56、设计代码和使用设计代码和使用GLUT菜单菜单 创建菜单使用创建菜单使用void glutCreateMenu(),菜单项使用(),菜单项使用一个带参数的函数一个带参数的函数glutCreateMenu(ProcessMenuEvents)来定义,必须编写来定义,必须编写ProcessMenuEvents函数。使用函数函数。使用函数glutAddMenuEntry()可以在菜单中添加选项,一旦菜()可以在菜单中添加选项,一旦菜单设计好,可以用单设计好,可以用glutAttachMenu(GLUT_RIGHT_BUTTON)建立与鼠标按钮的联系。)建立与鼠标按钮的联系。代码见书代码见书P69.案例

57、分析案例分析 为了巩固所学知识,最好的方式就是使用学过的知识,在最初的学习中更是为了巩固所学知识,最好的方式就是使用学过的知识,在最初的学习中更是如此,因为一开始学习计算机图形学,不了解程序的编写是必须克服的障如此,因为一开始学习计算机图形学,不了解程序的编写是必须克服的障碍。为了强调这一点,每章都有案例,其中介绍的编程项目不仅本身有趣,碍。为了强调这一点,每章都有案例,其中介绍的编程项目不仅本身有趣,而且浓缩了该章中所提及的知识。而且浓缩了该章中所提及的知识。 难易程度:难易程度: I: 简单的练习,课堂即可完成。简单的练习,课堂即可完成。. II: 教难任务,可能需要几天才能完成。教难任务

58、,可能需要几天才能完成。 III: 复杂任务,可能需要两周完成。复杂任务,可能需要两周完成。案例案例2.1 伪随机点云伪随机点云(难度难度 II)rand()函数不是随机产生的,而是通过一个很有规律的机制产生的:每个数()函数不是随机产生的,而是通过一个很有规律的机制产生的:每个数ni 都是由它前一个数都是由它前一个数 ni-1,通过一个等式确定,通过一个等式确定 : ni = (ni-1 * A + B) mod N 其中其中 A, B, 和和 N 是适当选择的常数。是适当选择的常数。 一组有效的值为一组有效的值为: A =1103515245, B = 12345, 和和 N = 3276

59、7. 这个数限制在这个数限制在 0 到到 N-1. 散乱点图,调用散乱点图,调用rand(N),它会返回一个),它会返回一个0,.,N-1之间的数。之间的数。glBegin(GL_POINTS);for(int i = 0; i num; i+) / do it num timesglVertex2i(random(N), random(N);glEnd();选择不同的选择不同的A,B,N的值生成(的值生成(x,y)对。)对。案例分析案例分析 案例案例2.2 迭代函数系统介绍迭代函数系统介绍(难度难度 II)绘制绘制Sierpinski垫片时的操作就是迭代函数垫片时的操作就是迭代函数(IFS)的一个例子。许多计算机生成的有趣图的一个例子。许多计算机生成的有趣图形(如分形、形(如分形、Mandelbrot集合等)都是基于迭代函数变化生成的。如:集合等)都是基于迭代函数变化生成的。如: f(.) = 2(.); 倍增器,倍增它的参数倍增器,倍增它的参数; f(.) =

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论