C语言使用OpenGL制作旋转地球
前置步骤(安装依赖库):
- sudo apt-get update
- sudo apt-get install build-essential
- sudo apt-get install libgl1-mesa-dev
- sudo apt-get install libglu1-mesa-dev
- $sudo apt-get install freeglut3-dev
- sudo apt-get install libfreeimage3 sudo apt-get install libfreeimage-dev
1.测试OpenGL环境
#include<GL/glut.h> void init() { glClearColor(0.0, 0.0, 0.0, 0.0); glMatrixMode(GL_PROJECTION); glOrtho(-5, 5, -5, 5, 5, 15); gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0); return ; } void display(void) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 0, 0); glutWireTeapot(3); glFlush(); return; } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(0, 0); glutInitWindowSize(300, 300); glutCreateWindow("OpenGL #D View"); init(); glutDisplayFunc(display); glutMainLoop(); return 0; }
编译:
gcc test.c -o test -lGL -lGLU -lglut
运行:
如果能出现这个图片,证明环境配置成功。
2.旋转地球模型
#include<stdio.h> #include<stdlib.h> #include<GL/glut.h> #include<GL/gl.h> #include<GL/glu.h> #include<FreeImage.h> #define GLUT_WHEEL_UP 3 #define GLUT_WHEEL_DOWN 4 struct _AUX_RGBImageRec { unsigned long sizeX; unsigned long sizeY; unsigned char *data; }; typedef struct _AUX_RGBImageRec AUX_RGBImageRec; GLuint texture[1]; //存储一个纹理 GLfloat rtri; //存储旋转变量,不断改变器值 GLfloat zoom = 1.0f; //缩放程度,默认位1,用于放大或缩小 GLfloat xpos = 0.f; //x方向移动 GLfloat ypos = 0.f; //y方向移动 void init(); void display(void); void reshape(int w, int h); void keyboard(unsigned char key, int x, int y); void processMouse(int button, int state, int x, int y); void changeParam(); int LoadGLTextures(); GLboolean LoadBmp(const char *filename, AUX_RGBImageRec* texture_image); int main(int argc, char **argv) { glutInit(&argc, argv); //GLUT环境初始化 //显示模式初始化 glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); //定义窗口daxiao glutInitWindowSize(600, 600); //定义窗口位置 glutInitWindowPosition(400, 600); //显示窗口位置,窗口标题为执行函数名 glutCreateWindow("EarthDemo"); //调用OpenGL初始化函数 init(); //注册OpenGL绘图函数 glutDisplayFunc(display); //注册窗口大小改变时的响应函数 glutReshapeFunc(reshape); //注册键盘响应事件 glutKeyboardFunc(keyboard); //注册鼠标响应事件 glutMouseFunc(processMouse); ////注册自动旋转的函数 glutIdleFunc(changeParam); //进入GLUT消息循环,开始执行函数 glutMainLoop(); return 0; } /*初始化openGL*/ void init() { LoadGLTextures(); //载入纹理 glEnable(GL_TEXTURE_2D); //启动纹路映射 glShadeModel(GL_SMOOTH); //启用阴影平滑 glClearColor(0.0f, 0.0f, 0.0f, 0.5f); //黑色背景 glClearDepth(1.0f); //设置深度缓存 glClearDepth(GL_DEPTH_TEST); //启用深度测试 glDepthFunc(GL_LEQUAL); //所作深度测试的类型 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //真正精细的透视修正 } /*载入位图(调用上面的代码)转换成纹理*/ int LoadGLTextures() { int Status = FALSE; //状态指示器 AUX_RGBImageRec *textureImage; //创建纹理的存储空间 textureImage = malloc(sizeof(AUX_RGBImageRec)); //载入位图,检查有无错误,如果位图没找到则退出 if (LoadBmp("earth.bmp", textureImage)) { Status = TRUE; glGenTextures(1, &texture[0]); //创建纹理的存储空间 /*使用来自位图数据生成的典型纹理*/ glBindTexture(GL_TEXTURE_2D, texture[0]); /*生成纹理*/ glTexImage2D(GL_TEXTURE_2D, 0, 3, textureImage->sizeX, textureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, textureImage->data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } //纹理是否存在 if (textureImage) { //纹理图像是否存在 if (textureImage->data) { free(textureImage->data); //释放纹理图像占用的内存 } free(textureImage); //释放图像结构 } return Status; } void display(void) { glClear(GL_COLOR_BUFFER_BIT); //清楚平面和深度缓存 glLoadIdentity(); //重置当前的模型观察矩阵 //加上xpos,ypos产生移动效果 glTranslatef(0.0f+xpos, 0.0f+ypos, -5.0f); //移入屏幕5个单位 //此处进行缩放, x,y,z,方向均按此比例缩放 glScalef(zoom, zoom, zoom); glRotatef(rtri, 0.0f, 1.0f, 0.0f); //绕Y轴旋转 glBindTexture(GL_TEXTURE_2D, texture[0]); glBegin(GL_QUADS); //绘制四边形 GLUquadric* quadricObj = gluNewQuadric(); //gluNewQuadric创建一个新的二次曲面对象 gluQuadricTexture(quadricObj, GL_TRUE); /*参数1:二次曲面对象指针 **参数2:球半径 **参数3:Z轴方向片数,经度方向 **参数4:Y周方向片数,纬度方向 */ gluSphere(quadricObj, 1, 100, 100); //gluDeleteQuadric删除一个二次曲面对象 gluDeleteQuadric(quadricObj); glEnd(); //通知硬件绘制图像 glFinish(); return ; } /*窗口大小发生变化时调用*/ void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); //利用glOrtho创建一个正交平行的视景体 if (w <= h) { glOrtho(-1.5, 1.5, -1.5*(GLfloat)h / (GLfloat)w, 1.5 *(GLfloat)h / (GLfloat)w, -10.0, 10.0); } else { glOrtho(-1.5*(GLfloat)w / (GLfloat)h, 1.5*(GLfloat)w / (GLfloat)h, -1.5, 1.5, -10.0, 10.0); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } /*定义对键盘的响应函数*/ void keyboard(unsigned char key, int x, int y) { switch ((key)) { /*ESC键退出*/ case 27: exit(0); break; case '+': //放大 zoom += 0.03; break; case '-': //缩小 zoom -= 0.03; break; case 'w': //上移 ypos += 0.03; break; case 's': //下移 ypos -= 0.03; break; case 'a': //左移 xpos -= 0.03; break; case 'd': //右移 xpos += 0.03; break; default: break; } printf("Enter Key %c zoom = %lf, xpos = %lf, ypos = %lf \n", key, zoom, xpos, ypos); } //处理鼠标事件 void processMouse(int button, int state, int x, int y) { if (state == GLUT_UP && button == GLUT_WHEEL_UP) { //滚轮向上,表示放大,增大缩放比例 zoom += 0.02; printf("Mouse Wheel UP\n"); glutPostRedisplay(); } if (state == GLUT_UP && button == GLUT_WHEEL_DOWN) { //滚轮向下,表示缩小,减少缩放比例 if (zoom > 0.02) { printf("Mouse Wheel Down\n"); zoom -= 0.02; } glutPostRedisplay(); } } // 自动旋转函数,用于修改绘制时所需要的参数 void changeParam() { rtri += 0.05f; glutPostRedisplay(); } /* *利用freeimage加载bmp图像 *此函数在Linux系统上可以作为util调用 */ GLboolean LoadBmp(const char *filename, AUX_RGBImageRec* texture_image) { FREE_IMAGE_FORMAT fifmt = FreeImage_GetFileType(filename, 0); FIBITMAP *dib = FreeImage_Load(fifmt, filename, 0); dib = FreeImage_ConvertTo24Bits(dib); int width = FreeImage_GetWidth(dib); int height = FreeImage_GetHeight(dib); BYTE *pixels = (BYTE*) FreeImage_GetBits(dib); int pix = 0; if (texture_image == NULL) { return FALSE; } texture_image->data = (BYTE*) malloc(width * height * 3); texture_image->sizeX = width; texture_image->sizeY = height; for (pix = 0; pix < width * height; pix++) { texture_image->data[pix*3 + 0] = pixels[pix * 3 + 2]; texture_image->data[pix*3 + 1] = pixels[pix * 3 + 1]; texture_image->data[pix*3 + 2] = pixels[pix * 3 + 0]; } FreeImage_Unload(dib); return TRUE; }
编译:
gcc main.c -o main -lGL -lGLU -lglut -lfreeimage
运行: