• 实现任务目标:
    • 使用纹理贴图,增强可视效果
    • 应用坐标变换,实现场景中不同物体重建
    • 采用双缓冲技术,实现场景实时绘制
    • 具有一定的鼠标、键盘交互功能
  • 先放效果

opengl简单入门实例-LMLPHP鼠标的交互功能有:右键暂停转动,左键继续转动,滚轮向前放大,向后缩小

  • IDE:opengl实现需要库函数。用的编译环境是visual studio。附上一个很好的教程【1】:在vs2017下配置opengl。(vs2019也可以用)
  • 一个很好的入门教程【2】:OpenGL入门教程(精)。讲得很仔细,通俗易懂。前几课用到的库都没有超过glut的范围。
  • 事实上,对于opengl的实现主要是对于各种库函数的调用,所以对于各种库函数的认知很重要。这里也给出一个很好的教程【3】:OpenGL库函数汇总
  • ok,在看了上面的教程以后肯定对于opengl有了一定认识,尤其是第二个教程中讲解得非常仔细。所以本文接下来的内容是建立在对那个教程的学习基础之上,对一些我在实践中遇到的问题作出补充。
  • 下面就进入正文。
  • 所包含的头文件目录
1 #include <GL/glut.h>
2 #include <stdlib.h>
3 #include <stdio.h>
  • 最基本的功能是当然是创建自己的图形并显示出来,如上图我创建的是日地月系统。需要的函数为display()和main()。
  • 这其中很重要的一个知识点就是图像的视图变换/模型变换、投影变换和视口变换。有关这块的内容个人觉得教程【2】中讲得不够清楚,可以参考一些别的教程。比如:OpenGL(六) gluLookAt和gluPerspective函数解析Opengl---gluLookAt函数详解
  • 这里要介绍一下opengl中的坐标轴。x轴水平向右为正,y轴竖直向上为正,z轴垂直屏幕向外为正。符合右手定则。
 1 void display(void)
 2 {
 3     glEnable(GL_DEPTH_TEST);  //3、5行代码中跟DEPTH有关的函数是为了在同一个窗口内创建多个图像而不会被后创建的图像覆盖。
 4     glClearColor(0, 0, 0, 1);  //设置“空”色。之前看到一个很好的解释,白纸是白色的,所以白纸上的“空”色为白色。那么信封上的“空”色就是信封的颜色。
 5     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //COLOR的那个参数是清除颜色缓存,设为“空”色
 6
 7     glMatrixMode(GL_PROJECTION);  //投影变换
 8     glLoadIdentity();
 9     gluPerspective(60.0, 1, 1.0, 100.0);
10
11     glMatrixMode(GL_MODELVIEW);   //视图变换/模型变换
12     glLoadIdentity();  //加载单位矩阵  
13     gluLookAt(0.0, 0.0, 60.0, 0, 0, 0, 0.0, 1.0, 0);
15    //太阳
16     glColor3f(1.0, 0, 0);
17     glutSolidSphere(6, 20, 20);
18   //地球
19     glColor3f(0.0, 0, 1.0);
20     glTranslatef(-20.0, 0, 0); //偏移矩阵
21     glutSolidSphere(3, 20, 20);
22   //月球
23     glColor3f(1.0, 1.0, 0);
24     glTranslatef(-6.0, 0, 0); //这里的偏移量是在上面已经偏移的基础上再进行偏移
25     glutSolidSphere(1, 20, 20);
26
27     glutSwapBuffers(); //双缓冲函数用到,相关内容看上面的教程【2】里
28 }
  •  main()中的函数就不具体解释了,应该都懂
 1 int main(int argc, char** argv)
 2 {
 3     glutInit(&argc, argv);
 4     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
 5     glutInitWindowSize(500, 500);
 6     glutInitWindowPosition(100, 100);
 7     glutCreateWindow("name");
 8     glutDisplayFunc(&display);
 9     glutMainLoop();
10     return 0;
11 }
  • 现在在现有程序的基础上加入动画需要4步
  • 1 加入全局变量
1 static GLfloat angle = 0.0f; 
  • 2 在display()里面加入旋转的函数。由于效果是让整个画面都转,这句话我选择加在gluLookAt()后面。需要加入的语句已标红。
 1 void display(void)
 2 {
 3     …… ……
 4     glMatrixMode(GL_MODELVIEW);
 5     glLoadIdentity();  //加载单位矩阵  
 6     gluLookAt(place_x, 0.0, place_z, 0, 0, 0, 0.0, 1.0, 0);
 7     glRotatef(angle, 0.0f, 1.0f, 0.0f); //旋转,改变的是x轴分量
 8
 9     glColor3f(1.0, 0, 0);
10     …… ……
11 }
  • 3 编写myIdle()函数
1 void myIdle(void)
2 {
3     angle += 1.8f;
4     if (angle >= 360.0f)
5         angle = 0.0f;
6     display();
7 }
  • 4 在主函数加入glutIdleFunc(&myIdle);可以加在刚刚的display语句下面。
1 int main(int argc, char** argv)
2 {
3     …… ……
4     glutDisplayFunc(&display);
5     glutIdleFunc(&myIdle);
6         …… ……
7     glutMainLoop();
8     return 0;
9 }
  • ok。接下来就要为我们的程序加上纹理了。首先在网上找了两张星空的网图。而且,为了方便起见,我把它们的格式改成了24位色的bmp图片,尺寸为258*258。
  • 至于怎么改格式:1 24位色可以对图片另存为时在下拉菜单里选择。2 修改尺寸可以用win自带的图片编辑器。
  • 我的两张照片分别命名为“wall.bmp”,"ground.bmp"。放在源程序的同一个子目录里面
  • 有关纹理贴图的详细内容继续参考教程【2】。这里附上我写的程序和说明。
  • 一共分为3步。
  • 1 搭建矩形框架【对我的程序来说相当于有一个支架,然后把按照点对点的方式纹理图贴上去】
  • 在这一步中先只写上矩形各个点的坐标,为后面建立矩形做准备。

opengl简单入门实例-LMLPHP

 1 //全局变量
 2 static const GLfloat vertex_list[][3] = {
 3     - 15.0f, -20.0f, -10.0f,  //事实上6、7两个点是用不到的,作为完整性就一起写了。贴图只在背面和底面贴了图,为了更好的演示效果。
 4     40.0f, -20.0f, -10.0f,
 5     40.0f,  20.0f, -10.0f,
 6     -15.0f,  20.0f, -10.0f,
 7     -15.0f, -20.0f,  10.0f,
 8     40.0f, -20.0f,  10.0f,
 9     -15.0f,  20.0f,  10.0f,
10     40.0f,  20.0f,  10.0f,
11  };
  1 //全局变量
  2 #define BMP_Header_Length 54
  3 //函数
  4 // 函数power_of_two用于判断一个整数是不是2的整数次幂
  5 int power_of_two(int n)
  6 {
  7     if (n <= 0)
  8         return 0;
  9     return (n & (n - 1)) == 0;
 10 }
 11 /* 函数load_texture
 12 * 读取一个BMP文件作为纹理
 13 * 如果失败,返回0,如果成功,返回纹理编号
 14 */
 15 GLuint load_texture(const char* file_name)
 16 {
 17     GLint width, height, total_bytes;
 18     GLubyte* pixels = 0;
 19     GLuint last_texture_ID = 0, texture_ID = 0;
 20
 21     // 打开文件,如果失败,返回
 22     FILE* pFile;
 23     errno_t err;
 24     err = fopen_s(&pFile, file_name, "rb");  //在vs中使用fopen_s()函数的示例。
 25     if (!pFile) exit(0);
 26
 27     // 读取文件中图象的宽度和高度
 28     fseek(pFile, 0x0012, SEEK_SET);
 29     fread(&width, sizeof(width), 1, pFile);
 30     fread(&height, sizeof(height), 1, pFile);
 31     fseek(pFile, BMP_Header_Length, SEEK_SET);
 32
 33     // 计算每行像素所占字节数,并根据此数据计算总像素字节数
 34     {
 35         GLint line_bytes = width * 3;
 36         while (line_bytes % 4 != 0)
 37             ++line_bytes;
 38         total_bytes = line_bytes * height;
 39     }
 40
 41     // 根据总像素字节数分配内存
 42     pixels = (GLubyte*)malloc(total_bytes);
 43     if (pixels == 0)
 44     {
 45         fclose(pFile);
 46         return 0;
 47     }
 48
 49     // 读取像素数据
 50     if (fread(pixels, total_bytes, 1, pFile) <= 0)
 51     {
 52         free(pixels);
 53         fclose(pFile);
 54         return 0;
 55     }
 56
 57     // 对就旧版本的兼容,如果图象的宽度和高度不是的整数次方,则需要进行缩放
 58     // 若图像宽高超过了OpenGL规定的最大值,也缩放
 59     {
 60         GLint max;
 61         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
 62         if (!power_of_two(width)
 63             || !power_of_two(height)
 64             || width > max
 65             || height > max)
 66         {
 67             const GLint new_width = 256;
 68             const GLint new_height = 256; // 规定缩放后新的大小为边长的正方形
 69             GLint new_line_bytes, new_total_bytes;
 70             GLubyte* new_pixels = 0;
 71
 72             // 计算每行需要的字节数和总字节数
 73             new_line_bytes = new_width * 3;
 74             while (new_line_bytes % 4 != 0)
 75                 ++new_line_bytes;
 76             new_total_bytes = new_line_bytes * new_height;
 77
 78             // 分配内存
 79             new_pixels = (GLubyte*)malloc(new_total_bytes);
 80             if (new_pixels == 0)
 81             {
 82                 free(pixels);
 83                 fclose(pFile);
 84                 return 0;
 85             }
 86
 87             // 进行像素缩放
 88             gluScaleImage(GL_RGB,
 89                 width, height, GL_UNSIGNED_BYTE, pixels,
 90                 new_width, new_height, GL_UNSIGNED_BYTE, new_pixels);
 91
 92             // 释放原来的像素数据,把pixels指向新的像素数据,并重新设置width和height
 93             free(pixels);
 94             pixels = new_pixels;
 95             width = new_width;
 96             height = new_height;
 97         }
 98     }
 99
100     // 分配一个新的纹理编号
101     glGenTextures(1, &texture_ID);
102     if (texture_ID == 0)
103     {
104         free(pixels);
105         fclose(pFile);
106         return 0;
107     }
108
109     // 绑定新的纹理,载入纹理并设置纹理参数
110     // 在绑定前,先获得原来绑定的纹理编号,以便在最后进行恢复
111     GLint lastTextureID = last_texture_ID;
112     glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastTextureID);
113     glBindTexture(GL_TEXTURE_2D, texture_ID);
114     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
115     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
116     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
117     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
118     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
119     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
120         GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
121     glBindTexture(GL_TEXTURE_2D, lastTextureID);  //恢复之前的纹理绑定
122     free(pixels);
123     return texture_ID;
124 }
  • 3 在display()中打开状态机->读取纹理图片->搭起矩形框架->贴图->关闭状态机。
  • 这里踩过的坑就是关于状态机的开闭问题。如果没有关闭状态机,显示的图像中之前画的几个球都是全黑的。这是因为纹理贴图会干扰别的颜色
  • 其中用到的glTexCoord2f()函数可以参考百度的这个示例。
 1 //全局变量
 2 GLuint texGround;
 3 GLuint texWall;
 4 //函数补充
 5 void display(void)
 6 {
 7     …… ……//之前内容的后面加入一下内容
 8     glEnable(GL_TEXTURE_2D); //开启状态机
 9     texGround = load_texture("ground.bmp");
10     texWall = load_texture("wall.bmp");
11
12     //绘制底面
13     glBindTexture(GL_TEXTURE_2D, texGround);
14     glBegin(GL_QUADS);
15     glTexCoord2f(0.0f, 0.0f); glVertex3fv(vertex_list[4]); //点对点
16     glTexCoord2f(1.0f, 0.0f); glVertex3fv(vertex_list[5]);
17     glTexCoord2f(1.0f, 1.0f); glVertex3fv(vertex_list[1]);
18     glTexCoord2f(0.0f, 1.0f); glVertex3fv(vertex_list[0]);
19     glEnd();
20     //绘制立面
21     glBindTexture(GL_TEXTURE_2D, texWall);
22     glBegin(GL_QUADS);
23     glTexCoord2f(0.0f, 0.0f); glVertex3fv(vertex_list[0]);
24     glTexCoord2f(1.0f, 0.0f); glVertex3fv(vertex_list[1]);
25     glTexCoord2f(1.0f, 1.0f); glVertex3fv(vertex_list[2]);
26     glTexCoord2f(0.0f, 1.0f); glVertex3fv(vertex_list[3]);
27     glEnd();
28     glDisable(GL_TEXTURE_2D);//关闭状态机
29     glutSwapBuffers();
30 }
  • ok。那么到这里我们已经完成了纹理贴图、双缓冲绘制和场景重建的任务啦。接下来还有鼠标交互的任务。那么在这里先插入一个新的函数讲解:reshape()。
  • 关于reshape()的原理呢可以去查查资料。我说说我的理解吧。简单来说呢就是在你显示窗口时,如果你拉动边框,窗口内的图像不会随着你拉动而改变。
  • 附上一个简单的图片示例。

opengl简单入门实例-LMLPHP  opengl简单入门实例-LMLPHP可以看到在右边的图中,我拉动了窗口的边框,则图像的形状也改变了。

  • reshape()就能在窗体大小被改变时,窗口大小不变,图像比例也不变。
  • 那么同样的,完成这个功能需要2步。
  • 1 写一个reshape()函数
 1 void reshape(int w, int h)
 2 {
 3     glViewport(0, 0, 500, 500);
 4     glMatrixMode(GL_PROJECTION);
 5     glLoadIdentity();
 6     gluPerspective(60.0, 1, 1, 100.0);
 7     glMatrixMode(GL_MODELVIEW);
 8     glLoadIdentity();
 9     gluLookAt(0, 0.0, 60.0, 0, 0, 0, 0.0, 1.0, 0);
10 }
  • 2 在main函数中加入一句
1 int main(int argc, char** argv)
2 {
3     …… ……
4     glutDisplayFunc(&display);
5     glutReshapeFunc(&reshape);
6     glutIdleFunc(&myIdle);
7     …… ……
8 }
  • ok。最后的最后,要完成鼠标的交互了。
  • 我所设置的鼠标的功能包括:右键暂停、左键继续;滚轮向上放大,滚轮向下缩小。
  • 前两个改变的是转过的角度angle,后两个则跟我们所建立的视图模型,也就是之前用过glLookAt()函数的参数有关。
  • 对于鼠标交互用到的函数及参量是void myMouse(int button, int state, int x, int y);关于这个更多的信息可以自行查找。
  • 那么同样的,完成这个需要2 / 3步。但是我分为两个部分来讲。首先是对于右键暂停和左键继续的部分。
  • 1 之前的显示函数里已经有了一个angle变量用来控制角度,所以我们要做的就是停掉这个angle变量的自增,所以我们要停用myIdle函数。
 1 void myMouse(int button, int state, int x, int y)
 2 {
 3     if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
 4     {
 5         glutIdleFunc(&myIdle);
 6     }
 7     if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
 8     {
 9         glutIdleFunc(NULL);
10     }
11 }
  • 2 在主函数中加入语句。
1 int main(int argc, char** argv)
2 {
3     …… ……
4     glutCreateWindow("name");
5     glutMouseFunc(&myMouse);
6     glutDisplayFunc(&display);
7     …… ……
8 }
  • 对于缩放.
  • 1 因为要涉及到之前显示函数display()中的glLookAt()的改变,所以我们将其中的值设为全局变量。
 1 //全局变量
 2 static float place_z = 60.0f;
 3 static float place_x = 0.0f;
 4 //修改函数参数
 5 void display(void)
 6 {
 7     …… ……
 8     gluLookAt(place_x, 0.0, place_z, 0, 0, 0, 0.0, 1.0, 0);
 9     glRotatef(angle, 0.0f, 1.0f, 0.0f); //旋转
10         …… ……
11 }
  • 2 在之前的鼠标的函数中加入对滚轮的控制语句
 1 //全局变量
 2 #define  GLUT_WHEEL_UP 3
 3 #define  GLUT_WHEEL_DOWN 4
 4 //函数中
 5 void myMouse(int button, int state, int x, int y)
 6 {
 7     …… ……
 8     if (state == GLUT_UP && button == GLUT_WHEEL_UP)
 9     {
10         glutReshapeFunc(NULL);
11         place_z -= 5.0;
12         display();
13     }
14     if (state == GLUT_UP && button == GLUT_WHEEL_DOWN)
15     {
16         glutReshapeFunc(NULL);
17         place_z += 5.0;
18         display();
19     }
20 }
  • 这样就ok啦。到这里就完成了一开始提出四个目标以及一个reshape()函数。效果就如最开始的gif动画一样。
  • 这里还需要提到的一点是,动画播放的速度在不同的cpu里是不一样的,如果太快或太慢可以通过myIdle函数的angle自增的大小来控制。
  • 为了避免混乱,最后附上完整的源代码。
  1 #include <GL/glut.h>
  2 #include <stdlib.h>
  3 #include <stdio.h>
  4
  5 static const GLfloat vertex_list[][3] = {
  6     - 15.0f, -20.0f, -10.0f,
  7     40.0f, -20.0f, -10.0f,
  8     40.0f,  20.0f, -10.0f,
  9     -15.0f,  20.0f, -10.0f,
 10     -15.0f, -20.0f,  10.0f,
 11     40.0f, -20.0f,  10.0f,
 12     -15.0f,  20.0f,  10.0f,
 13     40.0f,  20.0f,  10.0f,
 14  };
 15 GLuint texGround;
 16 GLuint texWall;
 17
 18 #define BMP_Header_Length 54
 19 static GLfloat angle = 0.0f;
 20 static float place_z = 60.0f;
 21 static float place_x = 0.0f;
 22 #define  GLUT_WHEEL_UP 3
 23 #define  GLUT_WHEEL_DOWN 4
 24
 25 // 函数power_of_two用于判断一个整数是不是2的整数次幂
 26 int power_of_two(int n)
 27 {
 28     if (n <= 0)
 29         return 0;
 30     return (n & (n - 1)) == 0;
 31 }
 32
 33 /* 函数load_texture
 34 * 读取一个BMP文件作为纹理
 35 * 如果失败,返回0,如果成功,返回纹理编号
 36 */
 37 GLuint load_texture(const char* file_name)
 38 {
 39     GLint width, height, total_bytes;
 40     GLubyte* pixels = 0;
 41     GLuint last_texture_ID = 0, texture_ID = 0;
 42
 43     // 打开文件,如果失败,返回
 44     FILE* pFile;
 45     errno_t err;
 46     err = fopen_s(&pFile, file_name, "rb");
 47     if (!pFile) exit(0);
 48
 49     // 读取文件中图象的宽度和高度
 50     fseek(pFile, 0x0012, SEEK_SET);
 51     fread(&width, sizeof(width), 1, pFile);
 52     fread(&height, sizeof(height), 1, pFile);
 53     fseek(pFile, BMP_Header_Length, SEEK_SET);
 54
 55     // 计算每行像素所占字节数,并根据此数据计算总像素字节数
 56     {
 57         GLint line_bytes = width * 3;
 58         while (line_bytes % 4 != 0)
 59             ++line_bytes;
 60         total_bytes = line_bytes * height;
 61     }
 62
 63     // 根据总像素字节数分配内存
 64     pixels = (GLubyte*)malloc(total_bytes);
 65     if (pixels == 0)
 66     {
 67         fclose(pFile);
 68         return 0;
 69     }
 70
 71     // 读取像素数据
 72     if (fread(pixels, total_bytes, 1, pFile) <= 0)
 73     {
 74         free(pixels);
 75         fclose(pFile);
 76         return 0;
 77     }
 78
 79     // 对就旧版本的兼容,如果图象的宽度和高度不是的整数次方,则需要进行缩放
 80     // 若图像宽高超过了OpenGL规定的最大值,也缩放
 81     {
 82         GLint max;
 83         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
 84         if (!power_of_two(width)
 85             || !power_of_two(height)
 86             || width > max
 87             || height > max)
 88         {
 89             const GLint new_width = 256;
 90             const GLint new_height = 256; // 规定缩放后新的大小为边长的正方形
 91             GLint new_line_bytes, new_total_bytes;
 92             GLubyte* new_pixels = 0;
 93
 94             // 计算每行需要的字节数和总字节数
 95             new_line_bytes = new_width * 3;
 96             while (new_line_bytes % 4 != 0)
 97                 ++new_line_bytes;
 98             new_total_bytes = new_line_bytes * new_height;
 99
100             // 分配内存
101             new_pixels = (GLubyte*)malloc(new_total_bytes);
102             if (new_pixels == 0)
103             {
104                 free(pixels);
105                 fclose(pFile);
106                 return 0;
107             }
108
109             // 进行像素缩放
110             gluScaleImage(GL_RGB,
111                 width, height, GL_UNSIGNED_BYTE, pixels,
112                 new_width, new_height, GL_UNSIGNED_BYTE, new_pixels);
113
114             // 释放原来的像素数据,把pixels指向新的像素数据,并重新设置width和height
115             free(pixels);
116             pixels = new_pixels;
117             width = new_width;
118             height = new_height;
119         }
120     }
121
122     // 分配一个新的纹理编号
123     glGenTextures(1, &texture_ID);
124     if (texture_ID == 0)
125     {
126         free(pixels);
127         fclose(pFile);
128         return 0;
129     }
130
131     // 绑定新的纹理,载入纹理并设置纹理参数
132     // 在绑定前,先获得原来绑定的纹理编号,以便在最后进行恢复
133     GLint lastTextureID = last_texture_ID;
134     glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastTextureID);
135     glBindTexture(GL_TEXTURE_2D, texture_ID);
136     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
137     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
138     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
139     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
140     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
141     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
142         GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
143     glBindTexture(GL_TEXTURE_2D, lastTextureID);  //恢复之前的纹理绑定
144     free(pixels);
145     return texture_ID;
146 }
147 void display(void)
148 {
149     glEnable(GL_DEPTH_TEST);
150     glClearColor(0, 0, 0, 1);
151     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
152
153     glMatrixMode(GL_PROJECTION);
154     glLoadIdentity();
155     gluPerspective(60.0, 1, 1.0, 100.0);
156
157     glMatrixMode(GL_MODELVIEW);
158     glLoadIdentity();  //加载单位矩阵  
159     gluLookAt(place_x, 0.0, place_z, 0, 0, 0, 0.0, 1.0, 0);
160     glRotatef(angle, 0.0f, 1.0f, 0.0f); //旋转
161
162     glColor3f(1.0, 0, 0);
163     glutSolidSphere(6, 20, 20);
164
165     glColor3f(0.0, 0, 1.0);
166     glTranslatef(-20.0, 0, 0);
167     glutSolidSphere(3, 20, 20);
168
169     glColor3f(1.0, 1.0, 0);
170     glTranslatef(-6.0, 0, 0);
171     glutSolidSphere(1, 20, 20);
172
173     glEnable(GL_TEXTURE_2D);
174     texGround = load_texture("ground.bmp");
175     texWall = load_texture("wall.bmp");
176
177     //绘制底面
178     glBindTexture(GL_TEXTURE_2D, texGround);
179     glBegin(GL_QUADS);
180     glTexCoord2f(0.0f, 0.0f); glVertex3fv(vertex_list[4]);
181     glTexCoord2f(1.0f, 0.0f); glVertex3fv(vertex_list[5]);
182     glTexCoord2f(1.0f, 1.0f); glVertex3fv(vertex_list[1]);
183     glTexCoord2f(0.0f, 1.0f); glVertex3fv(vertex_list[0]);
184     glEnd();
185     //绘制立面
186     glBindTexture(GL_TEXTURE_2D, texWall);
187     glBegin(GL_QUADS);
188     glTexCoord2f(0.0f, 0.0f); glVertex3fv(vertex_list[0]);
189     glTexCoord2f(1.0f, 0.0f); glVertex3fv(vertex_list[1]);
190     glTexCoord2f(1.0f, 1.0f); glVertex3fv(vertex_list[2]);
191     glTexCoord2f(0.0f, 1.0f); glVertex3fv(vertex_list[3]);
192     glEnd();
193     glDisable(GL_TEXTURE_2D);
194     glutSwapBuffers();
195 }
196 void myIdle(void)
197 {
198     angle += 1.8f;
199     if (angle >= 360.0f)
200         angle = 0.0f;
201     display();
202 }
203 void myMouse(int button, int state, int x, int y)
204 {
205     if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
206     {
207         glutIdleFunc(&myIdle);
208     }
209     if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
210     {
211         glutIdleFunc(NULL);
212     }
213     if (state == GLUT_UP && button == GLUT_WHEEL_UP)
214     {
215         glutReshapeFunc(NULL);
216         place_z -= 5.0;
217         display();
218     }
219     if (state == GLUT_UP && button == GLUT_WHEEL_DOWN)
220     {
221         glutReshapeFunc(NULL);
222         place_z += 5.0;
223         display();
224     }
225 }
226
227 void reshape(int w, int h)
228 {
229     glViewport(0, 0, 500, 500);
230     glMatrixMode(GL_PROJECTION);
231     glLoadIdentity();
232     gluPerspective(60.0, 1, 1, 100.0);
233     glMatrixMode(GL_MODELVIEW);
234     glLoadIdentity();
235     gluLookAt(0, 0.0, 60.0, 0, 0, 0, 0.0, 1.0, 0);
236 }
237 int main(int argc, char** argv)
238 {
239     glutInit(&argc, argv);
240     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
241     glutInitWindowSize(500, 500);
242     glutInitWindowPosition(100, 100);
243     glutCreateWindow("name");
244     glutMouseFunc(&myMouse);
245     glutDisplayFunc(&display);
246     glutReshapeFunc(&reshape);
247     glutIdleFunc(&myIdle);
248     glutMainLoop();
249     return 0;
250 }
05-15 03:29