OpenGL教程 用2D图形介绍OpenGL

OpenGL教程

用2D图形介绍OpenGL

1.设置OpenGL

要设置OpenGL,取决于您的编程平台,请阅读:

1.1示例1:设置OpenGL和GLUT(GL01Hello.cpp

确保您可以运行GL01Hello.cpp“ 如何使用C / C ++编写OpenGL程序 ”中描述的“ ”,如下所示:

1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
/ *
 * GL01Hello.cpp:测试OpenGL / GLUT C / C ++设置
 *使用MinGW / Cygwin在Eclipse CDT下测试,使用MinGW在CodeBlocks下测试
 *用-lfreeglut -lglu32 -lopengl32进行编译
 * / 
#include <windows.h>   //用于MS Windows 
#include <GL / glut.h>   // GLUT,包括glu.h和gl.h
 
/ *窗口重绘事件处理程序。当窗口第一次出现时回呼
   每当窗口需要重新着色时。* /
void display(){
   glClearColor(0.0f,0.0f,0.0f,1.0f); //将背景颜色设置为黑色和不透明 
   glClear(GL_COLOR_BUFFER_BIT);         //清除颜色缓冲区(背景)
 
   //绘制以原点 
   glBegin(GL_QUADS)为中心的红色1x1正方形 ;              //每组4个顶点组成一个四元组 
      glColor3f(1.0f,0.0f,0.0f); //红色 
      glVertex2f(-0.5f,-0.5f);    // x,y
      glVertex2f(0.5f,-0.5f);
      glVertex2f(0.5f,0.5f);
      glVertex2f(-0.5f,0.5f);
   glEnd();
 
   glFlush();  //现在渲染
}
 
/ *主要功能:GLUT作为控制台应用程序从main()开始运行* /
int main(int argc,char ** argv){
   glutInit(&argc,argv);                 //初始化GLUT 
   glutCreateWindow(“OpenGL Setup Test”); //使用给定的标题 
   glutInitWindowSize(320,320)创建一个窗口 ;   //设置窗口的初始宽度和高度 
   glutInitWindowPosition(50,50); //定位窗口的最左上角 
   glutDisplayFunc(display); //注册窗口重新绘制显示回调处理程序 
   glutMainLoop();           //输入事件处理循环
   返回0;
}
#include <windows.h>

标题“ windows.h”仅用于Windows平台。

#include <GL / glut.h>

我们还包括GLUT头文件,它确保包含“ glu.h”(用于GL实用程序)和“ gl.h”(用于核心OpenGL)。

程序的其余部分将在适当的时候解释。

2.介绍

OpenGL(开放图形库)是一种用于生成3D(包括2D)图形的跨平台,硬件加速的,与语言无关的工业标准API。现代计算机拥有专用GPU(图形处理单元)和自己的内存,可加速图形渲染速度。OpenGL是图形硬件的软件接口。换句话说,由您的应用程序发出的OpenGL图形渲染命令可以被引导到图形硬件并加速。

我们在OpenGL程序中使用3套库:

  1. 核心的OpenGL(GL) 由数百个命令,这与前缀“开头的gl”(如glColorglVertexglTranslateglRotate)。Core OpenGL通过一系列几何图元(如点,线和多边形)对对象进行建模。
  2. OpenGL实用程序库(GLU):建立在核心OpenGL之上,提供重要的实用程序(如设置摄像头视图和投影)以及更多建筑模型(如qradric曲面和多边形镶嵌)。GLU命令以前缀“ glu”开始(例如gluLookAt,,gluPerspective)。
  3. OpenGL实用程序工具包(GLUT):OpenGL被设计为独立于窗口系统或操作系统。GLUT需要与操作系统交互(例如创建窗口,处理键和鼠标输入); 它还提供了更多的建筑模型(如球体和圆环)。GLUT命令以“ glut”(例如glutCreatewindow,,glutMouseFunc的前缀开头GLUT是平台独立的,它建立在特定于平台的OpenGL扩展之上,例如用于X Window系统的GLX,用于Microsoft Window的WGL以及用于Mac OS的AGL,CGL或Cocoa。
    opengl.org引用:“GLUT专为构建中小型OpenGL程序而设计,虽然GLUT非常适合学习OpenGL和开发简单的OpenGL应用程序,但GLUT并不是一个全功能的工具包,因此需要复杂用户界面的大型应用程序最好使用本机窗口系统工具包,GLUT简单,简单,小巧。 “ 
    GLUT的替代方案包括SDL,....
  4. OpenGL Extension Wrangler Library(GLEW):“GLEW是一个跨平台的开源C / C ++扩展加载库,GLEW提供高效的运行时机制来确定哪些OpenGL扩展在目标平台上受支持。” 源代码和预编译二进制文件可在http://glew.sourceforge.net/找到一个名为“ glewinfo.exe”(在“ bin”目录下)的独立实用程序可用于生成图形系统支持的OpenGL函数列表。
  5. 其他。

3.顶点,原始和颜色

3.1例2:顶点,基元和颜色(GL02Primitive.cpp

尝试构建并运行这个OpenGL C / C ++程序:

1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/ *
 * GL02Primitive.cpp:顶点,原始和颜色
 *绘制简单的2D彩色形状:四边形,三角形和多边形。
 * / 
#include <windows.h>   //用于MS Windows 
#include <GL / glut.h>   // GLUT,包括glu.h和gl.h
 
/ *初始化OpenGL图形* /
void initGL(){
   //设置“清除”或背景色 
   glClearColor(0.0f,0.0f,0.0f,1.0f); //黑色和不透明
}
 
/ *窗口重绘事件处理程序。当窗口第一次出现时回呼
   每当窗口需要重新着色时。* /
void display(){
   glClear(GL_COLOR_BUFFER_BIT);   //用当前清除颜色清除颜色缓冲区
 
   //定义一对glBegin和glEnd 
   glBegin(GL_QUADS)中的形状 ;              //每组4个顶点组成一个四元组 
      glColor3f(1.0f,0.0f,0.0f); //红色 
      glVertex2f(-0.8f,0.1f);     //以逆时针(CCW)顺序定义顶点 
      glVertex2f(-0.2f,0.1f);     //使正常的(正面)面向你
      glVertex2f(-0.2f,0.7f);
      glVertex2f(-0.8f,0.7f);
 
      glColor3f(0.0f,1.0f,0.0f); // 绿色
      glVertex2f(-0.7f,-0.6f);
      glVertex2f(-0.1f,-0.6f);
      glVertex2f(-0.1f,0.0f);
      glVertex2f(-0.7f,0.0f);
 
      glColor3f(0.2f,0.2f,0.2f); // 深灰色
      glVertex2f(-0.9f,-0.7f);
      glColor3f(1.0f,1.0f,1.0f); //白色
      glVertex2f(-0.5f,-0.7f);
      glColor3f(0.2f,0.2f,0.2f); // 深灰色
      glVertex2f(-0.5f,-0.3f);
      glColor3f(1.0f,1.0f,1.0f); //白色
      glVertex2f(-0.9f,-0.3f);
   glEnd();
 
   在glBegin(GL_TRIANGLES);          //每组3个顶点形成一个三角形 
      glColor3f(0.0f,0.0f,1.0f); // 蓝色
      glVertex2f(0.1f,-0.6f);
      glVertex2f(0.7f,-0.6f);
      glVertex2f(0.4f,-0.1f);
 
      glColor3f(1.0f,0.0f,0.0f); //红色
      glVertex2f(0.3f,-0.4f);
      glColor3f(0.0f,1.0f,0.0f); // 绿色
      glVertex2f(0.9f,-0.4f);
      glColor3f(0.0f,0.0f,1.0f); // 蓝色
      glVertex2f(0.6f,-0.9f);
   glEnd();
 
   在glBegin(GL_POLYGON);            //这些顶点形成一个封闭的多边形 
      glColor3f(1.0f,1.0f,0.0f); // 黄色
      glVertex2f(0.4f,0.2f);
      glVertex2f(0.6f,0.2f);
      glVertex2f(0.7f,0.4f);
      glVertex2f(0.6f,0.6f);
      glVertex2f(0.4f,0.6f);
      glVertex2f(0.3f,0.4f);
   glEnd();
 
   glFlush();  //现在渲染
}
 
/ *主要功能:GLUT作为控制台应用程序从main()开始运行* /
int main(int argc,char ** argv){
   glutInit(&argc,argv);          //初始化GLUT 
   glutCreateWindow(“Vertex,Primitive&Color”);  //使用给定标题 
   glutInitWindowSize(320,320)创建窗口 ;   //设置窗口的初始宽度和高度 
   glutInitWindowPosition(50,50); //定位窗口的最左上角 
   glutDisplayFunc(display);       //为窗口重新绘制事件注册回调处理程序 
   initGL();                       //我们自己的OpenGL初始化 
   glutMainLoop();                 //输入事件处理循环
   返回0;
}

预期输出和坐标如下。请注意,4个形状具有纯色,并且2个形状从其顶点具有颜色混合。

 

我将在下面的章节中解释这个程序。

3.2作为状态机的OpenGL

OpenGL作为一个状态机运行,并维护一组状态变量(如前景色,背景色等等)。在状态机中,一旦设置了状态变量的值,该值就会一直存在,直到给出新的值。

例如,我们设置了“清理”(背景)颜色为黑色,一旦initGL()我们使用此设置display() 重复清除窗口display()每当有窗口重新绘制请求时都会调回) - 清除颜色在整个程序中不会更改。

//在initGL()中,设置“清除”或背景颜色 
glClearColor(0.0f,0.0f,0.0f,1.0f);  //黑色和不透明
 
//在display()中,用当前的“清除”颜色 
glClear(GL_COLOR_BUFFER_BIT)清除颜色缓冲区(即设置背景);

另一个例子:如果我们使用glColor函数将当前前景色设置为“红色”,那么“红色”将用于所有后续顶点,直到我们使用另一个glColor函数来改变前景色。

在状态机中,一切都应该保留,直到你明确地改变它!

3.3 OpenGL函数的命名约定

一个OpenGL的功能:

  • 以小写字母gl(对于核心OpenGL),glu(对于OpenGL实用程序)或glut(对于OpenGL Utility Toolkit)开头
  • 其次是该函数的目的,在骆驼情况下(初始大写),例如glColor指定绘图颜色,glVertex以定义顶点的位置。
  • 随后是参数的规格,例如,glColor3f需要三个float参数。glVectex2i需要两个int参数。
    (这是必需的,因为C语言不支持函数重载。不同版本的函数需要写入不同的参数列表。)

公约可以表述如下:

returnType  glFunction[234] [sifd]类型值,...);  // 2,3或4个参数
returnType  glFunction[234] [sifd] vtype * value);     //数组参数

函数可能需要2,3或4个参数,类型为sGLshort),iGLint),fGLfloat)或dGLdouble)。在“ v”(用于矢量)表示该参数保持在2,3,或4个元素的数组,并传递到函数作为数组的指针。

OpenGL定义了自己的数据类型

  • 有符号整数:GLbyte(8位),GLshort(16位),GLint(32位)。
  • 无符号整数:GLubyte(8位),GLushort(16位),GLuint(32位)。
  • 浮点数:GLfloat(32位),GLdouble(64位)GLclampfGLclampd(0.0到1.0之间)。
  • GLboolean (unsigned char,0代表false,非0代表true)。
  • GLsizei (32位非负整数)。
  • GLenum (32位枚举整数)。

OpenGL类型typedef在“ gl.h” 中定义如下:

typedef unsigned int GLenum;
typedef unsigned char GLboolean;
typedef unsigned int GLbitfield;
typedef void GLvoid;
typedef signed char GLbyte;         / * 1字节有符号* / 
typedef short GLshort;        / * 2字节签名* / 
typedef int GLint;          / * 4字节签名* / 
typedef unsigned char GLubyte;        / * 1字节无符号* / 
typedef unsigned short GLushort;       / * 2字节无符号* / 
typedef unsigned short GLuint;         / * 4字节无符号* / 
typedef int GLsizei;        / * 4字节签名* / 
typedef float GLfloat;        / *单精度浮点数* / 
typedef float GLclampf;       / *单精度浮点数[0,1] * /
typedef double GLdouble;       / *双精度浮点数* / 
typedef double GLclampd;       / *双精度浮点数[0,1] * /

OpenGL的常量以“ GL_”,“ GLU_”或“ GLUT_”开头,大写字母用下划线分隔,例如GL_COLOR_BUFFER_BIT

举些例子,

glVertex3f(1.1f,2.2f,3.3f);        // 3 GLfloat参数 
glVertex2i(4,5);                    // 2 GLint参数 
glColor4f(0.0f,0.0f,0.0f,1.0f);   // 4个GLfloat参数
 
GLdouble aVertex [] = {1.1,2.2,3.3};
glVertex3fv(aVertex);        // 3个GLfloat值的数组

3.4一次性初始化initGL()

initGL()意味着执行一次性OpenGL初始化任务,例如设置清除颜色。initGL()被调用一次(并且仅一次)main()

3.5回调处理程序显示()

该函数display()被称为回调事件处理程序事件处理程序提供对特定事件响应(如按键,鼠标单击,窗口绘制)。该函数旨在成为窗口绘制事件的处理程序OpenGL图形系统 响应于重新绘制窗口的窗口绘制请求(例如,首先出现窗口,最小化后窗口被恢复,窗口被调整大小)而回调。回调意味着该函数由系统调用,而不是由您的程序调用。display()display()

Display()当窗口第一次出现的运行每一次后续的再绘制请求。注意我们在display()函数中包含了OpenGL图形渲染代码,以便在窗口第一次出现时和每次重新绘制请求时重新绘制整个窗口。

3.6设置GLUT - main()

GLUT提供高级实用程序来简化OpenGL编程,尤其是与操作系统交互(例如创建窗口,处理键和鼠标输入)。上述程序中使用了以下GLUT函数:

  • glutInit:初始化GLUT,必须在其他GL / GLUT函数之前调用。它采用与。的相同的论点main()
    void glutInit(int * argc,char ** argv
  • glutCreateWindow:用给定的标题创建一个窗口。
    int glutCreateWindow(char * title
  • glutInitWindowSize:指定初始窗口宽度和高度(以像素为单位)。
    void glutInitWindowSize(int width,int height
  • glutInitWindowPosition:将初始窗口的左上角定位在(xy)处。以像素为单位的坐标(xy)以窗口坐标测量,即原点(0,0)位于屏幕的左上角; x轴指向右,y轴指向下。
    void glutInitWindowPosition(int x,int y
  • glutDisplayFunc:注册回调函数(或事件处理程序)以处理窗口绘制事件。OpenGL图形系统在收到窗口重新绘制请求时调用此处理程序。在这个例子中,我们将该函数注册display()为处理程序。
    void glutDisplayFunc(void(* func)(void))
  • glutMainLoop:进入无限事件处理循环,即让OpenGL图形系统等待事件(如重绘),并触发相应的事件处理程序(如display())。
    void glutMainLoop()

main()这个例子的 功能中:

glutInit(&argc,argv);
glutCreateWindow(“Vertex,Primitive&Color”);
glutInitWindowSize(320,320);
glutInitWindowPosition(50,50);

我们初始化GLUT并创建一个标题,初始大小和位置的窗口。

glutDisplayFunc(显示器);

我们注册display()函数作为window-paint事件的回调处理程序。也就是说,display()当窗口第一次出现时以及每当有重新绘制窗口的请求时运行。

initGL();

我们称之为initGL()执行所有的一次性初始化操作。在这个例子中,我们设置清除(背景)颜色一次,并在display()函数中重复使用它

glutMainLoop();

然后,我们将程序放入事件处理循环中,等待事件(如窗口绘制请求)触发相应的事件处理程序(如display())。

3.7颜色

我们使用glColor函数来设置前景色,并使用glClearColor函数来设置背景(或清除)颜色。

void glColor3f(GLfloat red,GLfloat green,GLfloat blue
void glColor3fv(GLfloat * colorRGB
void glColor4f(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha
void glColor4fv(GLfloat * colorRGBA
 
void glClearColor(GLclampf red,GLclampf green,GLclampf blue,GLclampf alpha// GLclampf,范围为0.0f至1.0f

笔记:

  • 颜色通常指定在float范围0.0f1.0f
  • 可以使用RGB(红 - 绿 - 蓝)或RGBA(红 - 绿 - 蓝 - 阿)组件指定颜色。'A'(或alpha)指定透明度(或不透明度)索引,值为1表示不透明(不透明且不能透视),值0表示总透明度。我们稍后会讨论alpha。

在上面的例子中,我们通过glClearColorin 设置背景颜色initGL(),其中R = 0,G = 0,B = 0(黑色)和A = 1(不透明且不能透视)。

//在initGL()中,设置“清除”或背景颜色 
glClearColor(0.0f,0.0f,0.0f,1.0f);  //黑色和相似

在中display(),我们glColor3f为后续顶点设置顶点颜色通孔例如,R = 1,G = 0,B = 0(红色)。

//在display()中,设置像素 
glColor3f(1.0f,0.0f,0.0f)的前景色 ;  //红色

3.8几何图元

在OpenGL中,一个对象由三角形,四边形,线段和点等几何图元组成。基元由一个或多个顶点组成。OpenGL支持以下原语:

的几何图元是通过指定通过其顶点定义glVertex功能,一对封闭的内glBeginglEnd

void glBegin(GLenum 形状
   void glVertex [234] [sifd]type  xtype  ytype  z,...)
   void glVertex [234] [sifd] vtype * coords
void glEnd()

glBegin指定的几何对象,诸如类型GL_POINTSGL_LINES GL_QUADSGL_TRIANGLES,和GL_POLYGON对于以“ S结尾的类型,可以在每个glBeginglEnd对中定义多个相同类型的对象例如,因为GL_TRIANGLES,每个三glVertex的定义一个三角形。

顶点通常以float精度指定这是因为整数不适合三角运算(需要执行转换等转换)。精度float足以执行中间操作,并将对象最终呈现为屏幕上的像素(分辨率为800x600,积分精度)。double精度往往是没有必要的。

在上面的例子中:

在glBegin(GL_QUADS);
   .... 4个四边形与12x glVertex().... 
glEnd();

我们定义了3个颜色四边形(GL_QUADS)和12个glVertex()函数。

glColor3f(1.0f,0.0f,0.0f);
glVertex2f(-0.8f,0.1f);
glVertex2f(-0.2f,0.1f);
glVertex2f(-0.2f,0.7f);
glVertex2f(-0.8f,0.7f);

我们将颜色设置为红色(R = 1,G = 0,B = 0)。所有后续的顶点将具有红色的颜色。请注意,在OpenGL中,颜色(和许多属性)应用于顶点而不是基本形状。原始形状的颜色是从顶点插入的

我们同样用绿色定义第二个四元组。

对于第三个四元组(如下所示),顶点具有不同的颜色。四边形曲面的颜色是从其顶点插入的,从而产生白色到深灰色的阴影,如输出中所示。

glColor3f(0.2f,0.2f,0.2f);  // 深灰色
glVertex2f(-0.9f,-0.7f);
glColor3f(1.0f,1.0f,1.0f);  //白色
glVertex2f(-0.5f,-0.7f);
glColor3f(0.2f,0.2f,0.2f);  // 深灰色
glVertex2f(-0.5f,-0.3f);
glColor3f(1.0f,1.0f,1.0f);  //白色 
glVertex2f(-0.9f,-0.3f);

3.9 2D坐标系和默认视图

下图显示了OpenGL 2D坐标系,它与位于左下角的原始2D笛卡尔坐标相对应。

默认的OpenGL二维裁剪区域(即摄像机捕捉的区域)是x和y在-1.0和1.0范围内的正交视图,即以原点为中心的2x2正方形。此裁剪区域被映射到屏幕上视口视口以像素为单位进行测量。

研究上述示例以说服您自己创建的2D图形在屏幕上正确定位。

4.剪辑区域和视口

尝试拖动窗口的角落以使其变大或变小。注意到所有的形状都是扭曲的。

我们可以通过回调处理程序来处理窗口的大小调整reshape(),该处理程序可以根据窗口的高宽比调整OpenGL裁剪区域。

剪切区域剪切区域是指在OpenGL坐标系中可以看到的区域(即由摄像机拍摄)。

该功能gluOrtho2D可用于设置2D正交视图的裁剪区域。裁剪区域外的对象将被裁剪掉,无法看到。

void gluOrtho2D(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top// OpenGL坐标中的默认裁剪区域为( -1.0,1.0 ,-1.0,1.0 
   //即,以原点为中心的2x2平方。

为了设置裁剪区域,我们需要发出如下一系列命令:我们首先选择所谓的投影矩阵进行操作,并将投影矩阵重置为标识。然后,我们通过选择所需剪贴区域的二维正交视图gluOrtho2D()

//设置为具有指定剪贴区域的二维正射投影 
glMatrixMode(GL_PROJECTION);      //选择用于操作的投影矩阵 
glLoadIdentity();                 //重置投影矩阵 
gluOrtho2D(-1.0,1.0,-1.0,1.0); //设置裁剪区域的左侧,右侧,底部,顶部

视口视口引用窗口(屏幕)上的显示区域,屏幕坐标(不包括标题栏)以像素为单位测量。

裁剪区域被映射到视口。我们可以使用glViewport函数来配置视口。

void glViewport(GLint xTopLeft,GLint yTopLeft,GLsizei width,GLsizei height

假设裁剪区域的(左,右,底部,顶部)是(-1.0,1.0,-1.0,1.0)(在OpenGL坐标中),而视口的(xTopLeft,xTopRight,width,height)是(0,0,640 ,480)(以屏幕坐标为像素),则左下角(-1.0,-1.0)映射到视口中的(0,0),右上角(1.0,1.0)映射到(639, 479)。很显然,如果裁剪区域和视口纵横比不相同,则形状将会失真。

请注意,在前面的示例中,320x320的窗口大小呈方形,其纵横比与默认的2x2方形剪切区域一致。

4.1示例3:裁剪区域和视口(GL03Viewport.cpp

1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/ *
 * GL03Viewport.cpp:裁剪区域和视口
 *实施重塑以确保相同的宽高比
 *裁剪区域和视口。
 * / 
#include <windows.h>   //用于MS Windows 
#include <GL / glut.h>   // GLUT,包括glu.h和gl.h
 
/ *初始化OpenGL图形* /
void initGL(){
   //设置“清除”或背景色 
   glClearColor(0.0f,0.0f,0.0f,1.0f); //黑色和不透明
}
 
void display(){
   glClear(GL_COLOR_BUFFER_BIT);   //用当前清除颜色清除颜色缓冲区
 
   //定义一对glBegin和glEnd 
   glBegin(GL_QUADS)中的形状 ;              //每组4个顶点组成一个四元组 
      glColor3f(1.0f,0.0f,0.0f); //红色 
      glVertex2f(-0.8f,0.1f);     //以逆时针(CCW)顺序定义顶点 
      glVertex2f(-0.2f,0.1f);     //使正常的(正面)面向你
      glVertex2f(-0.2f,0.7f);
      glVertex2f(-0.8f,0.7f);
 
      glColor3f(0.0f,1.0f,0.0f); // 绿色
      glVertex2f(-0.7f,-0.6f);
      glVertex2f(-0.1f,-0.6f);
      glVertex2f(-0.1f,0.0f);
      glVertex2f(-0.7f,0.0f);
 
      glColor3f(0.2f,0.2f,0.2f); // 深灰色
      glVertex2f(-0.9f,-0.7f);
      glColor3f(1.0f,1.0f,1.0f); //白色
      glVertex2f(-0.5f,-0.7f);
      glColor3f(0.2f,0.2f,0.2f); // 深灰色
      glVertex2f(-0.5f,-0.3f);
      glColor3f(1.0f,1.0f,1.0f); //白色
      glVertex2f(-0.9f,-0.3f);
   glEnd();
 
   在glBegin(GL_TRIANGLES);          //每组3个顶点形成一个三角形 
      glColor3f(0.0f,0.0f,1.0f); // 蓝色
      glVertex2f(0.1f,-0.6f);
      glVertex2f(0.7f,-0.6f);
      glVertex2f(0.4f,-0.1f);
 
      glColor3f(1.0f,0.0f,0.0f); //红色
      glVertex2f(0.3f,-0.4f);
      glColor3f(0.0f,1.0f,0.0f); // 绿色
      glVertex2f(0.9f,-0.4f);
      glColor3f(0.0f,0.0f,1.0f); // 蓝色
      glVertex2f(0.6f,-0.9f);
   glEnd();
 
   在glBegin(GL_POLYGON);            //这些顶点形成一个封闭的多边形 
      glColor3f(1.0f,1.0f,0.0f); // 黄色
      glVertex2f(0.4f,0.2f);
      glVertex2f(0.6f,0.2f);
      glVertex2f(0.7f,0.4f);
      glVertex2f(0.6f,0.6f);
      glVertex2f(0.4f,0.6f);
      glVertex2f(0.3f,0.4f);
   glEnd();
 
   glFlush();  //现在渲染
}
 
/ *处理程序的窗口重新大小事件。窗口第一次出现时调用回来
   每当窗口重新调整其宽度和高度* / 
void reshape(GLsizei width,GLsizei height){   // GLsizei为非负整数
   //计算新窗口的宽高比 
   if(height == 0)height = 1;                //防止被0除
   GLfloat aspect =(GLfloat)width /(GLfloat)height;
 
   //设置视口覆盖新窗口
   glViewport(0,0,width,height);
 
   //设置裁剪区域的长宽比以匹配视口 
   glMatrixMode(GL_PROJECTION);  //在Projection矩阵上操作 
   glLoadIdentity();             //重置投影矩阵
   if(width> = height){
     // aspect> = 1,将高度从-1更改为1,宽度更大
      gluOrtho2D(-1.0 *方面,1.0 *方面,-1.0,1.0);
   } else {
      // aspect <1,设置宽度为-1到1,高度更大
     gluOrtho2D(-1.0,1.0,-1.0 /方面,1.0 /方面);
   }
}
 
/ *主要功能:GLUT作为控制台应用程序从main()开始运行* /
int main(int argc,char ** argv){
   glutInit(&argc,argv);          //初始化GLUT 
   glutInitWindowSize(640,480);   //设置窗口的初始宽度和高度 - 非方形 
   glutInitWindowPosition(50,50); //定位窗口的最左上角 
   glutCreateWindow(“Viewport Transform”);  //使用给定的标题 
   glutDisplayFunc(display)创建窗口 ;       //为窗口重新绘制事件注册回调处理程序
   glutReshapeFunc(reshape);        //注册窗口重新调整事件的回调处理程序 
   initGL();                       //我们自己的OpenGL初始化 
   glutMainLoop();                 //输入无限事件处理循环
   返回0;
}

reshape()功能,这就是所谓背面当窗口第一次出现的时候的尺寸重新调整窗口,可用于确保限幅区域和视口之间是一致的纵横比,如示于上面的示例。图形子系统将窗口的宽度和高度(以像素为单位)传递给reshape()

GLfloat aspect =(GLfloat)width /(GLfloat)height;

我们计算新的重新调整大小的窗口的纵横比,给定它的新图形子系统width并将height提供给回调函数reshape()

glViewport(0,0,width,height);

我们将视口设置为覆盖整个新的重新调整大小的窗口,以像素为单位。
尝试将视口设置为仅覆盖窗口的四分之一(右下角的qradrant)glViewport(0, 0, width/2, height/2)

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(width> = height){
   gluOrtho2D(-1.0 *方面,1.0 *方面,-1.0,1.0);
} else {
   gluOrtho2D(-1.0,1.0,-1.0 /方面,1.0 /方面);
}

我们将裁剪区域的纵横比设置为与视口相匹配。为了设置剪辑区域,我们首先选择通过投影矩阵进行操作glMatrixMode(GL_PROJECTION)OpenGL有两个矩阵,一个投影矩阵(处理摄像机投影,例如设置剪辑区域)和一个模型视图矩阵(用于将物体从其本地空间转换为公共世界空间)。我们通过重置投影矩阵glLoadIdentity()

最后,我们调用gluOrtho2D()设置与视口匹配的宽高比的剪贴区域。短边的范围从-1到+1,如下所示:

我们需要注册reshape()通过与GLUT回调处理程序glutReshapeFunc()main(),如下所示:

int main(int argc,char ** argv){
   glutInitWindowSize(640,480);
   ......
   glutReshapeFunc(重塑);
}

在上面的main()函数中,我们指定初始窗口大小640x480,这是非方形的。尝试重新调整窗口大小并观察更改。

请注意,窗口首次出现时reshape()至少运行一次然后每当窗口重新塑形时就会被回调。另一方面,initGL()运行一次(也只有一次); 以及display()响应于窗口重新绘制请求的运行(例如,在窗口重新调整大小之后)。

5.翻译和旋转

在上面的示例中,我们通过分别定义相同的原点(称为世界空间来定义每个形状的顶点我花了很长时间才弄清楚这些顶点的绝对坐标。

相反,我们可以通过定义它们各自的顶点(称为模型空间局部空间来定位每个形状然后,我们可以使用平移和/或旋转将形状定位在世界空间中的所需位置,如下面的修改display()函数所示。

5.1例4:平移和旋转(GL04ModelTransform.cpp

1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/ *
 * GL04ModelTransform.cpp:模型变换 - 平移和旋转
 *将图元从模型空间转换到世界空间。
 * / 
#include <windows.h>   //用于MS Windows 
#include <GL / glut.h>   // GLUT,包括glu.h和gl.h
 
/ *初始化OpenGL图形* /
void initGL(){
   //设置“清除”或背景色 
   glClearColor(0.0f,0.0f,0.0f,1.0f); //黑色和不透明
}
 
/ *窗口重绘事件处理程序。当窗口第一次出现时回呼
   每当窗口需要重新着色时。* /
void display(){
   glClear(GL_COLOR_BUFFER_BIT);    //清除颜色缓冲区
   glMatrixMode(GL_MODELVIEW);      //在Model-View矩阵上操作 
   glLoadIdentity();                //重置模型视图矩阵
 
   glTranslatef(-0.5f,0.4f,0.0f); //向左和向上翻译 
   glBegin(GL_QUADS);               //每组4个顶点组成一个四元组 
      glColor3f(1.0f,0.0f,0.0f);  //红色 
      glVertex2f(-0.3f,-0.3f);     //以逆时针(CCW)顺序定义顶点 
      glVertex2f(0.3f,-0.3f);     //使正常的(正面)面向你
      glVertex2f(0.3f,0.3f);
      glVertex2f(-0.3f,0.3f);
   glEnd();
 
   glTranslatef(0.1f,-0.7f,0.0f); //向右和向下翻译 
   glBegin(GL_QUADS);               //每组4个顶点组成一个四元组 
      glColor3f(0.0f,1.0f,0.0f); // 绿色
      glVertex2f(-0.3f,-0.3f);
      glVertex2f(0.3f,-0.3f);
      glVertex2f(0.3f,0.3f);
      glVertex2f(-0.3f,0.3f);
   glEnd();
 
   glTranslatef(-0.3f,-0.2f,0.0f); //向左和向下翻译 
   glBegin(GL_QUADS);                //每组4个顶点组成一个四元组 
      glColor3f(0.2f,0.2f,0.2f); // 深灰色
      glVertex2f(-0.2f,-0.2f);
      glColor3f(1.0f,1.0f,1.0f); //白色
      glVertex2f(0.2f,-0.2f);
      glColor3f(0.2f,0.2f,0.2f); // 深灰色
      glVertex2f(0.2f,0.2f);
      glColor3f(1.0f,1.0f,1.0f); //白色
      glVertex2f(-0.2f,0.2f);
   glEnd();
 
   glTranslatef(1.1f,0.2f,0.0f); //向右和向上翻译 
   glBegin(GL_TRIANGLES);          //每组3个顶点形成一个三角形 
      glColor3f(0.0f,0.0f,1.0f); // 蓝色
      glVertex2f(-0.3f,-0.2f);
      glVertex2f(0.3f,-0.2f);
      glVertex2f(0.0f,0.3f);
   glEnd();
 
   glTranslatef(0.2f,-0.3f,0.0f);     //向右和向下翻译 
   glRotatef(180.0f,0.0f,0.0f,1.0f); //旋转180度 
      glBegin(GL_TRIANGLES);               //每组3个顶点形成一个三角形 
      glColor3f(1.0f,0.0f,0.0f); //红色
      glVertex2f(-0.3f,-0.2f);
      glColor3f(0.0f,1.0f,0.0f); // 绿色
      glVertex2f(0.3f,-0.2f);
      glColor3f(0.0f,0.0f,1.0f); // 蓝色
      glVertex2f(0.0f,0.3f);
   glEnd();
 
   glRotatef(-180.0f,0.0f,0.0f,1.0f); //撤销上一次旋转 
   glTranslatef(-0.1f,1.0f,0.0f);      //向右和向下翻译 
   glBegin(GL_POLYGON);                  //顶点形成一个封闭的多边形 
      glColor3f(1.0f,1.0f,0.0f); // 黄色
      glVertex2f(-0.1f,-0.2f);
      glVertex2f(0.1f,-0.2f);
      glVertex2f(0.2f,0.0f);
      glVertex2f(0.1f,0.2f);
      glVertex2f(-0.1f,0.2f);
      glVertex2f(-0.2f,0.0f);
   glEnd();
 
   glFlush();   //现在渲染
}
 
/ *处理程序的窗口重新大小事件。窗口第一次出现时调用回来
   每当窗口重新调整其宽度和高度* / 
void reshape(GLsizei width,GLsizei height){   // GLsizei为非负整数
   //计算新窗口的宽高比 
   if(height == 0)height = 1;                //防止被0除
   GLfloat aspect =(GLfloat)width /(GLfloat)height;
 
   //设置视口覆盖新窗口
   glViewport(0,0,width,height);
 
   //设置裁剪区域的长宽比以匹配视口 
   glMatrixMode(GL_PROJECTION);  //在投影矩阵上操作
   glLoadIdentity();
   if(width> = height){
     // aspect> = 1,将高度从-1更改为1,宽度更大
      gluOrtho2D(-1.0 *方面,1.0 *方面,-1.0,1.0);
   } else {
      // aspect <1,设置宽度为-1到1,高度更大
     gluOrtho2D(-1.0,1.0,-1.0 /方面,1.0 /方面);
   }
}
 
/ *主要功能:GLUT作为控制台应用程序从main()开始运行* /
int main(int argc,char ** argv){
   glutInit(&argc,argv);          //初始化GLUT 
   glutInitWindowSize(640,480);   //设置窗口的初始宽度和高度 - 非方形 
   glutInitWindowPosition(50,50); //定位窗口的左上角 
   glutCreateWindow(“Model Transform”);  //使用给定的标题 
   glutDisplayFunc(display)创建窗口 ;       //为窗口重新绘制事件注册回调处理程序 
   glutReshapeFunc(reshape);       //注册窗口重新调整事件的回调处理程序 
   initGL();                       //我们自己的OpenGL初始化 
   glutMainLoop();                 //输入无限事件处理循环
   返回0;
}
glMatrixMode(GL_MODELVIEW); //在模型视图矩阵 
glLoadIdentity()上操作;           // 重启

平移和旋转是所谓的模型变换的一部分,它从物体从局部空间(或模型空间)转换到共同的世界空间。为了进行模型转换,我们将矩阵模式设置为模式视图矩阵(GL_MODELVIEW)并重置矩阵。(回想一下在前面的例子中,我们将矩阵模式设置为投影矩阵(GL_PROJECTION)来设置剪切区域。)

OpenGL是作为一个状态机运行的。也就是说,一旦设置了状态,状态的值就会一直保持到它被更改。换句话说,一旦坐标被翻译或旋转,所有后续的操作将基于这个坐标。

翻译通过glTranslate功能完成

void gltranslatef(GLfloat x,GLfloat y,GLfloat z//其中(x,y,z)是平移向量

请注意,glTranslatef函数必须放在glBegin之外glEnd,因为glColor它可以放在glBegin里面glEnd

旋转是通过glRotatef函数完成的

void glRotatef(GLfloat angle,GLfloat x,GLfloat y,GLfloat z//其中angle指定旋转度,(xyz)形成旋转轴。

请注意,旋转角度在OpenGL中以度(而不是弧度)度量。

在上面的例子中,我们在xy平面内(z = 0)进行平移,并围绕z轴(与xy平面垂直)旋转。

6.动画

6.1空闲功能

要执行动画(例如,旋转形状),可以idle()通过glutIdleFunc命令向GLUT 注册回调处理程序idle()当没有其他事件需要处理时,图形系统会回调函数。

void glutIdleFunc(void(* func)(void))

在这个idle()函数中,你可以发出glutPostRedisplay命令来发布一个窗口重新绘制请求,而这个请求又会激活display()函数。

void idle(){
   glutPostRedisplay();   //发布重新绘制请求以激活display() 
}

请注意,上述内容等同于注册display()idle功能。

//主要 
glutIdleFunc(显示);

6.2双缓冲

双缓冲使用两个显示缓冲区来平滑动画。下一个屏幕准备在后台缓冲区中,而当前屏幕保存在前台缓冲区中。准备工作完成后,您可以使用glutSwapBuffer命令交换前后缓冲区。

要使用双缓冲,您需要进行两项更改:

  1. main()创建窗口之前包含这一行:
    glutInitDisplayMode(GLUT_DOUBLE);  //设置双缓冲模式
  2. display()函数中,替换glFlush()glutSwapBuffers(),交换前后缓冲区。

动画中应该使用双缓冲。对于静态显示,单缓冲就足够了。(许多图形硬件总是双重缓冲,所以很难看出差异。)

6.3示例5:使用空闲函数的动画(GL05IdleFunc.cpp

以下程序使用双缓冲空闲功能旋转我们前面示例中创建的所有形状。

1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/ *
 * GL05IdleFunc.cpp:平移和旋转
 *将图元从其模型空间转换到世界空间(模型转换)。
 * / 
#include <windows.h>   //用于MS Windows 
#include <GL / glut.h>   // GLUT,包括glu.h和gl.h
 
//全局变量
GLfloat角度= 0.0f;  //形状的当前旋转角度
 
/ *初始化OpenGL图形* /
void initGL(){
   //设置“清除”或背景色 
   glClearColor(0.0f,0.0f,0.0f,1.0f); //黑色和不透明
}
 
/ *当没有其他事件需要处理时回叫* /
void idle(){
   glutPostRedisplay();   //发布重新绘制请求以激活display() 
}
 
/ *窗口重绘事件处理程序。当窗口第一次出现时回呼
   每当窗口需要重新着色时。* /
void display(){
   glClear(GL_COLOR_BUFFER_BIT);   //清除颜色缓冲区
   glMatrixMode(GL_MODELVIEW);     //在Model-View矩阵上操作 
   glLoadIdentity();               //重置模型视图矩阵
 
    glPushMatrix();                     //保存模型视图矩阵设置 
   glTranslatef(-0.5f,0.4f,0.0f);    //翻译 
   glRotatef(角度,0.0f,0.0f,1.0f); //以度数角度旋转 
   glBegin(GL_QUADS);                  //每组4个顶点组成一个四元组 
      glColor3f(1.0f,0.0f,0.0f);     //红色
      glVertex2f(-0.3f,-0.3f);
      glVertex2f(0.3f,-0.3f);
      glVertex2f(0.3f,0.3f);
      glVertex2f(-0.3f,0.3f);
   glEnd();
   glPopMatrix();                      //恢复模型视图矩阵
 
   glPushMatrix();                     //保存模型视图矩阵设置 
   glTranslatef(-0.4f,-0.3f,0.0f);   //翻译 
   glRotatef(角度,0.0f,0.0f,1.0f); //以角度旋转角度
   在glBegin(GL_QUADS);
      glColor3f(0.0f,1.0f,0.0f); // 绿色
      glVertex2f(-0.3f,-0.3f);
      glVertex2f(0.3f,-0.3f);
      glVertex2f(0.3f,0.3f);
      glVertex2f(-0.3f,0.3f);
   glEnd();
   glPopMatrix();                      //恢复模型视图矩阵
 
   glPushMatrix();                     //保存模型视图矩阵设置 
   glTranslatef(-0.7f,-0.5f,0.0f);   //翻译 
   glRotatef(角度,0.0f,0.0f,1.0f); //以角度旋转角度
   在glBegin(GL_QUADS);
      glColor3f(0.2f,0.2f,0.2f); // 深灰色
      glVertex2f(-0.2f,-0.2f);
      glColor3f(1.0f,1.0f,1.0f); //白色
      glVertex2f(0.2f,-0.2f);
      glColor3f(0.2f,0.2f,0.2f); // 深灰色
      glVertex2f(0.2f,0.2f);
      glColor3f(1.0f,1.0f,1.0f); //白色
      glVertex2f(-0.2f,0.2f);
   glEnd();
   glPopMatrix();                      //恢复模型视图矩阵
 
   glPushMatrix();                     //保存模型视图矩阵设置 
   glTranslatef(0.4f,-0.3f,0.0f);    //翻译 
   glRotatef(角度,0.0f,0.0f,1.0f); //以角度旋转角度
   在glBegin(GL_TRIANGLES);
      glColor3f(0.0f,0.0f,1.0f); // 蓝色
      glVertex2f(-0.3f,-0.2f);
      glVertex2f(0.3f,-0.2f);
      glVertex2f(0.0f,0.3f);
   glEnd();
   glPopMatrix();                      //恢复模型视图矩阵
 
   glPushMatrix();                     //保存模型视图矩阵设置 
   glTranslatef(0.6f,-0.6f,0.0f);    //翻译 
   glRotatef(180.0f +角度,0.0f,0.0f,1.0f); //旋转180度+角度
   在glBegin(GL_TRIANGLES);
      glColor3f(1.0f,0.0f,0.0f); //红色
      glVertex2f(-0.3f,-0.2f);
      glColor3f(0.0f,1.0f,0.0f); // 绿色
      glVertex2f(0.3f,-0.2f);
      glColor3f(0.0f,0.0f,1.0f); // 蓝色
      glVertex2f(0.0f,0.3f);
   glEnd();
   glPopMatrix();                      //恢复模型视图矩阵
 
   glPushMatrix();                     //保存模型视图矩阵设置 
   glTranslatef(0.5f,0.4f,0.0f);     //翻译 
   glRotatef(角度,0.0f,0.0f,1.0f); //以角度旋转角度
   在glBegin(GL_POLYGON);
      glColor3f(1.0f,1.0f,0.0f); // 黄色
      glVertex2f(-0.1f,-0.2f);
      glVertex2f(0.1f,-0.2f);
      glVertex2f(0.2f,0.0f);
      glVertex2f(0.1f,0.2f);
      glVertex2f(-0.1f,0.2f);
      glVertex2f(-0.2f,0.0f);
   glEnd();
   glPopMatrix();                      //恢复模型视图矩阵
 
   glutSwapBuffers();   //双缓冲 - 交换前后缓冲区
 
   //每次显示后改变旋转角度() 
   angle + = 0.2f;
}
 
/ *处理程序的窗口重新大小事件。窗口第一次出现时调用回来
   每当窗口重新调整其宽度和高度* / 
void reshape(GLsizei width,GLsizei height){   // GLsizei为非负整数
   //计算新窗口的宽高比 
   if(height == 0)height = 1;                //防止被0除
   GLfloat aspect =(GLfloat)width /(GLfloat)height;
 
   //设置视口覆盖新窗口
   glViewport(0,0,width,height);
 
   //设置裁剪区域的长宽比以匹配视口 
   glMatrixMode(GL_PROJECTION);  //在投影矩阵上操作
   glLoadIdentity();
   if(width> = height){
     // aspect> = 1,将高度从-1更改为1,宽度更大
      gluOrtho2D(-1.0 *方面,1.0 *方面,-1.0,1.0);
   } else {
      // aspect <1,设置宽度为-1到1,高度更大
     gluOrtho2D(-1.0,1.0,-1.0 /方面,1.0 /方面);
   }
}
 
/ *主要功能:GLUT作为控制台应用程序从main()开始运行* /
int main(int argc,char ** argv){
   glutInit(&argc,argv);          //初始化GLUT 
   glutInitDisplayMode(GLUT_DOUBLE);  //启用双缓冲模式 
   glutInitWindowSize(640,480);   //设置窗口的初始宽度和高度 - 非方形 
   glutInitWindowPosition(50,50); //定位窗口的初始左上角 
   glutCreateWindow(“通过空闲函数动画”);  //使用给定的标题 
   glutDisplayFunc(display)创建窗口 ;       //为窗口重新绘制事件注册回调处理程序 
   glutReshapeFunc(reshape);       //为窗口重新大小事件注册回调处理程序
   glutIdleFunc(idle);             //注册回调处理程序,如果没有其他事件
   initGL();                       //我们自己的OpenGL初始化 
   glutMainLoop();                 //输入无限事件处理循环
   返回0;
}

在上面的例子中,我们glPushMatrix用来保存当前状态,执行转换并通过恢复保存的状态,而不是累积所有翻译并撤消旋转glPopMatrix(在上面的例子中,我们也可以使用glLoadIdentity在下一次转换之前重置矩阵。)

GL浮块角度= 0.0f;  //形状的当前旋转角度

我们定义了一个全局变量,angle用于跟踪所有形状的旋转角度。我们稍后将使用glRotatef旋转所有形状到这个角度。

角度+ = 0.2f;

在每次刷新(in display()结束时,我们更新所有形状的旋转角度。

glutSwapBuffers();                 //交换前后帧缓冲区
 
glutInitDisplayMode(GLUT_DOUBLE);  //在main()中,启用双缓冲模式

而不是glFlush()立即刷新帧缓冲器glutSwapBuffer()供显示,我们启用双缓冲并用于在VSync期间交换前后缓冲器以平滑显示。

void idle(){
   glutPostRedisplay();   //发布重新绘制请求以激活display()
}
 
glutIdleFunc(空闲);       //在main()中 - 注册回调处理程序,如果没有其他事件

我们定义一个idle()函数,display()如果没有未完成的事件发布重新绘制请求并调用我们idle()main()via中注册这个函数glutIdleFunc()

6.4双缓冲和刷新率

启用双缓冲时,glutSwapBuffers与屏幕刷新间隔(VSync)同步。也就是说,当显示器放置一个新的帧时,缓冲区将被同时交换。因此,idle()功能最多可以以与显示器刷新率相同的速率刷新动画(60Hz用于LCD / LED显示器)。它可以以显示器刷新频率的一半(如果计算花费超过1个刷新间隔),三分之一,四分之一等等操作,因为它需要等待VSync。

6.5定时器功能

有了idle(),我们无法控制刷新间隔。我们可以Timer()通过GLUT 注册一个函数glutTimerFuncTimer()功能将以指定的固定时间间隔回叫。

void glutTimerFunc(unsigned int millis,void(* func)(int value),value//其中millis是延迟毫秒数,将被传递给定时器函数。

6.6例6:通过定时器功能的动画(GL06TimerFunc.cpp

以下修改将先前示例中创建的所有形状每30毫秒逆时针旋转2度。

1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/ *
 * GL06TimerFunc.cpp:平移和旋转
 *将图元从其模型空间转换到世界空间(模型转换)。
 * / 
#include <windows.h>   //用于MS Windows 
#include <GL / glut.h>   // GLUT,包括glu.h和gl.h
 
//全局变量 
GLfloat angle = 0.0f;  //形状的旋转角度 
int refreshMills = 30; //以毫秒为单位刷新间隔
 
/ *初始化OpenGL图形* /
void initGL(){
   //设置“清除”或背景色 
   glClearColor(0.0f,0.0f,0.0f,1.0f); //黑色和不透明
}
 
/ *定时器过期时返回* /
void Timer(int value){
   glutPostRedisplay();      //发布重新绘制请求以激活display() 
   glutTimerFunc(refreshMills,Timer,0); //接下来的定时器调用毫秒 
}
 
/ *窗口重绘事件处理程序。当窗口第一次出现时回呼
   每当窗口需要重新着色时。* /
void display(){
   glClear(GL_COLOR_BUFFER_BIT);   //清除颜色缓冲区 
   glMatrixMode(GL_MODELVIEW);     //在Model-View矩阵上操作 
   glLoadIdentity();               //重置模型视图矩阵
 
   glPushMatrix();                     //保存模型视图矩阵设置 
   glTranslatef(-0.5f,0.4f,0.0f);    //翻译 
   glRotatef(角度,0.0f,0.0f,1.0f); //以度数角度旋转 
   glBegin(GL_QUADS);                  //每组4个顶点组成一个四元组 
      glColor3f(1.0f,0.0f,0.0f);     //红色
      glVertex2f(-0.3f,-0.3f);
      glVertex2f(0.3f,-0.3f);
      glVertex2f(0.3f,0.3f);
      glVertex2f(-0.3f,0.3f);
   glEnd();
   glPopMatrix();                      //恢复模型视图矩阵
 
   glPushMatrix();                     //保存模型视图矩阵设置 
   glTranslatef(-0.4f,-0.3f,0.0f);   //翻译 
   glRotatef(角度,0.0f,0.0f,1.0f); //以角度旋转角度
   在glBegin(GL_QUADS);
      glColor3f(0.0f,1.0f,0.0f); // 绿色
      glVertex2f(-0.3f,-0.3f);
      glVertex2f(0.3f,-0.3f);
      glVertex2f(0.3f,0.3f);
      glVertex2f(-0.3f,0.3f);
   glEnd();
   glPopMatrix();                      //恢复模型视图矩阵
 
   glPushMatrix();                     //保存模型视图矩阵设置 
   glTranslatef(-0.7f,-0.5f,0.0f);   //翻译 
   glRotatef(角度,0.0f,0.0f,1.0f); //以角度旋转角度
   在glBegin(GL_QUADS);
      glColor3f(0.2f,0.2f,0.2f); // 深灰色
      glVertex2f(-0.2f,-0.2f);
      glColor3f(1.0f,1.0f,1.0f); //白色
      glVertex2f(0.2f,-0.2f);
      glColor3f(0.2f,0.2f,0.2f); // 深灰色
      glVertex2f(0.2f,0.2f);
      glColor3f(1.0f,1.0f,1.0f); //白色
      glVertex2f(-0.2f,0.2f);
   glEnd();
   glPopMatrix();                      //恢复模型视图矩阵
 
   glPushMatrix();                     //保存模型视图矩阵设置 
   glTranslatef(0.4f,-0.3f,0.0f);    //翻译 
   glRotatef(角度,0.0f,0.0f,1.0f); //以角度旋转角度
   在glBegin(GL_TRIANGLES);
      glColor3f(0.0f,0.0f,1.0f); // 蓝色
      glVertex2f(-0.3f,-0.2f);
      glVertex2f(0.3f,-0.2f);
      glVertex2f(0.0f,0.3f);
   glEnd();
   glPopMatrix();                      //恢复模型视图矩阵
 
   glPushMatrix();                     //保存模型视图矩阵设置 
   glTranslatef(0.6f,-0.6f,0.0f);    //翻译 
   glRotatef(180.0f +角度,0.0f,0.0f,1.0f); //旋转180度+角度
   在glBegin(GL_TRIANGLES);
      glColor3f(1.0f,0.0f,0.0f); //红色
      glVertex2f(-0.3f,-0.2f);
      glColor3f(0.0f,1.0f,0.0f); // 绿色
      glVertex2f(0.3f,-0.2f);
      glColor3f(0.0f,0.0f,1.0f); // 蓝色
      glVertex2f(0.0f,0.3f);
   glEnd();
   glPopMatrix();                      //恢复模型视图矩阵
 
   glPushMatrix();                     //保存模型视图矩阵设置 
   glTranslatef(0.5f,0.4f,0.0f);     //翻译 
   glRotatef(角度,0.0f,0.0f,1.0f); //以角度旋转角度
   在glBegin(GL_POLYGON);
      glColor3f(1.0f,1.0f,0.0f); // 黄色
      glVertex2f(-0.1f,-0.2f);
      glVertex2f(0.1f,-0.2f);
      glVertex2f(0.2f,0.0f);
      glVertex2f(0.1f,0.2f);
      glVertex2f(-0.1f,0.2f);
      glVertex2f(-0.2f,0.0f);
   glEnd();
   glPopMatrix();                      //恢复模型视图矩阵
 
   glutSwapBuffers();   //双缓冲 - 交换前后缓冲区
 
   //每次显示后改变旋转角度()
   角度+ = 2.0f;
}
 
/ *处理程序的窗口重新大小事件。窗口第一次出现时调用回来
   每当窗口重新调整其宽度和高度* / 
void reshape(GLsizei width,GLsizei height){   // GLsizei为非负整数
   //计算新窗口的宽高比 
   if(height == 0)height = 1;                //防止被0除
   GLfloat aspect =(GLfloat)width /(GLfloat)height;
 
   //设置视口覆盖新窗口
   glViewport(0,0,width,height);
 
   //设置裁剪区域的长宽比以匹配视口 
   glMatrixMode(GL_PROJECTION);  //在投影矩阵上操作
   glLoadIdentity();
   if(width> = height){
     // aspect> = 1,将高度从-1更改为1,宽度更大
      gluOrtho2D(-1.0 *方面,1.0 *方面,-1.0,1.0);
   } else {
      // aspect <1,设置宽度为-1到1,高度更大
     gluOrtho2D(-1.0,1.0,-1.0 /方面,1.0 /方面);
   }
}
 
/ *主要功能:GLUT作为控制台应用程序从main()开始运行* /
int main(int argc,char ** argv){
   glutInit(&argc,argv);          //初始化GLUT 
   glutInitDisplayMode(GLUT_DOUBLE);  //启用双缓冲模式 
   glutInitWindowSize(640,480);   //设置窗口的初始宽度和高度 - 非方形 
   glutInitWindowPosition(50,50); //定位窗口的初始左上角 
   glutCreateWindow(“通过空闲函数动画”);  //使用给定的标题 
   glutDisplayFunc(display)创建窗口 ;       //为窗口重新绘制事件注册回调处理程序 
   glutReshapeFunc(reshape);       //为窗口重新大小事件注册回调处理程序
   glutTimerFunc(0,Timer,0);      //立即第一个计时器
   initGL();                       //我们自己的OpenGL初始化 
   glutMainLoop();                 //输入无限事件处理循环
   返回0;
}
void Timer(int value){
   glutPostRedisplay();                   //发布重新绘制请求以激活display() 
   glutTimerFunc(refreshMills,Timer,0); //接下来的定时器调用毫秒 
}

我们用一个idle()函数来替换函数,该timer()函数display()在计时器过期后发布重新绘制请求来调用

glutTimerFunc(0,Timer,0);     //立即第一个计时器

main(),我们注册该timer()功能,并timer()立即激活(初始计时器= 0)。

6.7更多GLUT功能

  • glutInitDisplayMode:请求显示与所述指定的模式,如彩色模式(GLUT_RGBGLUT_RGBAGLUT_INDEX),单/双缓冲(GLUT_SINGLEGLUT_DOUBLE),使深度(GLUT_DEPTH),加入了与一个位OR“ |”。
    void glutInitDisplayMode(unsigned int displayMode

    例如,

    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
       //使用RGBA颜色,启用双缓冲并启用深度缓冲区

6.8例7:弹跳球(GL07BouncingBall.cpp

这个例子显示了一个在窗口内弹跳的球。请注意,在OpenGL中,圆不是原始的几何形状。这个例子TRIANGLE_FAN用来组成一个圆。

1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/ *
 * GL07BouncingBall.cpp:一个在窗户内弹跳的球
 * / 
#include <windows.h>   // MS窗口 
#include <GL / glut.h>   // GLUT,包括glu.h和gl.h 
#include < Math.h >      //需要sin,cos
#define PI 3.14159265f
 
//全局变量 
char title [] =“Bouncing Ball(2D)”;  //窗口模式的标题 
int windowWidth = 640;     //窗口模式的宽度 
int windowHeight = 480;     //窗口模式的高度 
int windowPosX = 50;      //窗口模式的左上角x 
int windowPosY = 50;      //窗口模式的左上角y
 
GLfloat ballRadius = 0.5f;   //弹跳球的半径 
GLfloat ballX = 0.0f;         //球的中心(x,y)位置
GLfloat ballY = 0.0f;
GLfloat ballXMax,ballXMin,ballYMax,ballYMin; //球的中心(x,y)边界 
GLfloat xSpeed = 0.02f;      //球在x和y方向的速度
GLfloat ySpeed = 0.007f;
int refreshMillis = 30;      //以毫秒为单位刷新周期
 
//投影裁剪区域
GLdouble clipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop;
 
/ *初始化OpenGL图形* /
void initGL(){
   glClearColor(0.0,0.0,0.0,1.0); //将背景(清晰)颜色设置为黑色
}
 
/ *窗口重新绘制事件的回调处理程序* /
void display(){
   glClear(GL_COLOR_BUFFER_BIT);  //清除颜色缓冲区 
   glMatrixMode(GL_MODELVIEW);    //使用模型视图矩阵 
   glLoadIdentity();              //重置模型视图矩阵
 
   glTranslatef(ballX,ballY,0.0f);  //转换为(xPos,yPos)
   //使用三角形段形成一个圆
   在glBegin(GL_TRIANGLE_FAN);
      glColor3f(0.0f,0.0f,1.0f);  //蓝色 
      glVertex2f(0.0f,0.0f);       //圆的中心
      int numSegments = 100;
      GLfloat角;
      for(int i = 0; i <= numSegments; i ++){ //最后一个顶点与第一个顶点 
         角度相同 = i * 2.0f * PI / numSegments;  // 360度为所有部分
         glVertex2f(cos(angle)* ballRadius,sin(angle)* ballRadius);
      }
   glEnd();
 
   glutSwapBuffers();  //交换前端和后端缓冲区(双缓冲模式)
 
   //动画控制 - 计算下一次刷新的位置
   ballX + = xSpeed;
   ballY + = ySpeed;
   //检查球是否超出边缘
   if(ballX> ballXMax){
      ballX = ballXMax;
      xSpeed = -xSpeed;
   } else if(ballX <ballXMin){
      ballX = ballXMin;
      xSpeed = -xSpeed;
   }
   如果(ballY> ballYMax){
      ballY = ballYMax;
      ySpeed = -ySpeed;
   } else if(ballY <ballYMin){
      ballY = ballYMin;
      ySpeed = -ySpeed;
   }
}
 
/ *窗口重新调整大小时回拨* /
void reshape(GLsizei width,GLsizei height){
   //计算新窗口的宽比 if(height == 0)height = 1;                //防止被0除
   GLfloat aspect =(GLfloat)width /(GLfloat)height;
 
   //设置视口覆盖新窗口
   glViewport(0,0,width,height);
 
   //设置裁剪区域的长宽比以匹配视口 
   glMatrixMode(GL_PROJECTION);  //在Projection矩阵上操作 
   glLoadIdentity();             //重置投影矩阵
   if(width> = height){
      clipAreaXLeft = -1.0 * aspect;
      clipAreaXRight = 1.0 * aspect;
      clipAreaYBottom = -1.0;
      clipAreaYTop = 1.0;
   } else {
      clipAreaXLeft = -1.0;
      clipAreaXRight = 1.0;
      clipAreaYBottom = -1.0 / aspect;
      clipAreaYTop = 1.0 / aspect;
   }
   gluOrtho2D(clipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop);
   ballXMin = clipAreaXLeft + ballRadius;
   ballXMax = clipAreaXRight  -  ballRadius;
   ballYMin = clipAreaYBottom + ballRadius;
   ballYMax = clipAreaYTop  -  ballRadius;
}
 
/ *定时器过期时调回* /
void Timer(int value){
   glutPostRedisplay();    //发布一个绘制请求来激活display() 
   glutTimerFunc(refreshMillis,Timer,0); //以毫秒为单位的后续计时器调用
}
 
/ *主要功能:GLUT作为控制台应用程序从main()开始运行* /
int main(int argc,char ** argv){
   glutInit(&argc,argv);            //初始化GLUT 
   glutInitDisplayMode(GLUT_DOUBLE); //启用双缓冲模式 
   glutInitWindowSize(windowWidth,windowHeight);  //初始窗口的宽度和高度 
   glutInitWindowPosition(windowPosX,windowPosY); //初始窗口左上角(x,y) 
   glutCreateWindow(title);      //使用给定标题 
   glutDisplayFunc(display)创建窗口 ;     //注册窗口重新绘制的回调处理程序 
   glutReshapeFunc(reshape);     //注册窗口 
   重构的回调处理函数 glutTimerFunc(0,Timer,0);   //第一个定时器立即调用 
   initGL();                     //我们自己的OpenGL初始化 
   glutMainLoop();               //输入事件处理循环
   返回0;
}

[TODO]说明

7.使用GLUT处理键盘输入

我们可以注册回调函数来分别处理普通键和特殊键的键盘输入。

  • glutKeyboardFunc:为键盘事件注册回调处理程序。
    void glutKeyboardFunc(void(* func)(unsigned char key,int x,int y// key是按下的字符,例如'a'或27用于ESC
       //(xy)是Windows坐标中的鼠标位置
  • glutSpecialFunc:注册特殊键的回调处理程序(例如箭头键和功能键)。
    void glutSpecialFunc(void(* func)(int specialKey,int x,int y// specialKey:GLUT_KEY_ *(*用于LEFT,RIGHT,UP,DOWN,HOME,END,PAGE_UP,PAGE_DOWN,F1,... F12) 。
       //(xy)是Windows坐标中的鼠标位置

7.1例8:在全屏模式和窗口模式(GL08FullScreen.cpp之间切换

对于弹跳球程序,以下特殊键处理程序使用F1键全屏模式窗口模式之间切换

1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/ *
 * GL08FullScreen.cpp:在全屏模式和窗口模式之间切换
 * / 
#include <windows.h>   // MS窗口 
#include <GL / glut.h>   // GLUT,包括glu.h和gl.h 
#include < Math.h >      //需要sin,cos
#define PI 3.14159265f
 
//全局变量 
char title [] =“全屏和窗口模式”;  //窗口模式的标题 
int windowWidth = 640;     //窗口模式的宽度 
int windowHeight = 480;     //窗口模式的高度 
int windowPosX = 50;      //窗口模式的左上角x 
int windowPosY = 50;      //窗口模式的左上角y
 
GLfloat ballRadius = 0.5f;   //弹跳球的半径 
GLfloat ballX = 0.0f;         //球的中心(x,y)位置
GLfloat ballY = 0.0f;
GLfloat ballXMax,ballXMin,ballYMax,ballYMin; //球的中心(x,y)边界 
GLfloat xSpeed = 0.02f;      //球在x和y方向的速度
GLfloat ySpeed = 0.007f;
int refreshMillis = 30;      //以毫秒为单位刷新周期
 
//投影裁剪区域
GLdouble clipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop;
 
bool fullScreenMode = true; //全屏或窗口模式?
 
/ *初始化OpenGL图形* /
void initGL(){
   glClearColor(0.0,0.0,0.0,1.0); //将背景(清晰)颜色设置为黑色
}
 
/ *窗口重新绘制事件的回调处理程序* /
void display(){
   glClear(GL_COLOR_BUFFER_BIT);  //清除颜色缓冲区 
   glMatrixMode(GL_MODELVIEW);    //使用模型视图矩阵 
   glLoadIdentity();              //重置模型视图矩阵
 
   glTranslatef(ballX,ballY,0.0f);  //转换为(xPos,yPos)
   //使用三角形段形成一个圆
   在glBegin(GL_TRIANGLE_FAN);
      glColor3f(0.0f,0.0f,1.0f);  //蓝色 
      glVertex2f(0.0f,0.0f);       //圆的中心
      int numSegments = 100;
      GLfloat角;
      for(int i = 0; i <= numSegments; i ++){ //最后一个顶点与第一个顶点 
         角度相同 = i * 2.0f * PI / numSegments;  // 360度为所有部分
         glVertex2f(cos(angle)* ballRadius,sin(angle)* ballRadius);
      }
   glEnd();
 
   glutSwapBuffers();  //交换前端和后端缓冲区(双缓冲模式)
 
   //动画控制 - 计算下一次刷新的位置
   ballX + = xSpeed;
   ballY + = ySpeed;
   //检查球是否超出边缘
   if(ballX> ballXMax){
      ballX = ballXMax;
      xSpeed = -xSpeed;
   } else if(ballX <ballXMin){
      ballX = ballXMin;
      xSpeed = -xSpeed;
   }
   如果(ballY> ballYMax){
      ballY = ballYMax;
      ySpeed = -ySpeed;
   } else if(ballY <ballYMin){
      ballY = ballYMin;
      ySpeed = -ySpeed;
   }
}
 
/ *窗口重新调整大小时回拨* /
void reshape(GLsizei width,GLsizei height){
   //计算新窗口的宽比 if(height == 0)height = 1;                //防止被0除
   GLfloat aspect =(GLfloat)width /(GLfloat)height;
 
   //设置视口覆盖新窗口
   glViewport(0,0,width,height);
 
   //设置裁剪区域的长宽比以匹配视口 
   glMatrixMode(GL_PROJECTION);  //在Projection矩阵上操作 
   glLoadIdentity();             //重置投影矩阵
   if(width> = height){
      clipAreaXLeft = -1.0 * aspect;
      clipAreaXRight = 1.0 * aspect;
      clipAreaYBottom = -1.0;
      clipAreaYTop = 1.0;
   } else {
      clipAreaXLeft = -1.0;
      clipAreaXRight = 1.0;
      clipAreaYBottom = -1.0 / aspect;
      clipAreaYTop = 1.0 / aspect;
   }
   gluOrtho2D(clipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop);
   ballXMin = clipAreaXLeft + ballRadius;
   ballXMax = clipAreaXRight  -  ballRadius;
   ballYMin = clipAreaYBottom + ballRadius;
   ballYMax = clipAreaYTop  -  ballRadius;
}
 
/ *定时器过期时调回* /
void Timer(int value){
   glutPostRedisplay();    //发布一个绘制请求来激活display() 
   glutTimerFunc(refreshMillis,Timer,0); //以毫秒为单位的后续计时器调用
}
 
/ *特殊键事件的回调处理程序* /
void specialKeys(int key,int x,int y){
   开关(键){
      case GLUT_KEY_F1:     // F1:在全屏和窗口模式之间切换 
         fullScreenMode =!fullScreenMode;         //切换状态 
         if(fullScreenMode){                      //全屏模式 
            windowPosX = glutGet(GLUT_WINDOW_X); //保存参数以供稍后恢复
            windowPosY = glutGet(GLUT_WINDOW_Y);
            windowWidth = glutGet(GLUT_WINDOW_WIDTH);
            windowHeight = glutGet(GLUT_WINDOW_HEIGHT);
            glutFullScreen();                      //切换到全屏模式 
         } else {                                          //窗口模式 
            glutReshapeWindow(windowWidth,windowHeight); //切换到窗口模式 
            glutPositionWindow(windowPosX,windowPosX);   //位置左上角
         }
         打破;
   }
}
 
/ *主要功能:GLUT作为控制台应用程序从main()开始运行* /
int main(int argc,char ** argv){
   glutInit(&argc,argv);            //初始化GLUT 
   glutInitDisplayMode(GLUT_DOUBLE); //启用双缓冲模式 
   glutInitWindowSize(windowWidth,windowHeight);  //初始窗口的宽度和高度 
   glutInitWindowPosition(windowPosX,windowPosY); //初始窗口左上角(x,y) 
   glutCreateWindow(title);      //使用给定标题 
   glutDisplayFunc(display)创建窗口 ;     //注册窗口重新绘制的回调处理程序 
   glutReshapeFunc(reshape);     //注册窗口 
   重构的回调处理函数 glutTimerFunc(0,Timer,0);   //立即调用第一个定时器
   glutSpecialFunc(specialKeys);//注册特殊键事件的回调处理程序 
   glutFullScreen();             //放入全屏
    initGL();                     //我们自己的OpenGL初始化 
   glutMainLoop();               //输入事件处理循环
   返回0;
}

[TODO]说明

[TODO]使用glVertex绘制圆是低效的(由于计算密集型sin()cos()函数)。尝试使用GLU的二次曲面。

7.2示例9:密钥控制(GL09KeyControl.cpp

对于弹跳球程序,以下按键和特殊键处理程序通过ESC(27)提供出口,使用上/下箭头键增加/减少速度,使用左/右箭头键增加/减少x速度,使用PageUp / PageDown键增加/减少球的半径。

1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/ *
 * GL09KeyControl.cpp:一个按键控制的弹跳球
 * / 
#include <windows.h>   //用于MS Windows 
#include <GL / glut.h>   // GLUT,include glu.h和gl.h 
#include < Math.h >      //需要sin,cos
#define PI 3.14159265f
 
//全局变量 
char title [] =“全屏和窗口模式”;  //窗口模式的标题 
int windowWidth = 640;     //窗口模式的宽度 
int windowHeight = 480;     //窗口模式的高度 
int windowPosX = 50;      //窗口模式的左上角x 
int windowPosY = 50;      //窗口模式的左上角y
 
GLfloat ballRadius = 0.5f;   //弹跳球的半径 
GLfloat ballX = 0.0f;        //球的中心(x,y)位置
GLfloat ballY = 0.0f;
GLfloat ballXMax,ballXMin,ballYMax,ballYMin; //球的中心(x,y)边界 
GLfloat xSpeed = 0.02f;      //球在x和y方向的速度
GLfloat ySpeed = 0.007f;
int refreshMillis = 30;      //以毫秒为单位刷新周期
 
//投影裁剪区域
GLdouble clipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop;
 
bool fullScreenMode = true; //全屏或窗口模式?
 
/ *初始化OpenGL图形* /
void initGL(){
   glClearColor(0.0,0.0,0.0,1.0); //将背景(清晰)颜色设置为黑色
}
 
/ *窗口重新绘制事件的回调处理程序* /
void display(){
   glClear(GL_COLOR_BUFFER_BIT);  //清除颜色缓冲区 
   glMatrixMode(GL_MODELVIEW);    //使用模型视图矩阵 
   glLoadIdentity();              //重置模型视图矩阵
 
   glTranslatef(ballX,ballY,0.0f);  //转换为(xPos,yPos)
   //使用三角形段形成一个圆
   在glBegin(GL_TRIANGLE_FAN);
      glColor3f(0.0f,0.0f,1.0f);  //蓝色 
      glVertex2f(0.0f,0.0f);       //圆的中心
      int numSegments = 100;
      GLfloat角;
      for(int i = 0; i <= numSegments; i ++){ //最后一个顶点与第一个顶点 
         角度相同 = i * 2.0f * PI / numSegments;  // 360度为所有部分
         glVertex2f(cos(angle)* ballRadius,sin(angle)* ballRadius);
      }
   glEnd();
 
   glutSwapBuffers();  //交换前端和后端缓冲区(双缓冲模式)
 
   //动画控制 - 计算下一次刷新的位置
   ballX + = xSpeed;
   ballY + = ySpeed;
   //检查球是否超出边缘
   if(ballX> ballXMax){
      ballX = ballXMax;
      xSpeed = -xSpeed;
   } else if(ballX <ballXMin){
      ballX = ballXMin;
      xSpeed = -xSpeed;
   }
   如果(ballY> ballYMax){
      ballY = ballYMax;
      ySpeed = -ySpeed;
   } else if(ballY <ballYMin){
      ballY = ballYMin;
      ySpeed = -ySpeed;
   }
}
 
/ *窗口重新调整大小时回拨* /
void reshape(GLsizei width,GLsizei height){
   //计算新窗口的宽比 if(height == 0)height = 1;                //防止被0除
   GLfloat aspect =(GLfloat)width /(GLfloat)height;
 
   //设置视口覆盖新窗口
   glViewport(0,0,width,height);
 
   //设置裁剪区域的长宽比以匹配视口 
   glMatrixMode(GL_PROJECTION);  //在Projection矩阵上操作 
   glLoadIdentity();             //重置投影矩阵
   if(width> = height){
      clipAreaXLeft = -1.0 * aspect;
      clipAreaXRight = 1.0 * aspect;
      clipAreaYBottom = -1.0;
      clipAreaYTop = 1.0;
   } else {
      clipAreaXLeft = -1.0;
      clipAreaXRight = 1.0;
      clipAreaYBottom = -1.0 / aspect;
      clipAreaYTop = 1.0 / aspect;
   }
   gluOrtho2D(clipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop);
   ballXMin = clipAreaXLeft + ballRadius;
   ballXMax = clipAreaXRight  -  ballRadius;
   ballYMin = clipAreaYBottom + ballRadius;
   ballYMax = clipAreaYTop  -  ballRadius;
}
 
/ *定时器过期时调回* /
void Timer(int value){
   glutPostRedisplay();    //发布一个绘制请求来激活display() 
   glutTimerFunc(refreshMillis,Timer,0); //以毫秒为单位的后续计时器调用
}
 
/ *正常密钥事件的回调处理程序* /
void keyboard(unsigned char key,int x,int y){
   开关(键){
      情况27:      // ESC键
         出口(0);
         打破;
   }
}
 
/ *特殊键事件的回调处理程序* /
void specialKeys(int key,int x,int y){
   开关(键){
      case GLUT_KEY_F1:     // F1:在全屏和窗口模式之间切换 
         fullScreenMode =!fullScreenMode;         //切换状态 
         if(fullScreenMode){                      //全屏模式 
            windowPosX = glutGet(GLUT_WINDOW_X); //保存参数以供稍后恢复
            windowPosY = glutGet(GLUT_WINDOW_Y);
            windowWidth = glutGet(GLUT_WINDOW_WIDTH);
            windowHeight = glutGet(GLUT_WINDOW_HEIGHT);
            glutFullScreen();                      //切换到全屏模式 
         } else {                                          //窗口模式 
            glutReshapeWindow(windowWidth,windowHeight); //切换到窗口模式 
            glutPositionWindow(windowPosX,windowPosX);   //位置左上角
         }
         打破;
      case GLUT_KEY_RIGHT:     //右:增加x速度
         xSpeed * = 1.05f; 打破;
      case GLUT_KEY_LEFT:      //左:降低x速度
         xSpeed * = 0.95f; 打破;
      GLUT_KEY_UP:        //向上:增加y速度
         ySpeed * = 1.05f; 打破;
      GLUT_KEY_DOWN:      // Down:减小y速度
         ySpeed * = 0.95f; 打破;
      GLUT_KEY_PAGE_UP:   // Page-Up:增加球的半径
         ballRadius * = 1.05f;
         ballXMin = clipAreaXLeft + ballRadius;
         ballXMax = clipAreaXRight  -  ballRadius;
         ballYMin = clipAreaYBottom + ballRadius;
         ballYMax = clipAreaYTop  -  ballRadius;
         打破;
      GLUT_KEY_PAGE_DOWN:// Page-Down:减少球的半径
         ballRadius * = 0.95f;
         ballXMin = clipAreaXLeft + ballRadius;
         ballXMax = clipAreaXRight  -  ballRadius;
         ballYMin = clipAreaYBottom + ballRadius;
         ballYMax = clipAreaYTop  -  ballRadius;
         打破;
   }
}
 
/ *主要功能:GLUT作为控制台应用程序从main()开始运行* /
int main(int argc,char ** argv){
   glutInit(&argc,argv);            //初始化GLUT 
   glutInitDisplayMode(GLUT_DOUBLE); //启用双缓冲模式 
   glutInitWindowSize(windowWidth,windowHeight);  //初始窗口的宽度和高度 
   glutInitWindowPosition(windowPosX,windowPosY); //初始窗口左上角(x,y) 
   glutCreateWindow(title);      //使用给定标题 
   glutDisplayFunc(display)创建窗口 ;     //注册窗口重新绘制的回调处理程序 
   glutReshapeFunc(reshape);     //注册窗口 
   重构的回调处理函数 glutTimerFunc(0,Timer,0);   //立即调用第一个定时器 
   glutSpecialFunc(specialKeys);//注册特殊键事件的回调处理程序 
   glutKeyboardFunc(keyboard);   //注册特殊键事件的回调处理程序
glutFullScreen(); //放入全屏 initGL(); //我们自己的OpenGL初始化 glutMainLoop(); //输入事件处理循环 返回0; }

[TODO]说明

8.使用GLUT处理鼠标输入

同样,我们可以注册回调函数来处理鼠标点击和鼠标移动。

  • glutMouseFunc:为鼠标点击注册回调处理程序。
    void glutMouseFunc(void(* func)(int button,int state,int x,int y//(xy)是鼠标单击的位置。
       // 按钮:GLUT_LEFT_BUTTON,GLUT_RIGHT_BUTTON,GLUT_MIDDLE_BUTTON
       // 状态:GLUT_UP,GLUT_DOWN
  • glutMotionFunc:为鼠标移动注册回调处理程序(当鼠标单击并移动时)。
    void glutMotionFunc(void(* func)(int x,int y//其中(xy)是Window坐标中的鼠标位置

8.1实施例10:小鼠控制的(GL10MouseControl.cpp

对于弹跳球程序,以下鼠标处理程序通过鼠标左键点击暂停移动,然后通过鼠标右键点击恢复。

1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/ *
 * GL10MouseControl.cpp:鼠标控制的弹跳球
 * / 
#include <windows.h>   //用于MS Windows 
#include <GL / glut.h>   // GLUT,include glu.h和gl.h 
#include < Math.h >      //需要sin,cos
#define PI 3.14159265f
 
//全局变量 
char title [] =“全屏和窗口模式”;  //窗口模式的标题 
int windowWidth = 640;     //窗口模式的宽度 
int windowHeight = 480;     //窗口模式的高度 
int windowPosX = 50;      //窗口模式的左上角x 
int windowPosY = 50;      //窗口模式的左上角y
 
GLfloat ballRadius = 0.5f;   //弹跳球的半径 
GLfloat ballX = 0.0f;        //球的中心(x,y)位置
GLfloat ballY = 0.0f;
GLfloat ballXMax,ballXMin,ballYMax,ballYMin; //球的中心(x,y)边界 
GLfloat xSpeed = 0.02f;      //球在x和y方向的速度
GLfloat ySpeed = 0.007f;
int refreshMillis = 30;      //以毫秒为单位刷新周期
 
//投影裁剪区域
GLdouble clipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop;
 
bool fullScreenMode = true; //全屏或窗口模式?
bool paused = false;         //运动已暂停或恢复 
GLfloat xSpeedSaved,ySpeedSaved;  //支持简历
 
/ *初始化OpenGL图形* /
void initGL(){
   glClearColor(0.0,0.0,0.0,1.0); //将背景(清晰)颜色设置为黑色
}
 
/ *窗口重新绘制事件的回调处理程序* /
void display(){
   glClear(GL_COLOR_BUFFER_BIT);  //清除颜色缓冲区 
   glMatrixMode(GL_MODELVIEW);    //使用模型视图矩阵 
   glLoadIdentity();              //重置模型视图矩阵
 
   glTranslatef(ballX,ballY,0.0f);  //转换为(xPos,yPos)
   //使用三角形段形成一个圆
   在glBegin(GL_TRIANGLE_FAN);
      glColor3f(0.0f,0.0f,1.0f);  //蓝色 
      glVertex2f(0.0f,0.0f);       //圆的中心
      int numSegments = 100;
      GLfloat角;
      for(int i = 0; i <= numSegments; i ++){ //最后一个顶点与第一个顶点 
         角度相同 = i * 2.0f * PI / numSegments;  // 360度为所有部分
         glVertex2f(cos(angle)* ballRadius,sin(angle)* ballRadius);
      }
   glEnd();
 
   glutSwapBuffers();  //交换前端和后端缓冲区(双缓冲模式)
 
   //动画控制 - 计算下一次刷新的位置
   ballX + = xSpeed;
   ballY + = ySpeed;
   //检查球是否超出边缘
   if(ballX> ballXMax){
      ballX = ballXMax;
      xSpeed = -xSpeed;
   } else if(ballX <ballXMin){
      ballX = ballXMin;
      xSpeed = -xSpeed;
   }
   如果(ballY> ballYMax){
      ballY = ballYMax;
      ySpeed = -ySpeed;
   } else if(ballY <ballYMin){
      ballY = ballYMin;
      ySpeed = -ySpeed;
   }
}
 
/ *窗口重新调整大小时回拨* /
void reshape(GLsizei width,GLsizei height){
   //计算新窗口的宽比 if(height == 0)height = 1;                //防止被0除
   GLfloat aspect =(GLfloat)width /(GLfloat)height;
 
   //设置视口覆盖新窗口
   glViewport(0,0,width,height);
 
   //设置裁剪区域的长宽比以匹配视口 
   glMatrixMode(GL_PROJECTION);  //在Projection矩阵上操作 
   glLoadIdentity();             //重置投影矩阵
   if(width> = height){
      clipAreaXLeft = -1.0 * aspect;
      clipAreaXRight = 1.0 * aspect;
      clipAreaYBottom = -1.0;
      clipAreaYTop = 1.0;
   } else {
      clipAreaXLeft = -1.0;
      clipAreaXRight = 1.0;
      clipAreaYBottom = -1.0 / aspect;
      clipAreaYTop = 1.0 / aspect;
   }
   gluOrtho2D(clipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop);
   ballXMin = clipAreaXLeft + ballRadius;
   ballXMax = clipAreaXRight  -  ballRadius;
   ballYMin = clipAreaYBottom + ballRadius;
   ballYMax = clipAreaYTop  -  ballRadius;
}
 
/ *定时器过期时调回* /
void Timer(int value){
   glutPostRedisplay();    //发布一个绘制请求来激活display() 
   glutTimerFunc(refreshMillis,Timer,0); //以毫秒为单位的后续计时器调用
}
 
/ *正常密钥事件的回调处理程序* /
void keyboard(unsigned char key,int x,int y){
   开关(键){
      情况27:      // ESC键
         出口(0);
         打破;
   }
}
 
/ *特殊键事件的回调处理程序* /
void specialKeys(int key,int x,int y){
   开关(键){
      case GLUT_KEY_F1:     // F1:在全屏和窗口模式之间切换 
         fullScreenMode =!fullScreenMode;         //切换状态 
         if(fullScreenMode){                      //全屏模式 
            windowPosX = glutGet(GLUT_WINDOW_X); //保存参数以供稍后恢复
            windowPosY = glutGet(GLUT_WINDOW_Y);
            windowWidth = glutGet(GLUT_WINDOW_WIDTH);
            windowHeight = glutGet(GLUT_WINDOW_HEIGHT);
            glutFullScreen();                      //切换到全屏模式 
         } else {                                          //窗口模式 
            glutReshapeWindow(windowWidth,windowHeight); //切换到窗口模式 
            glutPositionWindow(windowPosX,windowPosX);   //位置左上角
         }
         打破;
      case GLUT_KEY_RIGHT:     //右:增加x速度
         xSpeed * = 1.05f; 打破;
      case GLUT_KEY_LEFT:      //左:降低x速度
         xSpeed * = 0.95f; 打破;
      GLUT_KEY_UP:        //向上:增加y速度
         ySpeed * = 1.05f; 打破;
      GLUT_KEY_DOWN:      // Down:减小y速度
         ySpeed * = 0.95f; 打破;
      GLUT_KEY_PAGE_UP:   // Page-Up:增加球的半径
         ballRadius * = 1.05f;
         ballXMin = clipAreaXLeft + ballRadius;
         ballXMax = clipAreaXRight  -  ballRadius;
         ballYMin = clipAreaYBottom + ballRadius;
         ballYMax = clipAreaYTop  -  ballRadius;
         打破;
      GLUT_KEY_PAGE_DOWN:// Page-Down:减少球的半径
         ballRadius * = 0.95f;
         ballXMin = clipAreaXLeft + ballRadius;
         ballXMax = clipAreaXRight  -  ballRadius;
         ballYMin = clipAreaYBottom + ballRadius;
         ballYMax = clipAreaYTop  -  ballRadius;
         打破;
   }
}
 
/ *鼠标事件的回调处理程序* /
void mouse(int button,int state,int x,int y){
   if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN){ //暂停/恢复 
      暂停=!暂停;         //切换状态
      如果(暂停){
         xSpeedSaved = xSpeed;  //保存参数以供稍后恢复
         ySpeedSaved = ySpeed;
         xSpeed = 0;            //停止移动
         ySpeed = 0;
      } else {
         xSpeed = xSpeedSaved;  //恢复参数
         ySpeed = ySpeedSaved;
      }
   }
}
 
/ *主要功能:GLUT作为控制台应用程序从main()开始运行* /
int main(int argc,char ** argv){
   glutInit(&argc,argv);            //初始化GLUT 
   glutInitDisplayMode(GLUT_DOUBLE); //启用双缓冲模式 
   glutInitWindowSize(windowWidth,windowHeight);  //初始窗口的宽度和高度 
   glutInitWindowPosition(windowPosX,windowPosY); //初始窗口左上角(x,y) 
   glutCreateWindow(title);      //使用给定标题 
   glutDisplayFunc(display)创建窗口 ;     //注册窗口重新绘制的回调处理程序 
   glutReshapeFunc(reshape);     //注册窗口 
   重构的回调处理函数 glutTimerFunc(0,Timer,0);   //立即调用第一个定时器 
   glutSpecialFunc(specialKeys);//注册特殊键事件的回调处理程序 
   glutKeyboardFunc(keyboard);   //注册特殊键事件的回调处理程序 
   glutFullScreen();             //放入全屏
   glutMouseFunc(鼠标);   //注册鼠标事件的回调处理程序 
   initGL();                     //我们自己的OpenGL初始化 
   glutMainLoop();               //输入事件处理循环
   返回0;
}

[TODO]说明

8.2例11:一个简单的画图程序

[TODO]使用鼠标移动和GL_LINE_STRIP

 

链接到OpenGL /计算机图形参考和资源

猜你喜欢

转载自blog.csdn.net/cjb_king/article/details/79483465