#include"stdafx.h" #define GLUT_DISABLE_ATEXIT_HACK #include <GL/glut.h> //glut自动将gl.h和glu.h包含了 #include"math.h" #include <time.h> const int n = 20; const GLfloat R = 20.0f; const GLfloat Pi = 3.1415926536f; // 太阳、地球和月亮 // 假设每个月都是30天 // 一年12个月,共是360天 static int day = 200; // day的变化:从0到359 #define WIDTH 400 #define HEIGHT 400 static GLfloat angle = 0.0f; #define ColoredVertex(c, v) do{ glColor3fv(c); glVertex3fv(v); }while(0) void myDisplay5(void) { static int list = 0; if( list == 0 ) { // 如果显示列表不存在,则创建 /* GLfloat PointA[] = {-0.5, -5*sqrt(5)/48, sqrt(3)/6}, PointB[] = { 0.5, -5*sqrt(5)/48, sqrt(3)/6}, PointC[] = { 0, -5*sqrt(5)/48, -sqrt(3)/3}, PointD[] = { 0, 11*sqrt(6)/48, 0}; */ // 2007年4月27日修改 GLfloat PointA[] = { 0.5f, -sqrt(6.0f)/12, -sqrt(3.0f)/6}, PointB[] = {-0.5f, -sqrt(6.0f)/12, -sqrt(3.0f)/6}, PointC[] = { 0.0f, -sqrt(6.0f)/12, sqrt(3.0f)/3}, PointD[] = { 0.0f, sqrt(6.0f)/4, 0}; GLfloat ColorR[] = {1, 0, 0}, ColorG[] = {0, 1, 0}, ColorB[] = {0, 0, 1}, ColorY[] = {1, 1, 0}; //一、分配显示列表编号 //要分配i个连续的未使用的显示列表编号,返回的是分配的若干连续编号中最小的一个。 //。如果函数返回零,表示分配失败。 list = glGenLists(1); //二、创建显示列表 //glNewList有两个参数, //第一个参数是一个正整数表示装入到哪个显示列表。 //第二个参数有两种取值,如果为GL_COMPILE,则表示以下的内容只是装入到显示列表,但现在不执行它们; //如果为GL_COMPILE_AND_EXECUTE,表示在装入的同时,把装入的内容执行一遍。 glNewList(list, GL_COMPILE); //显示列表只能装入OpenGL函数,而不能装入其它内容 glBegin(GL_TRIANGLES); // 平面ABC ColoredVertex(ColorR, PointA); ColoredVertex(ColorG, PointB); ColoredVertex(ColorB, PointC); // 平面ACD ColoredVertex(ColorR, PointA); ColoredVertex(ColorB, PointC); ColoredVertex(ColorY, PointD); // 平面CBD ColoredVertex(ColorB, PointC); ColoredVertex(ColorG, PointB); ColoredVertex(ColorY, PointD); // 平面BAD ColoredVertex(ColorG, PointB); ColoredVertex(ColorR, PointA); ColoredVertex(ColorY, PointD); glEnd(); glEndList(); glEnable(GL_DEPTH_TEST); } // 已经创建了显示列表,在每次绘制正四面体时将调用它 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glRotatef(angle, 1, 0.5, 0); //三、调用显示列表 //使用glCallList函数可以调用一个显示列表。该函数有一个参数,表示要调用的显示列表的编号。 glCallList(list); glPopMatrix(); // //使用glDeleteLists来销毁一串编号连续的显示列表。 glutSwapBuffers(); } void myIdle2(void) { ++angle; if( angle >= 360.0f ) angle = 0.0f; myDisplay5(); } void myDisplay4(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 创建透视效果视图 glMatrixMode(GL_PROJECTION); glLoadIdentity(); //透视投影 gluPerspective(90.0f, 1.0f, 1.0f, 20.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 5.0, -10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); // 定义太阳光源,它是一种白色的光源 { GLfloat sun_light_position[] = {0.0f, 0.0f, 0.0f, 1.0f}; GLfloat sun_light_ambient[] = {0.0f, 0.0f, 0.0f, 1.0f}; GLfloat sun_light_diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f}; GLfloat sun_light_specular[] = {1.0f, 1.0f, 1.0f, 1.0f}; glLightfv(GL_LIGHT0, GL_POSITION, sun_light_position); glLightfv(GL_LIGHT0, GL_AMBIENT, sun_light_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, sun_light_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, sun_light_specular); glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); } // 定义太阳的材质并绘制太阳 { GLfloat sun_mat_ambient[] = {0.0f, 0.0f, 0.0f, 1.0f}; GLfloat sun_mat_diffuse[] = {0.0f, 0.0f, 0.0f, 1.0f}; GLfloat sun_mat_specular[] = {0.0f, 0.0f, 0.0f, 1.0f}; GLfloat sun_mat_emission[] = {0.5f, 0.0f, 0.0f, 1.0f}; GLfloat sun_mat_shininess = 0.0f; glMaterialfv(GL_FRONT, GL_AMBIENT, sun_mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, sun_mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, sun_mat_specular); glMaterialfv(GL_FRONT, GL_EMISSION, sun_mat_emission); glMaterialf (GL_FRONT, GL_SHININESS, sun_mat_shininess); glutSolidSphere(2.0, 40, 32); } // 定义地球的材质并绘制地球 { GLfloat earth_mat_ambient[] = {0.0f, 0.0f, 0.5f, 1.0f}; GLfloat earth_mat_diffuse[] = {0.0f, 0.0f, 0.5f, 1.0f}; GLfloat earth_mat_specular[] = {0.0f, 0.0f, 1.0f, 1.0f}; GLfloat earth_mat_emission[] = {0.0f, 0.0f, 0.0f, 1.0f}; GLfloat earth_mat_shininess = 30.0f; glMaterialfv(GL_FRONT, GL_AMBIENT, earth_mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, earth_mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, earth_mat_specular); glMaterialfv(GL_FRONT, GL_EMISSION, earth_mat_emission); glMaterialf (GL_FRONT, GL_SHININESS, earth_mat_shininess); glRotatef(angle, 0.0f, -1.0f, 0.0f); glTranslatef(5.0f, 0.0f, 0.0f); glutSolidSphere(2.0, 40, 32); } glutSwapBuffers(); //使用glLight*函数可设置光源的属性,使用glMaterial*函数可设置材质的属性,使用glLightModel*函数可设置光照模式。 } double CalFrequency() { static int count; static double save; static clock_t last, current; double timegap; ++count; if( count <= 50 ) return save; count = 0; last = current; current = clock(); timegap = (current-last)/(double)CLK_TCK; save = 50.0/timegap; return save; } void myDisplay2(void) { glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(75, 1, 1, 400000000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0, -200000000, 200000000, 0, 0, 0, 0, 0, 1); // 绘制红色的“太阳” glColor3f(1.0f, 0.0f, 0.0f); glutSolidSphere(69600000, 20, 20); // 绘制蓝色的“地球” glColor3f(0.0f, 0.0f, 1.0f); glRotatef(day/360.0*360.0, 0.0f, 0.0f, -1.0f); glTranslatef(150000000, 0.0f, 0.0f); glutSolidSphere(15945000, 20, 20); // 绘制黄色的“月亮” glColor3f(1.0f, 1.0f, 0.0f); glRotatef(day/30.0*360.0 - day/360.0*360.0, 0.0f, 0.0f, -1.0f); glTranslatef(38000000, 0.0f, 0.0f); glutSolidSphere(4345000, 20, 20); glFlush(); //小结:本课开始,我们正式进入了三维的OpenGL世界。 //OpenGL通过矩阵变换来把三维物体转变为二维图象,进而在屏幕上显示出来。 //为了指定当前操作的是何种矩阵,我们使用了函数glMatrixMode。 //我们可以移动、旋转观察点或者移动、旋转物体,使用的函数是glTranslate*和glRotate*。 //我们可以缩放物体,使用的函数是glScale*。 //我们可以定义可视空间,这个空间可以是“正投影”的(使用glOrtho或gluOrtho2D), //也可以是“透视投影”的(使用glFrustum或gluPerspective)。 //我们可以定义绘制到窗口的范围,使用的函数是glViewport。 //矩阵有自己的“堆栈”,方便进行保存和恢复。 //这在绘制复杂图形时很有帮助。使用的函数是glPushMatrix和glPopMatrix。 } void myDisplay3(void) { double FPS = CalFrequency(); printf("FPS = %f\n", FPS); glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(75, 1, 1, 400000000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0, -200000000, 200000000, 0, 0, 0, 0, 0, 1); // 绘制红色的“太阳” glColor3f(1.0f, 0.0f, 0.0f); glutSolidSphere(69600000, 20, 20); // 绘制蓝色的“地球” glColor3f(0.0f, 0.0f, 1.0f); glRotatef(day/360.0*360.0, 0.0f, 0.0f, -1.0f); glTranslatef(150000000, 0.0f, 0.0f); glutSolidSphere(15945000, 20, 20); // 绘制黄色的“月亮” glColor3f(1.0f, 1.0f, 0.0f); glRotatef(day/30.0*360.0 - day/360.0*360.0, 0.0f, 0.0f, -1.0f); glTranslatef(38000000, 0.0f, 0.0f); glutSolidSphere(4345000, 20, 20); glFlush(); glutSwapBuffers(); //OpenGL动画和传统意义上的动画相似,都是把画面一幅一幅的呈现在观众面前。 //一旦画面变换的速度快了,观众就会认为画面是连续的。 //双缓冲技术是一种在计算机图形中普遍采用的技术,绝大多数OpenGL实现都支持双缓冲技术。 //通常都是利用CPU空闲的时候绘制动画,但也可以有其它的选择。 //介绍了垂直同步的相关知识。 //介绍了一种简单的计算帧速(FPS)的方法。 } void myIdle1(void) { /* 新的函数,在空闲时调用,作用是把日期往后移动一天并重新绘制,达到动画效果 */ angle += 0.05f; if( angle >= 360.0f ) angle = 0.0f; myDisplay4(); } void myIdle(void) { /* 新的函数,在空闲时调用,作用是把日期往后移动一天并重新绘制,达到动画效果 */ ++day; if( day >= 360 ) day = 0; myDisplay3(); } //gl是基本函数库 //glu是gl的一些方便的和直观的高级应用 //这两个都和OS无关 //glut是和os打交道的库 //lut是一个系统无关的窗口系统,不用它就要用api或MFC画窗口,而glut窗口操作比较简单的,适合初学者或者编小型的程序 void init(void) { glClearColor(1.0,1.0,1.0,0.0); //设置当前操作的矩阵 glMatrixMode(GL_PROJECTION); //前把当前矩阵设置为单位矩阵。 //glLoadIdentity(); //将当前的可视空间设置为透视投影空间 //glFrustum(); //将当前的可视空间设置为正投影空间 gluOrtho2D(0.0,200.0,0.0,150.0); //使用glViewport来定义视口 //操作矩阵堆栈 //当我们需要保存时,调用glPushMatrix函数。 //当需要恢复最近一次的保存时,调用glPopMatrix函数。 } void myDisplay(void) { double FPS = CalFrequency(); printf("FPS = %f\n", FPS); glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0,0.0,0.0); glPolygonMode(GL_FRONT, GL_FILL); // 设置正面为填充模式 glPolygonMode(GL_BACK, GL_LINE); // 设置反面为线形模式 glFrontFace(GL_CCW); // 设置逆时针方向为正面 glBegin(GL_POLYGON); // 按逆时针绘制一个正方形,在左下方 glVertex2f(-10.5f, -10.5f); glVertex2f(10.0f, -10.5f); glVertex2f(10.0f, 10.0f); glVertex2f(-10.5f, 10.0f); glEnd(); glBegin(GL_POLYGON); // 按顺时针绘制一个正方形,在右上方 glVertex2f(10.0f, 10.0f); glVertex2f(10.0f, 15.0f); glVertex2f(15.0f, 15.0f); glVertex2f(15.0f, 10.0f); glEnd(); glFlush(); } void myDisplay1(void) { static GLubyte Mask[128]; FILE *fp; fp = fopen("11.bmp", "rb"); if( !fp ) exit(0); if( fseek(fp, -(int)sizeof(Mask), SEEK_END) ) exit(0); if( !fread(Mask, sizeof(Mask), 1, fp) ) exit(0); fclose(fp); glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0,0.0,0.0); glEnable(GL_POLYGON_STIPPLE); glPolygonStipple(Mask); glRectf(0.0f, 0.0f, 50.0f, 50.0f); // 在左下方绘制一个有镂空效果的正方形 glDisable(GL_POLYGON_STIPPLE); //glRectf(50.0f, 50.0f, 100.0f, 100.0f); // 在右上方绘制一个无镂空效果的正方形 glFlush(); } void lineSegment(void) { //清除。GL_COLOR_BUFFER_BIT表示清除颜色 glClear(GL_COLOR_BUFFER_BIT); //指定顶点颜色 glColor3f(1.0,0.0,0.0); //使用glNormal*函数则可以指定法线向量 //光源是通过glLight*函数来设置 //,OpenGL至少会支持8个光源,即GL_LIGHT0到GL_LIGHT7 //,glEnable(GL_LIGHT0);可以开启第0号光源。使用glDisable函数则可以关闭光源。 //光源的属性GL_AMBIENT、GL_DIFFUSE、GL_SPECULAR属性。这三个属性表示了光源所发出的光的反射特性(以及颜色) //GL_POSITION属性。表示光源所在的位置。 //)GL_SPOT_DIRECTION、GL_SPOT_EXPONENT、GL_SPOT_CUTOFF属性。表示将光源作为聚光灯使用(这些属性只对位置性光源有效) //OpenGL默认是关闭光照处理的。 //要打开光照处理功能,使用下面的语句: glEnable(GL_LIGHTING); //要关闭光照处理功能,使用glDisable(GL_LIGHTING);即可。 //材质则是通过glMaterial*函数来设置 //glBegin支持参数 //GL_POINTS点、GL_LINES线、 //GL_LINE_STRIP不闭合多边形、 //GL_LINE_LOOP闭合多边形、 //GL_TRIANGLES三角形、 //GL_TRIANGLE_STRIP、 //GL_TRIANGLE_FAN //GL_POLYGON //GL_QUODS //GL_QUOD_STRIP //设置点的大小,单位为像素,默认为1. glPointSize(5.0f); glBegin(GL_POINTS); glVertex2f(30.0f, 45.0f); glVertex2f(78.0f, 54.0f); glEnd(); //设置线的宽度,与glPointSize用法类似 glLineWidth(5.0f); //启动虚线模式 glEnable(GL_LINE_STIPPLE); glLineStipple(2, 0x0F0F); glBegin(GL_LINES); glVertex2i(100,0); glVertex2i(0,50); glEnd(); //关闭虚线模式 glDisable(GL_LINE_STIPPLE); //可知坐标系原点在窗口的左下角 int i; int x = 100,y = 50; //glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_POLYGON); for(i=0; i<n; ++i) glVertex2f(x + R*cos(2*Pi/n*i),y + R*sin(2*Pi/n*i)); glEnd(); /*从三维的角度来看,一个多边形具有两个面。 每一个面都可以设置不同的绘制方式:填充、只绘制边缘轮廓线、只绘制顶点, 其中“填充”是默认的方式。可以为两个面分别设置不同的方式。*/ //glPolygonMode(GL_FRONT, GL_FILL); 设置正面为填充方式 //glPolygonMode(GL_BACK, GL_LINE); 设置反面为边缘绘制方式 //glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // 设置两面均为顶点绘制方式 //一般约定为“顶点以逆时针顺序出现在屏幕上的面”为“正面”,另一个面即成为“反面”。 //glFrontFace(GL_CCW); // 设置CCW方向为“正面”,CCW即CounterClockWise,逆时针 //glFrontFace(GL_CW); // 设置CW方向为“正面”,CW即ClockWise,顺时针 //使用glEnable(GL_CULL_FACE);来启动剔除功能(使用glDisable(GL_CULL_FACE)可以关闭之) //使用glCullFace来进行剔除。参数可以是GL_FRONT,GL_BACK或者GL_FRONT_AND_BACK。 //直线可以被画成虚线,而多边形则可以进行镂空。 //首先,使用glEnable(GL_POLYGON_STIPPLE);来启动镂空模式(使用glDisable(GL_POLYGON_STIPPLE)可以关闭之)。 //然后,使用glPolygonStipple来设置镂空的样式。 //保证前面的OpenGL命令立即执行(而不是让它们在缓冲区中等待)。其作用跟fflush(stdout)类似。 glFlush(); } //argc 是指命令行输入参数的个数(以空白符分隔) argv存储了所有的命令行参数 int main(int argc, char **argv) { //以glut 开头的函数都是GLUT工具包所提供的函数 //对GLUT进行初始化,这个函数必须在其它的GLUT使用之前调用一次。 glutInit(&argc,argv); //设置显示方式 //GLUT_RGB表示使用RGB颜色,GLUT_INDEX表示使用索引颜色 //GLUT_SINGLE表示使用单缓冲,GLUT_DOUBLE使用双缓冲 glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB); //设置窗口在屏幕中的位置 glutInitWindowPosition(100,100); //设置窗口的大小 glutInitWindowSize(WIDTH,HEIGHT); //根据前面设置的信息创建窗口。参数将被作为窗口的标题。注意:窗口被创建后,并不立即显示到屏幕上。需要调用glutMainLoop才能看到窗口 glutCreateWindow("测试"); init(); //设置一个函数,当需要进行画图时,这个函数就会被调用 glutDisplayFunc(myDisplay4); glutIdleFunc(&myIdle1); // 新加入了这句,空闲时调用,实现动画效果 glutMainLoop(); return 0; }