opengl学习

#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;

}

 

你可能感兴趣的:(OpenGL)