[关闭]
@stepbystep 2015-01-30T17:49:44.000000Z 字数 7385 阅读 8204

C语言基于OpenGl绘制地球转动模型

实验楼


代码clone

本项目的代码已经上传到githup,通过如下命令可以下载代码

  1. git clone https://github.com/gostepbystep/EarthDemo.git

在配置好opengl和freeimage环境之后,运行效果图如下:

OpenGl简介

OpenGL是目前用于开发可移植的、可交互的2D和3D图形应用程序的首选环境,也是目前应用最广泛的计算机图形标准。OpenGL是SGI公司开发的一套的计算机图形处理系统,是图形硬件的软件接口,GL代表图形库(Graphics Library)。OpenGL具有可移植性,任何一个OpenGL应用程序无须考虑其运行环境所在平台与操作系统,在任何一个遵循OpenGL标准的环境下都会产生相同的可视效果。

OpenGL不是一种编程语言,而是一种API(Application Programming Interface,应用程序编程接口)。当我们说某个程序是基于OpenGL的或者说它是个OpenGL程序是,意思是说它是用某种编程语言如C或C++编写的,其中调用了一个或多个OpenGL库函数。作为一种API,OpenGL遵循C语言的调用约定。

OpenGL主要包括三个函数库,它们是核心库、实用函数库和编程辅助库。核心库中包含了OpenGL最基本的命令函数。核心库提供了一百多个函数,这些函数都以”gl”为前缀,用来建立各种各样的几何模型、进行坐标变换、产生光照效果、进行纹理映射、产生雾化效果等所有的二维和三维图形操作。实用函数库是比核心库更高一层的函数库,它提供四十多个函数,这些函数都以”glu”为前缀。由于OpenGL是一个图形标准,是独立于任何窗口系统或操作系统的,在OpenGL中没有提供窗口管理和消息事件响应的函数,也没有鼠标和键盘读取事件的功能,所以在编程辅助库提供了一些基本的窗口管理函数、事件处理函数和简单的事件函数。这类函数以”aux”作为前缀。值得一提的是,目前AUX编程辅助库已经很大程度上被GLUT库取代了。以下介绍以GLUT库为例。

GLUT代表OpenGL应用工具包(OpenGL Utility Toolkit),是一个与窗口系统无关的工具包。它作为AUX库的功能更强的替代品,用于隐藏不同窗口系统API的复杂性。GLUT的子程序的前缀使用”glut”。

实验楼下安装OpenGl简介

linux 下安装OpenGl很简单,只需要安装其所需的库就好了
首先更新源, 实验楼下root密码是shiyanlou

  1. sudo apt-get update

安装OpenGL Library

  1. sudo apt-get install build-essential

安装OpenGL Utilities
OpenGL Utilities 是一组建构于 OpenGL Library之上的工具组,提供许多很方便的函式,使 OpenGL更强大且更容易使用。接下来我们安装OpenGL Utilities

  1. sudo apt-get install libgl1-mesa-dev

安装OpenGL Utility Toolkit
OpenGL Utility Toolkit 是建立在 OpenGL Utilities 上面的工具箱,除了强化了 OpenGL Utilities 的不足之外,也增加了 OpenGL 对于视窗介面支援。

  1. sudo apt-get install libglu1-mesa-dev

安装freeglut3-dev

  1. $sudo apt-get install freeglut3-dev

安装过程截图

测试安装环境

用桌面的gedit新建一个文件,输入如下内容

  1. #include <GL/glut.h>
  2. void init(void){
  3. glClearColor(0.0,0.0,0.0,0.0);
  4. glMatrixMode(GL_PROJECTION);
  5. glOrtho(-5,5,-5,5,5,15);
  6. glMatrixMode(GL_MODELVIEW);
  7. gluLookAt(0,0,10,0,0,0,0,1,0);
  8. return;
  9. }
  10. void display(void){
  11. glClear(GL_COLOR_BUFFER_BIT);
  12. glColor3f(1.0,0,0);
  13. glutWireTeapot(3);
  14. glFlush();
  15. return;
  16. }
  17. int main(int argc,char *argv[]){
  18. glutInit(&argc,argv);
  19. glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
  20. glutInitWindowPosition(0,0);
  21. glutInitWindowSize(300,300);
  22. glutCreateWindow("OpenGL #D View");
  23. init();
  24. glutDisplayFunc(display);
  25. glutMainLoop();
  26. return 0;
  27. }

保存在Code目录下的test.c文件,如下图:

在命令行输入如下命令,编译文件,并执行文件

  1. gcc test.c -o test -lGL -lGLU -lglut
  2. ./test

如出现下图,那么恭喜你,OpenGl已经配置成功了

地球模型实验

freeimage安装

因为需要贴纹理图,获取bmp文件内容。本项目使用freeimage获取

  1. sudo apt-get install libfreeimage3
  2. sudo apt-get install libfreeimage-dev

此后的编译命令需要在末尾加上 -lfreeimage,如下:

  1. gcc main.c -o main -lGL -lGLU -lglut -lfreeimage

知识点讲解

GLUT采用一种函数注册的机制来实现OpenGL绘图。它的一般流程是:

新建文件并测试

新建main.c文件。
把earth.bmp图片从clone的目录中拷贝到与main.c同一目录下。

用geidt修改代码为:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <GL/glut.h>
  4. #include <GL/gl.h>
  5. #include <GL/glu.h>
  6. #include <FreeImage.h>
  7. #define GLUT_WHEEL_UP 3 //定义滚轮操作
  8. #define GLUT_WHEEL_DOWN 4
  9. // 定义Bmp的结构体
  10. struct _AUX_RGBImageRec {
  11. unsigned long sizeX; // X方向大小
  12. unsigned long sizeY; // y方向大小
  13. unsigned char *data; // 数据地址
  14. };
  15. typedef struct _AUX_RGBImageRec AUX_RGBImageRec;
  16. /*
  17. ** 定义变量
  18. */
  19. GLuint texture[1]; // 存储一个纹理
  20. GLfloat rtri; // 存储旋转变量,不断改变其值
  21. GLfloat zoom = 1.0f; // 缩放程度,默认为1,用于方大和缩小
  22. GLfloat xpos = 0.f; // x方向移动
  23. GLfloat ypos = 0.f; // y方向移动
  24. /*
  25. ** 利用freeimage加载bmp图像
  26. ** 此函数在Linux系统上可以作为常用util调用
  27. */
  28. GLboolean LoadBmp(const char* filename,
  29. AUX_RGBImageRec* texture_image) {
  30. FREE_IMAGE_FORMAT fifmt = FreeImage_GetFileType(filename, 0);
  31. FIBITMAP *dib = FreeImage_Load(fifmt, filename, 0);
  32. dib = FreeImage_ConvertTo24Bits(dib);
  33. int width = FreeImage_GetWidth(dib);
  34. int height = FreeImage_GetHeight(dib);
  35. BYTE *pixels = (BYTE*) FreeImage_GetBits(dib);
  36. int pix = 0;
  37. if (texture_image == NULL)
  38. return FALSE;
  39. texture_image->data = (BYTE *) malloc(width * height * 3);
  40. texture_image->sizeX = width;
  41. texture_image->sizeY = height;
  42. for (pix = 0; pix < width * height; pix++) {
  43. texture_image->data[pix * 3 + 0] = pixels[pix * 3 + 2];
  44. texture_image->data[pix * 3 + 1] = pixels[pix * 3 + 1];
  45. texture_image->data[pix * 3 + 2] = pixels[pix * 3 + 0];
  46. }
  47. FreeImage_Unload(dib);
  48. return TRUE;
  49. }
  50. int LoadGLTextures()
  51. // 载入位图(调用上面的代码)并转换成纹理
  52. {
  53. int Status=FALSE; // 状态指示器
  54. AUX_RGBImageRec *textureImage; // 创建纹理的存储空间
  55. textureImage = malloc(sizeof(AUX_RGBImageRec));
  56. // 载入位图,检查有无错误,如果位图没找到则退出
  57. if ( LoadBmp("earth.bmp", textureImage) )
  58. {
  59. Status=TRUE; // 将 Status 设为 TRUE
  60. glGenTextures(1, &texture[0]); // 创建纹理
  61. // 使用来自位图数据生成 的典型纹理
  62. glBindTexture(GL_TEXTURE_2D, texture[0]);
  63. // 生成纹理
  64. glTexImage2D(GL_TEXTURE_2D, 0, 3, textureImage->sizeX, textureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, textureImage->data);
  65. glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // 线形滤波
  66. glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // 线形滤波
  67. }
  68. if (textureImage) // 纹理是否存在
  69. {
  70. if (textureImage->data) // 纹理图像是否存在
  71. {
  72. free(textureImage->data); // 释放纹理图像占用的内存
  73. }
  74. free(textureImage); // 释放图像结构
  75. }
  76. return Status; // 返回 Status
  77. }
  78. // 初始化opengl
  79. void init(void){
  80. // 载入文理
  81. LoadGLTextures();
  82. glEnable(GL_TEXTURE_2D); // 启用纹理映射
  83. glShadeModel(GL_SMOOTH); // 启用阴影平滑
  84. glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // 黑色背景
  85. glClearDepth(1.0f); // 设置深度缓存
  86. glEnable(GL_DEPTH_TEST); // 启用深度测试
  87. glDepthFunc(GL_LEQUAL); // 所作深度测试的类型
  88. glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 真正精细的透视修正
  89. }
  90. /* 当窗口大小发生变化的时候调用 */
  91. void reshape (int w, int h)
  92. {
  93. glViewport (0, 0, (GLsizei) w, (GLsizei) h);
  94. glMatrixMode (GL_PROJECTION);
  95. glLoadIdentity ( );
  96. // 利用glOrtho创建一个正交平行的视景体
  97. if (w <= h){
  98. glOrtho (-1.5, 1.5, -1.5 * ( GLfloat ) h / ( GLfloat ) w,
  99. 1.5 * ( GLfloat ) h / ( GLfloat ) w, -10.0, 10.0 );
  100. }
  101. else{
  102. glOrtho (-1.5 * ( GLfloat ) w / ( GLfloat ) h,
  103. 1.5 * ( GLfloat ) w / ( GLfloat ) h, -1.5, 1.5, -10.0, 10.0);
  104. }
  105. glMatrixMode ( GL_MODELVIEW );
  106. glLoadIdentity ( ) ;
  107. }
  108. /* 定义对键盘的响应函数 */
  109. void keyboard ( unsigned char key, int x, int y)
  110. {
  111. /*按Esc键退出*/
  112. switch (key) {
  113. case 27:
  114. exit ( 0 );
  115. break;
  116. // 按下+的时候zoom缩放增加
  117. case '+':
  118. zoom += 0.03;
  119. break;
  120. // 按下-的时候zoom缩放减少
  121. case '-':
  122. zoom -= 0.03;
  123. break;
  124. // w,s 分别使模型上下移动
  125. case 'w':
  126. ypos += 0.03;
  127. break;
  128. case 's':
  129. ypos -= 0.03;
  130. break;
  131. // a,d 分别使模型左右移动
  132. case 'a':
  133. xpos -= 0.03;
  134. break;
  135. case 'd':
  136. xpos += 0.03;
  137. break;
  138. }
  139. printf("Enter Key %c zoom=%f, xpos=%f, ypos=%f \n", key);
  140. }
  141. void display(void){
  142. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存
  143. glLoadIdentity(); // 重置当前的模型观察矩阵
  144. // 此处加上xpos,ypos 产生移动效果
  145. glTranslatef(0.0f+xpos,0.0f+ypos,-5.0f); // 移入屏幕 5 个单位
  146. // 此处进行缩放,x,y,z方向均按此比例缩放
  147. glScalef(zoom, zoom, zoom);
  148. glRotatef(rtri,0.0f,1.0f,0.0f); // 绕Y轴旋转
  149. glBindTexture(GL_TEXTURE_2D, texture[0]);
  150. glBegin(GL_QUADS);//绘制四边形
  151. GLUquadric* quadricObj=gluNewQuadric(); //gluNewQuadric 创建一个新的二次曲面对象
  152. gluQuadricTexture(quadricObj,GL_TRUE);
  153. gluSphere(quadricObj,1,100,100); //参数1:二次曲面对象指针,参数2:球半径,参数3:Z轴方向片数,经度方向,参数4:Y轴方向片数,维度方向
  154. gluDeleteQuadric(quadricObj); //gluDeleteQuadric 删除一个二次曲面对象
  155. glEnd();//结束绘制
  156. // 通知硬件绘制图形
  157. glFinish();
  158. return;
  159. }
  160. /* 处理鼠标事件 */
  161. void processMouse(int button, int state, int x, int y)
  162. {
  163. if (state == GLUT_UP && button == GLUT_WHEEL_UP)
  164. { // 滚轮向上,表示方大,增加缩放比例
  165. zoom += 0.02;
  166. glutPostRedisplay();
  167. }
  168. if (state == GLUT_UP && button == GLUT_WHEEL_DOWN)
  169. {
  170. // 滚轮向下,表示缩小,减少缩放比例
  171. if(zoom > 0.02){
  172. // 防止zoom太小
  173. zoom -= 0.02;
  174. }
  175. glutPostRedisplay();
  176. }
  177. }
  178. // 自动旋转函数,用于修改绘制时所需要的参数
  179. void changeParam( void )
  180. {
  181. rtri += 0.05f; // 旋转变量自动加上0.05
  182. glutPostRedisplay ();
  183. }
  184. int main(int argc,char *argv[]){
  185. /* GLUT环境初始化*/
  186. glutInit (&argc, argv);
  187. /* 显示模式初始化 */
  188. glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
  189. /* 定义窗口大小 */
  190. glutInitWindowSize(600,600);
  191. /* 定义窗口位置 */
  192. glutInitWindowPosition (400, 400);
  193. /* 显示窗口,窗口标题为执行函数名 */
  194. glutCreateWindow("EarthDemo");
  195. /* 调用OpenGL初始化函数 */
  196. init ( );
  197. /* 注册OpenGL绘图函数 */
  198. glutDisplayFunc ( display );
  199. /* 注册窗口大小改变时的响应函数 */
  200. glutReshapeFunc ( reshape );
  201. /* 注册键盘响应函数 */
  202. glutKeyboardFunc ( keyboard );
  203. /* 注册鼠标事件 */
  204. glutMouseFunc( processMouse );
  205. /* 注册自动旋转的函数 */
  206. glutIdleFunc( changeParam );
  207. /* 进入GLUT消息循环,开始执行程序 */
  208. glutMainLoop( );
  209. return 0;
  210. }

编译代码
编译命令需要在末尾加上 -lfreeimage

  1. gcc main.c -o main -lGL -lGLU -lglut -lfreeimage

执行代码

  1. ./main

执行结果
点击如下地址,可以查看视频录制结果
http://7u2m19.com1.z0.glb.clouddn.com/earth-out-2.ogv

项目总结

OpenGl 在linux上做一些简单的界面显示效果非常好的。用起来也很方便,大家可以参考NeHe OpenGl教程学习相关知识。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注