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
", 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
", 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;
}
原文地址:https://www.cnblogs.com/cugwx/p/3711170.html