} } }

    OpenGL入门进修

    添加时间:2013-6-26 点击量:

    说起编程作图,可能还有很多人想起TC的#include <graphics.h>吧?


    然则各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640480辨别率、16色来做吗?显然是不可的。


    本帖的目标是让大师放弃TC的老旧图形接口,让大师接触一些新事物。


    OpenGL作为当前主流的图形API之一,它在一些场合具有比DirectX更优胜的特点。


    1、与C说话慎密连络。


    OpenGL号令最初就是用C说话函数来进行描述的,对于进修过C说话的人来讲,OpenGL是轻易懂得和进修的。若是你曾经接触过TC的graphics.h,你会发明,应用OpenGL作图甚至比TC加倍简单。


    2、强大的可移植性。


    微软的Direct3D固然也是十分优良的图形API,但它只用于Windows体系(如今还要加上一个XBOX游戏机)。而OpenGL不仅用于 Windows,还可以用于Unix/Linux等其它体系,它甚至在大型策画机、各类专业策画机(如:医疗用显示设备)上都有应用。并且,OpenGL 的根蒂根基号令都做到了硬件无关,甚至是平台无关。


    3、高机能的图形衬着。


    OpenGL是一个产业标准,它的技巧紧跟时代,现今各个显卡厂家无一不合错误OpenGL供给强力支撑,激烈的竞争中使得OpenGL机能一向领先。


    总之,OpenGL是一个很NB的图形软件接口。至于毕竟有多NB,去看看DOOM3和QUAKE4等专业游戏就知道了。


    OpenGL官方网站(英文)


    http://www.opengl.org


    下面将对Windows下的OpenGL编程进行简单介绍。


    进修OpenGL前的筹办工作


    第一步,选择一个编译景象


    如今Windows体系的主流编译景象有Visual Studio,Broland C++ Builder,Dev-C++等,它们都是支撑OpenGL的。但这里我们选择Visual Studio 2005作为进修OpenGL的景象。


    第二步,安装GLUT对象包


    GLUT不是OpenGL所必须的,但它会给我们的进修带来必然的便利,推荐安装。


    Windows景象下的GLUT地址:(大小约为150k)


    http://www.opengl.org/resources/libraries/glut/glutdlls37beta.zip


    无法从以上地址的话请应用下面的连接:


    http://upload.programfan.com/upfile/200607311626279.zip


    Windows景象下安装GLUT的步调:


    1、将的紧缩包解开,将获得5个文件


    2、在“我的电脑”中搜刮“gl.h”,并找到其地点文件夹(若是是VisualStudio2005,则应当是其安装目次下面的“VC\PlatformSDK\include\gl文件夹”)。把解压获得的glut.h放到这个文件夹。


    3、把解压获得的glut.lib和glut32.lib放到静态函数库地点文件夹(若是是VisualStudio2005,则应当是其安装目次下面的“VC\lib”文件夹)。


    4、把解压获得的glut.dll和glut32.dll放到操纵体系目次下面的system32文件夹内。(典范的地位为:C:\Windows\System32)


    第三步,建树一个OpenGL


    这里以VisualStudio2005为例。


    选择File->New->Project,然后选择Win32 Console Application,选择一个名字,然后按OK。


    在谈出的对话框左边点Application Settings,找到Empty project并勾上,选择Finish。


    然后向该添加一个代码文件,取名为“OpenGL.c”,重视用.c来作为文件结尾。


    搞定了,就跟日常平凡的没什么两样的。



    第一个OpenGL法度


    一个简单的OpenGL法度如下:(重视,若是须要编译并运行,须要正确安装GLUT,安装办法如上所述)


    #include <GL/glut.h>


    void myDisplay(void)


    {


         glClear(GL_COLOR_BUFFER_BIT);


         glRectf(-0.5f, -0.5f, 0.5f, 0.5f);


         glFlush();


    }


    int main(int argc, char argv[])


    {


         glutInit(&argc, argv);


         glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);


         glutInitWindowPosition(100, 100);


         glutInitWindowSize(400, 400);


         glutCreateWindow(第一个OpenGL法度);


         glutDisplayFunc(&myDisplay);


         glutMainLoop();


         return 0;


    }


    该法度的感化是在一个黑色的窗口中心画一个白色的矩形。下面对各行语句进行申明。


    起首,须要包含头文件#include <GL/glut.h>,这是GLUT的头文件。


    底本OpenGL法度一般还要包含<GL/gl.h>和<GL/glu.h>,但GLUT的头文件中已经主动将这两个文件包含了,不必再次包含。


    然后看main函数。


    int main(int argc, char argv[]),这个是带号令行参数的main函数,各位应当见过吧?没见过的同道们请多翻翻书,等弄熟悉打听了再往下看。


    重视main函数中的各语句,除了最后的return之外,其余全部以glut开首。这种以glut开首的函数都是GLUT对象包所供给的函数,下面对用到的几个函数进行介绍。


    1、glutInit,对GLUT进行初始化,这个函数必须在其它的GLUT应用之前调用一次。其格局斗劲呆板,一般照抄这句glutInit(&argc, argv)就可以了。


    2、 glutInitDisplayMode,设置显示体式格式,此中GLUT_RGB默示应用RGB色彩,与之对应的还有GLUT_INDEX(默示应用索引色彩)。GLUT_SINGLE默示应用单缓冲,与之对应的还有GLUT_DOUBLE(应用双缓冲)。更多信息,请本身Google。当然今后的教程也会有一些讲解。


    3、glutInitWindowPosition,这个简单,设置窗口在屏幕中的地位。


    4、glutInitWindowSize,这个也简单,设置窗口的大小。


    5、glutCreateWindow,按照前面设置的信息创建窗口。参数将被作为窗口的题目。重视:窗口被创建后,并不立即显示到屏幕上。须要调用glutMainLoop才干看到窗口。


    6、glutDisplayFunc,设置一个函数,当须要进行画图时,这个函数就会被调用。(这个说法不敷正确,但正确的说法可能初学者不太好懂得,临时如许说吧)。


    7、glutMainLoop,进行一个消息轮回。(这个可能初学者也不太熟悉打听,如今只须要知道这个函数可以显示窗口,并且守候窗口封闭后才会返回,这就足够了。)


    在glutDisplayFunc函数中,我们设置了“当须要画图时,请调用myDisplay函数”。于是myDisplay函数就用来画图。调查myDisplay中的三个函数调用,发明它们都以gl开首。这种以gl开首的函数都是OpenGL的标准函数,下面对用到的函数进行介绍。


    1、glClear,清除。GL_COLOR_BUFFER_BIT默示清除色彩,glClear函数还可以清除其它的器材,但这里不作介绍。


    2、glRectf,画一个矩形。四个参数分别默示了位于对角线上的两个点的横、纵坐标。


    3、glFlush,包管前面的OpenGL号令立即履行(而不是让它们在缓冲区中守候)。其感化跟fflush(stdout)类似。

    OpenGL入门进修[二]

    本次课程所要讲的是绘制简单的几何图形,在实际绘制之前,让我们先熟悉一些概念。

    一、点、直线和多边形
    我们知道数学(具体的说,是几何学)中有点、直线和多边形的概念,但这些概念在策画机中会有所不合。
    数学上的点,只有地位,没有大小。但在策画机中,无论策画精度如何进步,始终不克不及默示一个无穷小的点。另一方面,无论图形输出设备(例如,显示器)如何正确,始终不克不及输出一个无穷小的点。一般景象下,OpenGL中的点将被画成单个的像素(像素的概念,请本身搜刮之~),固然它可能足够小,但并不会是无穷小。同一像素上,OpenGL可以绘制很多坐标只有稍微不合的点,但该像素的具体色彩将取决于OpenGL的实现。当然,过度的重视细节就是钻牛角尖,我们大可不必花费过多的精力去研究“多个点如何画到同一像素上”。
    同样的,数学上的直线没有宽度,但OpenGL的直线则是有宽度的。同时,OpenGL的直线必须是有限长度,而不是像数学概念那样是无穷的。可以认为,OpenGL的“直线”概念与数学上的“线段”接近,它可以由两个端点来断定。
    多边形是由多条线段首尾相连而形成的闭合区域。OpenGL规定,一个多边形必须是一个“凸多边形”(其定义为:多边形内随便率性两点所断定的线段都在多边形内,由此也可以推导出,凸多边形不克不及是空心的)。多边形可以由其边的端点(这里可称为顶点)来断定。(重视:若是应用的多边形不是凸多边形,则最后输出的结果是不决义的——OpenGL为了效力,放宽了搜检,这可能导致显示错误。要避免这个错误,尽量应用三角形,因为三角形都是凸多边形)

    可以想象,经由过程点、直线和多边形,就可以组合成各类几何图形。甚至于,你可以把一段弧算作是很多短的直线段相连,这些直线段足够短,以至于其长度小于一个像素的宽度。如许一来弧和圆也可以默示出来了。经由过程位于不合平面的相连的小多边形,我们还可以构成一个“曲面”。

    二、在OpenGL中指定顶点
    由以上的评论辩论可以知道,“点”是一切的根蒂根基。
    如何指定一个点呢?OpenGL供给了一系列函数。它们都以glVertex开首,后面跟一个数字和1~2个字母。例如:
    glVertex2d
    glVertex2f
    glVertex3f
    glVertex3fv
    等等。
    数字默示参数的个数,2默示有两个参数,3默示三个,4默示四个(我知道有点罗嗦~)。
    字母默示参数的类型,s默示16位整数(OpenGL中将这个类型定义为GLshort),
                       i默示32位整数(OpenGL中将这个类型定义为GLint和GLsizei),
                       f默示32位浮点数(OpenGL中将这个类型定义为GLfloat和GLclampf),
                       d默示64位浮点数(OpenGL中将这个类型定义为GLdouble和GLclampd)。
                       v默示传递的几个参数将应用指针的体式格式,见下面的例子。
    这些函数除了参数的类型和个数不合以外,功能是雷同的。例如,以下五个代码段的功能是等效的:
    (一)glVertex2i(1, 3);
    (二)glVertex2f(1.0f, 3.0f);
    (三)glVertex3f(1.0f, 3.0f, 0.0f);
    (四)glVertex4f(1.0f, 3.0f, 0.0f, 1.0f);
    (五)GLfloat VertexArr3[] = {1.0f, 3.0f, 0.0f};
          glVertex3fv(VertexArr3);
    今后我们将用glVertex来默示这一系列函数。
    重视:OpenGL的很多函数都是采取如许的情势,一个雷同的前缀再加上参数申明标识表记标帜,这一点会跟着进修的深切而有更多的领会。


    三、开端绘制
    假设如今我已经指定了若干顶点,那么OpenGL是如何知道我想拿这些顶点来干什么呢?是一个一个的画出来,还是连成线?或者构成一个多边形?或者做其它什么工作?
    为懂得决这一题目,OpenGL请求:指定顶点的号令必须包含在glBegin函数之后,glEnd函数之前(不然指定的顶点将被忽视)。并由glBegin来指明如何应用这些点。
    例如我写:
    glBegin(GL_POINTS);
         glVertex2f(0.0f, 0.0f);
         glVertex2f(0.5f, 0.0f);
    glEnd();
    则这两个点将分别被画出来。若是将GL_POINTS调换成GL_LINES,则两个点将被认为是直线的两个端点,OpenGL将会画出一条直线。
    我们还可以指定更多的顶点,然后画出更错杂的图形。
    另一方面,glBegin支撑的体式格式除了GL_POINTS和GL_LINES,还有GL_LINE_STRIP,GL_LINE_LOOP,GL_TRIANGLES,GL_TRIANGLE_STRIP,GL_TRIANGLE_FAN等,每种体式格式的大致结果见下图:

    声明:该来自www.opengl.org,该是《OpenGL编程指南》一书的附图,因为该书的旧版(初版,1994年)已经撒播于收集,我没有触及到版权题目。

    我并不筹办在glBegin的各类体式格式上鸿文文章。大师可以本身测验测验改变glBegin的体式格式和顶点的地位,生成一些有趣的图案。

    法度代码:
    void myDisplay(void)
    {
         glClear(GL_COLOR_BUFFER_BIT);
         glBegin( / 在这里填上你所的模式 / );
            / 在这里应用glVertex系列函数 /
            / 指定你所的顶点地位 /
         glEnd();
         glFlush();
    }
    把这段代码改成你喜好的样子,然后用它调换第一课中的myDisplay函数,编译后即可运行。



    两个例子
    例一、画一个圆
    /
    正四边形,正五边形,正六边形,……,直到正n边形,当n越大时,这个图形就越接近圆
    当n大到必然程度后,人眼将无法把它跟真正的圆相差别
    这时我们已经成功的画出了一个“圆”
    (注:画圆的办法很多,这里应用的是斗劲简单,但效力较低的一种)
    试批改下面的const int n的值,调查当n=3,4,5,8,10,15,20,30,50等不合数值时输出的变更景象
    将GL_POLYGON改为GL_LINE_LOOP、GL_POINTS等其它体式格式,调查输出的变更景象
    /
    #include <math.h>
    const int n = 20;
    const GLfloat R = 0.5f;
    const GLfloat Pi = 3.1415926536f;
    void myDisplay(void)
    {
         int i;
         glClear(GL_COLOR_BUFFER_BIT);
         glBegin(GL_POLYGON);
         for(i=0; i<n; ++i)
             glVertex2f(Rcos(2Pi/ni), Rsin(2Pi/ni));
         glEnd();
         glFlush();
    }


    例二、画一个五角星
    /
    设五角星的五个顶点分布地位关系如下:
          A
    E        B

        D    C
    起首,按照余弦定理列方程,策画五角星的中间到顶点的间隔a
    (假设五角星对应正五边形的边长为.0)
    a = 1 / (2-2cos(72Pi/180));
    然后,按照正弦和余弦的定义,策画B的x坐标bx和y坐标by,以及C的y坐标
    (假设五角星的中间在坐标原点)
    bx = a cos(18 Pi/180);
    by = a sin(18 Pi/180);
    cy = -a cos(18 Pi/180);
    五个点的坐标就可以经由过程以上四个量和一些常数简单的默示出来
    /
    #include <math.h>
    const GLfloat Pi = 3.1415926536f;
    void myDisplay(void)
    {
         GLfloat a = 1 / (2-2cos(72Pi/180));
         GLfloat bx = a cos(18 Pi/180);
         GLfloat by = a sin(18 Pi/180);
         GLfloat cy = -a cos(18 Pi/180);
         GLfloat
             PointA[2] = { 0, a },
             PointB[2] = { bx, by },
             PointC[2] = { 0.5, cy },
             PointD[2] = { -0.5, cy },
             PointE[2] = { -bx, by };

         glClear(GL_COLOR_BUFFER_BIT);
         // 遵守A->C->E->B->D->A的次序,可以一笔将五角星画出
         glBegin(GL_LINE_LOOP);
             glVertex2fv(PointA);
             glVertex2fv(PointC);
             glVertex2fv(PointE);
             glVertex2fv(PointB);
             glVertex2fv(PointD);
         glEnd();
         glFlush();
    }


    例三、画出正弦函数的图形
    /
    因为OpenGL默认坐标值只能从-1到1,(可以批改,但办法留到今后讲)
    所以我们设置一个因子factor,把所有的坐标值等比例缩小,
    如许就可以画出更多个正弦周期
    试批改factor的值,调查变更景象
    /
    #include <math.h>
    const GLfloat factor = 0.1f;
    void myDisplay(void)
    {
         GLfloat x;
         glClear(GL_COLOR_BUFFER_BIT);
         glBegin(GL_LINES);
             glVertex2f(-1.0f, 0.0f);
             glVertex2f(1.0f, 0.0f);         // 以上两个点可以画x轴
             glVertex2f(0.0f, -1.0f);
             glVertex2f(0.0f, 1.0f);         // 以上两个点可以画y轴
         glEnd();
         glBegin(GL_LINE_STRIP);
         for(x=-1.0f/factor; x<1.0f/factor; x+=0.01f)
         {
             glVertex2f(xfactor, sin(x)factor);
         }
         glEnd();
         glFlush();
    }


    小结
    本课讲述了点、直线和多边形的概念,以及如何应用OpenGL来描述点,并应用点来描述几何图形。
    大师可以阐扬本身的想象,画出各类几何图形,当然,也可以用GL_LINE_STRIP把很多地位附近的点连接起来,构成函数图象。若是有爱好,也可以去找一些图象斗劲美观的函数,本身下手,用OpenGL把它画出来。

    =====================    第二课 完    =====================
    =====================TO BE CONTINUED=====================

    OpenGL入门进修[三]


    在第二课中,我们进修了如何绘制几何图形,但大师若是多写几个法度,就会发明其实还是有些愁闷之处。例如:点太小,难以看清楚;直线也太细,不舒畅;或者想画虚线,但不知道办法只能用很多短直线,甚至用点组合而成。


    这些题目将在本课中被解决。


    下面就点、直线、多边形分别评论辩论。


    1、关于点


    点的大小默认为1个像素,但也可以改变之。改变的号令为glPointSize,其函数原型如下:


    void glPointSize(GLfloat size);


    size必须大于0.0f,默认值为1.0f,单位为“像素”。


    重视:对于具体的OpenGL实现,点的大小都有个限度的,若是设置的size跨越最大值,则设置可能会有题目。


    例子:


    void myDisplay(void)


    {


         glClear(GL_COLOR_BUFFER_BIT);


         glPointSize(5.0f);


         glBegin(GL_POINTS);


             glVertex2f(0.0f, 0.0f);


             glVertex2f(0.5f, 0.5f);


         glEnd();


         glFlush();


    }


    2、关于直线


    (1)直线可以指定宽度:


    void glLineWidth(GLfloat width);


    其用法跟glPointSize类似。


    (2)画虚线。


    起首,应用glEnable(GL_LINE_STIPPLE);来启动虚线模式(应用glDisable(GL_LINE_STIPPLE)可以封闭之)。


    然后,应用glLineStipple来设置虚线的样式。


    void glLineStipple(GLint factor, GLushort pattern);


    pattern是由1和0构成的长度为16的序列,从最低位开端看,若是为1,则直线上接下来应当画的factor个点将被画为实的;若是为0,则直线上接下来应当画的factor个点将被画为虚的。


    以下是一些例子:



    声明:该来自www.opengl.org,该是《OpenGL编程指南》一书的附图,因为该书的旧版(初版,1994年)已经撒播于收集,我没有触及到版权题目。


    示例代码:


    void myDisplay(void)


    {


         glClear(GL_COLOR_BUFFER_BIT);


         glEnable(GL_LINE_STIPPLE);


         glLineStipple(2, 0 x0F0F);


         glLineWidth(10.0f);


         glBegin(GL_LINES);


             glVertex2f(0.0f, 0.0f);


             glVertex2f(0.5f, 0.5f);


         glEnd();


         glFlush();


    }


    3、关于多边形


    多边形的内容较多,我们将讲述以下四个方面。


    (1)多边形的两面以及绘制体式格式。


    固然我们今朝还没有真正的应用三维坐标来画图,然则建树一些三维的概念还是须要的。


    从三维的角度来看,一个多边形具有两个面。每一个面都可以设置不合的绘制体式格式:填充、只绘制边沿轮廓线、只绘制顶点,此中“填充”是默认的体式格式。可认为两个面分别设置不合的体式格式。


    glPolygonMode(GL_FRONT, GL_FILL);            // 设置正面为填充体式格式


    glPolygonMode(GL_BACK, GL_LINE);             // 设置不和为边沿绘制体式格式


    glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // 设置两面均为顶点绘制体式格式


    (2)反转


    一般商定为“顶点以逆时针次序呈如今屏幕上的面”为“正面”,另一个面即成为“不和”。生活生计中常见的物体概况,凡是都可以用如许的“正面”和“不和”,“公道的”被发挥解析出来(请找一个斗劲透明的矿泉水瓶子,在正对你的一面沿逆时针画一个圆,并标明画的标的目标,然后将后头转为正面,画一个类似的圆,领会一下“正面”和“不和”。你会发明正对你的标的目标,瓶的外侧是正面,而背对你的标的目标,瓶的内侧才是正面。正对你的内侧和背对你的外侧则是不和。如许一来,同样属于“瓶的外侧”这个概况,但某些处所算是正面,某些处所却算是不和了)。


    但也有一些概况斗劲特别。例如“麦比乌斯带”(请本身Google一下),可以全部应用“正面”或全部应用“后头”来默示。


    可以经由过程glFrontFace函数来互换“正面”和“不和”的概念。


    glFrontFace(GL_CCW);   // 设置CCW标的目标为“正面”,CCW即CounterClockWise,逆时针


    glFrontFace(GL_CW);    // 设置CW标的目标为“正面”,CW即ClockWise,顺时针


    下面是一个示例法度,请用它调换第一课中的myDisplay函数,并将glFrontFace(GL_CCW)批改为glFrontFace(GL_CW),并调查成果的变更。


    void myDisplay(void)


    {


         glClear(GL_COLOR_BUFFER_BIT);


         glPolygonMode(GL_FRONT, GL_FILL); // 设置正面为填充模式


         glPolygonMode(GL_BACK, GL_LINE);   // 设置不和为线形模式


         glFrontFace(GL_CCW);               // 设置逆时针标的目标为正面


         glBegin(GL_POLYGON);               // 按逆时针绘制一个正方形,在左下方


             glVertex2f(-0.5f, -0.5f);


             glVertex2f(0.0f, -0.5f);


             glVertex2f(0.0f, 0.0f);


             glVertex2f(-0.5f, 0.0f);


         glEnd();


         glBegin(GL_POLYGON);               // 按顺时针绘制一个正方形,在右上方


             glVertex2f(0.0f, 0.0f);


             glVertex2f(0.0f, 0.5f);


             glVertex2f(0.5f, 0.5f);


             glVertex2f(0.5f, 0.0f);


         glEnd();


         glFlush();


    }


    (3)剔除多边形概况


    在三维空间中,一个多边形固然有两个面,但我们无法看见后头的那些多边形,而一些多边形固然是正面的,但被其他多边形所遮挡。若是将无法看见的多边形和可见的多边形一律对待,无疑会降落我们处理惩罚图形的效力。在这种时辰,可以将不须要的面剔除。


    起首,应用glEnable(GL_CULL_FACE);来启动剔除功能(应用glDisable(GL_CULL_FACE)可以封闭之)


    然后,应用glCullFace来进行剔除。


    glCullFace的参数可所以GL_FRONT,GL_BACK或者GL_FRONT_AND_BACK,分别默示剔除正面、剔除不和、剔除正反两面的多边形。


    重视:剔除功能只影响多边形,而对点和直线无影响。例如,应用glCullFace(GL_FRONT_AND_BACK)后,所有的多边形都将被剔除,所以看见的就只有点和直线。


    (4)镂空多边形


    直线可以被画成虚线,而多边形则可以进行镂空。


    起首,应用glEnable(GL_POLYGON_STIPPLE);来启动镂空模式(应用glDisable(GL_POLYGON_STIPPLE)可以封闭之)。


    然后,应用glPolygonStipple来设置镂空的样式。


    void glPolygonStipple(const GLubyte mask);


    此中的参数mask指向一个长度为128字节的空间,它默示了一个3232的矩形应当如何镂空。此中:第一个字节默示了最左下方的从左到右(也可所以从右到左,这个可以批改)8个像素是否镂空(1默示不镂空,显示该像素;0默示镂空,显示厥后面的色彩),最后一个字节默示了最右上方的8个像素是否镂空。


    然则,若是我们直接定义这个mask数组,像如许:


    static GLubyte Mask[128] =


    {


         0 x00, 0 x00, 0 x00, 0 x00,    //   这是最下面的一行


         0 x00, 0 x00, 0 x00, 0 x00,


         0 x03, 0 x80, 0 x01, 0 xC0,    //   麻


         0 x06, 0 xC0, 0 x03, 0 x60,    //   烦


         0 x04, 0 x60, 0 x06, 0 x20,    //   的


         0 x04, 0 x30, 0 x0C, 0 x20,    //   初


         0 x04, 0 x18, 0 x18, 0 x20,    //   始


         0 x04, 0 x0C, 0 x30, 0 x20,    //   化


         0 x04, 0 x06, 0 x60, 0 x20,    //   ,


         0 x44, 0 x03, 0 xC0, 0 x22,    //   不


         0 x44, 0 x01, 0 x80, 0 x22,    //   建


         0 x44, 0 x01, 0 x80, 0 x22,    //   议


         0 x44, 0 x01, 0 x80, 0 x22,    //   使


         0 x44, 0 x01, 0 x80, 0 x22,    //   用


         0 x44, 0 x01, 0 x80, 0 x22,


         0 x44, 0 x01, 0 x80, 0 x22,


         0 x66, 0 x01, 0 x80, 0 x66,


         0 x33, 0 x01, 0 x80, 0 xCC,


         0 x19, 0 x81, 0 x81, 0 x98,


         0 x0C, 0 xC1, 0 x83, 0 x30,


         0 x07, 0 xE1, 0 x87, 0 xE0,


         0 x03, 0 x3F, 0 xFC, 0 xC0,


         0 x03, 0 x31, 0 x8C, 0 xC0,


         0 x03, 0 x3F, 0 xFC, 0 xC0,


         0 x06, 0 x64, 0 x26, 0 x60,


         0 x0C, 0 xCC, 0 x33, 0 x30,


         0 x18, 0 xCC, 0 x33, 0 x18,


         0 x10, 0 xC4, 0 x23, 0 x08,


         0 x10, 0 x63, 0 xC6, 0 x08,


         0 x10, 0 x30, 0 x0C, 0 x08,


         0 x10, 0 x18, 0 x18, 0 x08,


         0 x10, 0 x00, 0 x00, 0 x08    // 这是最上方的一行


    };


    如许一堆数据很是缺乏直观性,我们须要很费劲的去解析,才会发明它默示的竟然是一只苍蝇。


    若是将如许的数据保存成,并用专门的对象进行编辑,显然会便利很多。下面介绍如何做到这一点。


    起首,用Windows自带的画笔法度新建一副,取名为mask.bmp,重视保存时,应当选择“单色位图”。在“图象”->“属性”对话框中,设置的高度和宽度均为32。


    用放大镜调查,并编辑之。黑色对应二进制零(镂空),白色对应二进制一(不镂空),编辑完毕后保存。


    然后,就可以应用以下代码来获得这个Mask数组了。


    static GLubyte Mask[128];


    FILE fp;


    fp = fopen(mask.bmp, rb);


    if( !fp )


         exit(0);


    // 移动文件指针到这个地位,使得再读sizeof(Mask)个字节就会碰到文件停止


    // 重视-(int)sizeof(Mask)固然不是什么好的写法,但这里它确切是正确有效的


    // 若是直接写-sizeof(Mask)的话,因为sizeof取得的是一个无符号数,取负号会有题目


    if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )


         exit(0);


    // 读取sizeof(Mask)个字节到Mask


    if( !fread(Mask, sizeof(Mask), 1, fp) )


         exit(0);


    fclose(fp);


    好的,如今请本身编辑一个作为mask,并用上述办法取得Mask数组,运行后调查结果。


    申明:绘制虚线时可以设置factor因子,但多边形的镂空无法设置factor因子。请用鼠标改变窗口的大小,调查镂空结果的变更景象。


    #include <stdio.h>


    #include <stdlib.h>


    void myDisplay(void)


    {


         static GLubyte Mask[128];


         FILE fp;


         fp = fopen(mask.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);


         glEnable(GL_POLYGON_STIPPLE);


         glPolygonStipple(Mask);


         glRectf(-0.5f, -0.5f, 0.0f, 0.0f);   // 在左下方绘制一个有镂空结果的正方形


         glDisable(GL_POLYGON_STIPPLE);


         glRectf(0.0f, 0.0f, 0.5f, 0.5f);     // 在右上方绘制一个无镂空结果的正方形


         glFlush();


    }


    小结


    本课进修了绘制几何图形的一些细节。


    点可以设置大小。


    直线可以设置宽度;可以将直线画成虚线。


    多边形的两个面的绘制办法可以分别设置;在三维空间中,不成见的多边形可以被剔除;可以将填充多边形绘制成镂空的样式。


    懂得这些细节会使我们在一些图象绘制中加倍驾轻就熟。


    别的,把一些数据写到法度之外的文件中,并用专门的对象编辑之,有时可以显得更便利。


    =====================    第三课 完    =====================


    =====================TO BE CONTINUED=====================








    OpenGL入门进修[四]

    2008-10-06 21:26





    本次进修的是色彩的选择。终于要走出曲直短长的世界了~~


    OpenGL支撑两种色彩模式:一种是RGBA,一种是色彩索引模式。
    无论哪种色彩模式,策画机都必须为每一个像素保存一些数据。不合的是,RGBA模式中,数据直接就代表了色彩;而色彩索引模式中,数据代表的是一个索引,要获得真正的色彩,还必须去查索引表。

    1. RGBA色彩
    RGBA模式中,每一个像素会保存以下数据:R值(红色分量)、G值(绿色分量)、B值(蓝色分量)和A值(alpha分量)。此中红、绿、蓝三种色彩相组合,就可以获得我们所须要的各类色彩,而alpha不直接影响色彩,它将留待今后介绍。
    在RGBA模式下选择色彩是十分简单的工作,只须要一个函数就可以搞定。
    glColor系列函数可以用于设置色彩,此中三个参数的版本可以指定R、G、B的值,而A值采取默认;四个参数的版本可以分别指定R、G、B、A的值。例如:
    void glColor3f(GLfloat red, GLfloat green, GLfloat blue);
    void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
    (还记得吗?3f默示有三个浮点参数~请看第二课中关于glVertex函数的论述。)
    将浮点数作为参数,此中0.0默示不应用该种色彩,而1.0默示将该种色彩用到最多。例如:
    glColor3f(1.0f, 0.0f, 0.0f);    默示不应用绿、蓝色,而将红色应用最多,于是获得最纯净的红色。
    glColor3f(0.0f, 1.0f, 1.0f);    默示应用绿、蓝色到最多,而不应用红色。混淆的结果就是浅蓝色。
    glColor3f(0.5f, 0.5f, 0.5f);    默示各类色彩应用一半,结果为灰色。
    重视:浮点数可以正确到小数点后若干位,这并不默示策画机就可以显示如此多种色彩。实际上,策画机可以显示的色彩种数将由硬件决意。若是OpenGL找不到正确的色彩,会进行类似“四舍五入”的处理惩罚。

    大师可以经由过程改变下面代码中glColor3f的参数值,绘制不合色彩的矩形。
    void myDisplay(void)
    {
         glClear(GL_COLOR_BUFFER_BIT);
         glColor3f(0.0f, 1.0f, 1.0f);
         glRectf(-0.5f, -0.5f, 0.5f, 0.5f);
         glFlush();
    }

    重视:glColor系列函数,在参数类型不应时,默示“最大”色彩的值也不合。
    采取f和d做后缀的函数,以1.0默示大应用。
    采取b做后缀的函数,以127默示大应用。
    采取ub做后缀的函数,以255默示大应用。
    采取s做后缀的函数,以32767默示大应用。
    采取us做后缀的函数,以65535默示大应用。
    这些规矩看似麻烦,但熟悉后实际应用中不会有什么障碍。

    2、索引色彩
    在索引色彩模式中,OpenGL须要一个色彩表。这个表就相当于画家的调色板:固然可以调出很多种色彩,但同时存在于调色板上的色彩种数将不会跨越调色板的格数。试将色彩表的每一项想象成调色板上的一个格子:它保存了一种色彩。
    在应用索引色彩模式画图时,我说“我把第i种色彩设置为某某”,其实就相当于将调色板的第i格调为某某色彩。“我须要第k种色彩来画图”,那么就用画笔去蘸一下第k格调色板。
    色彩表的大小是很有限的,一般在256~4096之间,且老是2的整数次幂。在应用索引色彩体式格式进行画图时,老是先设置色彩表,然后选择色彩。

    2.1、选择色彩
    应用glIndex系列函数可以在色彩表中选择色彩。此中最常用的可能是glIndexi,它的参数是一个整形。
    void glIndexi(GLint c);
    是的,这的确很简单。

    2.2、设置色彩表
    OpenGL 并直接没有供给设置色彩表的办法,是以设置色彩表须要应用操纵体系的支撑。我们所用的Windows和其他大多半图形操纵体系都具有这个功能,但所应用的函数却不雷同。正如我没有讲述如何本身写代码在Windows下建树一个窗口,这里我也不会讲述如安在Windows下设置色彩表。
    GLUT对象包供给了设置色彩表的函数glutSetColor,但我测试始终有题目。如今为了让大师体验一下索引色彩,我向大师介绍另一个OpenGL对象包: aux。这个对象包是VisualStudio自带的,不必别的安装,但它已经过期,这里仅仅是体验一下,大师不必深切。
    #include <windows.h>
    #include <GL/gl.h>
    #include <GL/glaux.h>

    #pragma comment (lib, opengl32.lib)
    #pragma comment (lib, glaux.lib)

    #include <math.h>
    const GLdouble Pi = 3.1415926536;
    void myDisplay(void)
    {
         int i;
         for(i=0; i<8; ++i)
             auxSetOneColor(i, (float)(i&0 x04), (float)(i&0 x02), (float)(i&0 x01));
         glShadeModel(GL_FLAT);
         glClear(GL_COLOR_BUFFER_BIT);
         glBegin(GL_TRIANGLE_FAN);
         glVertex2f(0.0f, 0.0f);
         for(i=0; i<=8; ++i)
         {
             glIndexi(i);
             glVertex2f(cos(iPi/4), sin(iPi/4));
         }
         glEnd();
         glFlush();
    }

    int main(void)
    {
         auxInitDisplayMode(AUX_SINGLE|AUX_INDEX);
         auxInitPosition(0, 0, 400, 400);
         auxInitWindow(L);
         myDisplay();
         Sleep(10 1000);
         return 0;
    }

    其它项目组大师都可以不管,只看myDisplay函数就可以了。起首,应用auxSetOneColor设置色彩表中的一格。轮回八次就可以设置八格。
    glShadeModel等下再讲,这里不提。
    然后在轮回顶用glVertex设置顶点,同时用glIndexi改变顶点代表的色彩。
    终极获得的结果是八个雷同外形、不合色彩的三角形。

    索引色彩固然讲得多了点。索引色彩的首要上风是占用空间小(每个像素不必零丁保存本身的色彩,只用很少的二进制位就可以代表其色彩在色彩表中的地位),花费体系资料少,图形运算速度快,但它编程稍稍显得不是那么便利,并且画面结果也会比RGB色彩差一些。“星际争霸”可能代表了256色的色彩表的画面结果,固然它在一台很烂的PC上也可以运行很流畅,但以今朝的目光来看,其画面结果就显得不足了。
    今朝的PC机机能已经足够在各类场合下应用RGB色彩,是以PC法度开辟中,应用索引色彩已经不是主流。当然,一些小型设备例如GBA、等,索引色彩还是有它的用武之地。


    3、指定清除屏幕用的色彩
    我们写:glClear(GL_COLOR_BUFFER_BIT);意思是把屏幕上的色彩清空。
    但实际上什么才叫“空”呢?在宇宙中,黑色代表了“空”;在一张白纸上,白色代表了“空”;在信封上,信封的色彩才是“空”。
    OpenGL用下面的函数来定义清楚屏幕后屏幕所拥有的色彩。
    在RGB模式下,应用glClearColor来指定“空”的色彩,它须要四个参数,其参数的意义跟glColor4f类似。
    在索引色彩模式下,应用glClearIndex来指定“空”的色彩地点的索引,它须要一个参数,其意义跟glIndexi类似。
    void myDisplay(void)
    {
         glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
         glClear(GL_COLOR_BUFFER_BIT);
         glFlush();
    }
    呵,这个还真简单~


    4、指定着色模型
    OpenGL容许为同一多边形的不合顶点指定不合的色彩。例如:
    #include <math.h>
    const GLdouble Pi = 3.1415926536;
    void myDisplay(void)
    {
         int i;
         // glShadeModel(GL_FLAT);
         glClear(GL_COLOR_BUFFER_BIT);
         glBegin(GL_TRIANGLE_FAN);
         glColor3f(1.0f, 1.0f, 1.0f);
         glVertex2f(0.0f, 0.0f);
         for(i=0; i<=8; ++i)
         {
             glColor3f(i&0 x04, i&0 x02, i&0 x01);
             glVertex2f(cos(iPi/4), sin(iPi/4));
         }
         glEnd();
         glFlush();
    }
    在默认景象下,OpenGL管帐算两点顶点之间的其它点,并为它们填上“合适”的色彩,使相邻的点的色彩值都斗劲接近。若是应用的是RGB模式,看起来就具有渐变的结果。若是是应用色彩索引模式,则其相邻点的索引值是接近的,若是将色彩表中接近的项设置成接近的色彩,则看起来也是渐变的结果。但若是色彩表中接近的项色彩却差距很大,则看起来可能是很新鲜的结果。
    应用glShadeModel函数可以封闭这种策画,若是顶点的色彩不合,则将顶点之间的其它点全部设置为与某一个点雷同。(直线今后指定的点的色彩为准,而多边形将以随便率性顶点的色彩为准,由实现决意。)为了避免这个不断定性,尽量在多边形中应用同一种色彩。
    glShadeModel的应用办法:
    glShadeModel(GL_SMOOTH);    // 腻滑体式格式,这也是默认体式格式
    glShadeModel(GL_FLAT);      // 单色体式格式

    小结:
    本课进修了如何设置色彩。此中RGB色彩体式格式是今朝PC机上的常用体式格式。
    可以设置glClear清除后屏幕所剩的色彩。
    可以设置色彩填充体式格式:腻滑体式格式或单色体式格式。

    =====================    第四课 完    =====================
    =====================TO BE CONTINUED=====================


    彼此相爱,却不要让爱成了束缚:不如让它成为涌动的大海,两岸乃是你们的灵魂。互斟满杯,却不要同饮一杯。相赠面包,却不要共食一个。一起歌舞欢喜,却依然各自独立,相互交心,却不是让对方收藏。因为唯有生命之手,方能收容你们的心。站在一起却不要过于靠近。—— 纪伯伦《先知》
    分享到: