OpenGL入门5——点、直线、多边形

来源:互联网 发布:如何使用网络电视 编辑:程序博客网 时间:2024/05/21 16:59

1、点的细节

      设置点的大小: void glPointSize( GLfloat size );//设置被渲染的点的宽度,以像素为单位。size必须大于0.0, 在默认情况下为1.0。

      glGetFloatv( );

      GL_ALLASED_POINT_PANGE 查询在未进行抗锯齿处理的情况下最小和最大的点。

      GL_SMOOTH_POINT_SIZE_RANGE:查询在进行了抗锯齿处理的情况下最小和最大的点。

      GL_SMOOTH_POINT_SIZE_GRANULARITY: 查询OpenGL支持的特定抗锯齿点大小的精度。

2、直线的细节

      void glLineWidth( GLfloat width);//以像素为单位设置宽度,用于直线的渲染。width参数必须大于0.0, 在默认情况下为1.0.
      注:OpenGL 3.1不支持大于1.0的值,并且如果指定了一个大于1.0的值,将会产生一个GL_INVALID_VALUE错误。

      通过glGetFloatv(),使用:

      GL_ALLASED_LINE_WIDTH_RANGE:查询系统所支持的带锯齿直线宽度的范围。

      GL_SMOOTH_LINE_WIDTH_RANGE:查询抗锯齿直线的最小和最大宽度。

      GL_SMOOTH_LINE_WIDTH_GRANULARITY:抗锯齿直线宽度的粒度。


     1*、点画线

     使用glLineStipple()函数定义点画模式,然后用glEnable()函数启用直线点画功能;

      如:glLineStipple( 1,  0x3F07);

              glEnable( GL_LINE_STIPPLE );

     原型: void glLineStipple( GLint factor, GLushort pattern);//设置直线的当前点画模式。pattern参数是一个由1或0组成的16位序列,从这个模式的低位开始,一个像素一个像素地进行处理。如果模型中对应的位是1,就绘制这个像素,否则就不绘制;参数factor(表示重复因子),它与pattern指定的序列相乘,来扩展模式,比如,如果pattern指定出现连续的3个1,并且factor为2,那么它们就扩展为6个连续的1。比如模式为0x3F07(二进制形式为0011111100000111),它所画出来的直线是这样的:先是连续绘制3个像素,然后连续5个像素留空,然后再连续绘制6个像素,最后2个像素留空(注意,首先开始的是低位)。如果factor是2,那么这个模式便扩展为:绘制6个像素、留空10个像素、绘制12个像素、最后留空4个像素。

     例如:模式          重复因子

              0x00FF       1              --------          --------          --------         --------

              0x00FF       2              ----------------                    ---------------

              

      注:如果没有启用点画线功能,OpenGL会自动把pattern当成是0xFFFF,把factor当成1.

3、多边形细节

注意:相邻的填充多边形如果共享一条边或者一个顶点,组成这条边或这个顶点的像素只绘制一次,它们只包含在其中一个多边形中,这样,部分透明的多边形的边不会绘制两次,它们的边缘看上去不会更亮或更暗。特别注意,这样可能导致狭窄的多边形有一行或多行(或列)像素未绘制。

      1*、void glPolygonMode( GLenum face, GLenum mode);//控制一个多边形的正面和背面的绘图模式

      face参数可以是GL_FRONT_AND_BACK, CL_FRONT或GL_BACK。

      mode参数可以是GL_POINT、GL_LINE或GL_FILL,表示多边形应该被画成点、轮廓哈市填充形式。在默认情况下,多边形的正面和背面都画成填充形式。

      例如:可以通过下面两个调用,把多边形的正面画成填充形式,把背面画成轮廓形式:

      glPolygonMode( GL_FRONT, GL_FILL);

      glPolygonMode( GL_BACK, GL_LINE );

     2* 、反转和剔除多边形表面

      按照约定,如果多边形的顶点以逆时针顺序出现在屏幕上,它便称为“正面”。可以根据方向一致的多边形构建任何“合理的”实心表面。按照数学的术语,这种表面称为可定向簇(orientable mainifold)。例如,球体、圆环体和茶壶都是可定向的,克莱因瓶(Klein bottles)和麦比乌斯带(Mobius strip)都是不可定向的。换句话说,为了创建可定向的表面,可以使用全部是逆时针方向的多边形,也可以使用全部是顺时针方向的多边形,这正是可定向的数学定义

     使用glFrontFace()函数,可以交换OpenGL的正面和背面的概念。

     void glFrontFace( GLenum mode);//控制多边形的正面是如何决定的。在默认情况下,mode是GL_CCW,它表示窗口坐标上投影多边形的顶点顺序为逆时针方向的表面为正面。如果mode是GL_CW,顶点顺序为顺时针方向的表面被认为是正面。

      注意:顶点的方向(顺时针或逆时针)又称为环绕(winding)。

      

    void glCullFace( GLenum mode);//注意,调用之前要调用glEnable函数,传递参数: GL_CULLFACE ,启动剔除功能。

    在一个完全闭合的表面(由方向一致的不透明多边形所组成)上,所有的背面多边形都是不可见的。因为它们总是被多边形的正面所遮挡。如果观察者位于这个表面的外侧,可以启动剔除(culling)功能,丢弃哪些被OpenGL认为是背面的多边形。类似地,如果观察者位于物体的内侧,只有背面的多边形才是可见的。

     该函数,表示哪些多边形在转换为屏幕坐标之前应该丢弃(剔除)。mode参数可以是GL_FRONT、GL_BACK或GL_FRONT_AND_BACK,分别表示正面多边形、背面多边形和所有多边形。

例子:

//多边形//glPolygonMode( GL_FRONT, GL_FILL );//glPolygonMode( GL_BACK, GL_LINE );//设置顶点顺时针方向为多边形正面。 glFrontFace( GL_CCW); glEnable( GL_CULL_FACE );//默认剔除多边形反面 glCullFace( /*GL_BACK*/ GL_FRONT /*GL_FRONT_AND_BACK */);glPolygonMode( GL_FRONT,  GL_LINE);glPolygonMode( GL_BACK, GL_FILL );//顺时针glBegin( GL_POLYGON );   glVertex2f(50.0, 250.0);   glVertex2f(200.0, 250.0);   glVertex2f(200.0, 200.0);   glVertex2f(50.0, 200.0);glEnd();//逆时针glBegin( GL_POLYGON );   glVertex2f(210.0, 200.0);   glVertex2f(360.0, 200.0);   glVertex2f(360.0, 250.0);   glVertex2f(210.0, 250.0);glEnd();glDisable( GL_CULL_FACE );glFlush();

     3*、点画多边形

      在默认情况下,填充多边形是用实心模式绘制的,此外,它们还可以使用一种32位*32位的窗口对齐的点画模式。

      glPolygonStipple()函数用于指定多边形的点画模式

      void glPolygonStipple( const GLubyte* mask );//定义填充多边形的当前点画模式

      mask参数是一个指向32*32位图的指针,后者被解释为0和1的掩码。如果模式中出现的是1,那么多边形中对应的像素就被绘制,如果出现的是0,多边形中对应的像素就不被绘制。mask数据的解释受到glPixelStore*() GL_UNPACK* 模式的影响。

      注:可以使用GL_POLYGON_STIPPLE为参数调用glEnable()和glDisable函数,分别启用和禁用多边形点画功能。

              在默认情况下,每个字节的最高有效位首先出现, 位顺序可以通过调用glPixelStore*()进行修改。

例子:

void polygonDisplay(){GLubyte fly[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x03, 0x80, 0x01, 0xC0, 0x06, 0xC0, 0x03, 0x60,0x04, 0x60, 0x06, 0x20, 0x04, 0x0C, 0x30, 0x20,0x04, 0x18, 0x18, 0x20, 0x04, 0x0C, 0x30, 0x20,0x04, 0x06, 0x60, 0x20, 0x44, 0x03, 0xC0, 0x22,0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,0x44, 0x01, 0x80, 0x22, 0444, 0x01, 0x80, 0x22,0x66, 0x01, 0x80, 0x66, 0x33, 0x01, 0x80, 0xcc,0x19, 0x81, 0x81, 0x98, 0x0c, 0xc1, 0x83, 0x30,0x07, 0xe1, 0x87, 0xe0, 0x03, 0x3f, 0xfc, 0xc0,0x03, 0x31, 0x8c, 0xc0, 0x03, 0x33, 0xcc, 0xc0,0x06, 0x64, 0x26, 0x60, 0x0c, 0xcc, 0x33, 0x30,0x18, 0xcc, 0x33, 0x18, 0x10, 0xc4, 0x23, 0x08,0x10, 0x63, 0xc6, 0x08, 0x10, 0x30, 0x0c, 0x08,0x10, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, 0x08};GLubyte halftone[] = {0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55};glClear( GL_COLOR_BUFFER_BIT );glColor3f( 1.0, 1.0, 1.0);glRectf( 25.0, 25.0, 125.0, 325.0);glEnable( GL_POLYGON_STIPPLE );glPolygonStipple( fly);glRectf( 125.0, 25.0, 225.0, 325.0);glPolygonStipple( halftone );glRectf( 225.0, 25.0, 325.0, 325.0 );glDisable( GL_POLYGON_STIPPLE );glFlush();}

       4*、标记多边形的边界边

       在默认情况下,多边形所有的顶点都标记为边界边的起点,但是可以使用glEdgeFlag*()函数手动控制边界标志(edge flag)的设置。这个函数在glBegin()和glEnd()之间调用,它将影响在它之后所指定的所有顶点,直到再次调用glEdgeFlag()函数。它只作用于那些为多边形、三角形和四边形所指定的顶点,对于那些为三角形带或四边形带所指定的顶点是无效的。

       void  glEdgeFlag( GLboolean flag);

       void  glEdgeFlag( const GLboolean *flag );//表示一个顶点是否应该被认为是多边形的一条边界边的起点。如果flag是GL_TRUE,边界标志就设置为TRUE( 默认),在此之后创建的所有顶点都认为是边界边的起点,直到用GL_FALSE为flag参数的值再次调用了这个函数。

      随便提一下 gluOrtho2D函数:

      void gluOrtho2D( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top );//定义一个二维正投影矩阵

      参数:left:左下角x坐标, right: 右上角x坐标, bottom:左下角y坐标,top,右上角y坐标,near、far默认为-1和1。此函数决定一个平行六面体, 即ViewVolume (视景体)。

      VIewVolume越大,里面的物体显得越小。

      例如:如果调用 gluOrtho2D( -5, 5, -5, 5);  那么一个点的坐标如果是(0,0,0),那么它就在ViewVolume(视景体,也就是一个平行六面体)的中央,也就在ViewPort(视口)的中央;如果一个点的坐标是(-5,-5,0),那么它就在ViewVolume的左下角,也就在viewPort的左下角。

      void glViewport( GLint x, GLint y, GLsizei width, GLsizei height);//定义视口像素范围。

      参数:x,, y 以像素为单位定义视口的左下角坐标位置; width、height,表示这个视口矩形的宽度和高度。

      ViewVolume中的坐标通过映射转换为Viewport中的坐标。

      

4、法线向量

     法线向量(简称法线)是一条垂直于某个表面的方向向量。

     对于平表面而言,它上面每个点的垂直方向都是相同的。但是对于普通的曲面而言,表面的每个点的法线方向各不相同。在OpenGL中,除了顶点之外,不能为多边形的其他地方分配法线。

     物体的法线向量定义了它的表面在空间中的方向。具体地说,定义了它相对于光源的方向。OpenGL使用法线向量确定这个物体的各个顶点所接收的光照。

     可以使用glNormal*()函数,把当前的法线向量设置为这个函数的参数所表示的值。以后调用glVertex*()时,就会把当前法线向量分配给它所指定的顶点。

     void  glNormal3{bsidf}( TYPE nx, TYPE ny, TYPE nz);

     void  glNormal3{bsidf}v( const TYPE* v);//根据参数设置当前的法线向量。b、s、i版本的函数会对它们的参数值进行线性缩放,使它们位于范围[-1.0, 1.0]之间。


5、顶点数组

    为什么需要顶点数组:

         (1)、OpenGL需要进行大量的函数调用才能完成对几何图元的渲染。绘制一个20条边的多边形至少需要22个函数调用。由于还需要额外的信息(多边形边界标志或表面法线),所以在每个顶点上还要增加函数调用。这可能会成倍增加渲染几何物体所需要的函数调用数量,在有些系统中,函数调用具有相当大的开销,可能会影响应用程序的性能。

        (2)、相邻多边形的共享顶点的冗余处理。立方体具有6个面和8个共享顶点,如果按照标准方法描述这个物体,每个顶点必须指定3次,一共要指定24个顶点,OpenGL提供了一些顶点数组函数,允许只用少数几个数组指定大量的与顶点相关的数据,并用少量函数调用(与顶点数组的数量相仿)访问这些数据。

        把数据放在顶点数组中可以提高应用程序的性能。使用顶点数组可以减少函数调用的次数,从而提高性能。另外,使用顶点数组还可以避免共享顶点的冗余处理。

      使用顶点数组对几何图形进行渲染的步骤:

       (1)、激活(启动)最多可达8个数组。每个数组用于存储不同类型的数据:顶点坐标、表面法线、RGBA颜色、辅助颜色、颜色索引、雾坐标、纹理坐标以及多边形的边界标志。

        void  glEnableClientState( GLenum  array );//指定需要启动的数组。

        void glDisableClientState( GLenum array);//指定需要禁用的数组。 

        参数 array 参数可以使用下面这些符号常量:

        GL_VERTEX_ARRAY、 GL_COLOR_ARRAY、GL_SEONDARY_COLOR_ARRAY、GL_INDEX_ARRAY、GL_NORMAL_ARRAY、GL_FOG_COORDINATE_ARRAY、GL_TEXTURE_COORD_ARRAY 和 GL_EDGE_FLAG_ARRAY。

        注意:glEnable、glDisable可以存储在显示列表中,但是顶点数组却不可以放在显示列表中,因为这些数据被保存在客户端。

        (2)、指定数组的数据

         在客户端-服务器模型中,这些数组存储在客户机的地址空间中,除非选择使用缓冲区对象,这时候数据存储在服务器内存中。

         可以用一条命令指定客户空间中的一个数组。共有8个不同的函数可以用来指定数组,每个函数用于指定一个不同类型的数组。另外,还可以用一个函数一次指定客户空间中的几个数组,它们均来源于一个混合数组。

        void glVertexPointer( GLint size, GLenum type, GLsize stride, const GLvoid *pointer);//指定了需要访问的空间坐标数据

        参数pointer是数组包含的第一个顶点的第一个坐标的内存地址。type指定了数组中每个坐标的数据类型(GL_SHORT、GL_INT、GL_FLOAT或GL_DOUBLE)。size是每个顶点的坐标数量,它必须是2,3或4.stride是连续顶点之间的字节偏移量。如果stride是0,数组中的顶点便是紧密相邻的。

        访问其他几个数组,可以使用下面这些类似的函数:

         void glColorPointer( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);

         void glSecondaryColorPointer( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);

         void glIndexPointer( GLenum type, GLsizei stride, const GLvoid *pointer);

         void glNormalPointer( GLenum type, GLsizei stride, const GLvoid* pointer);

         void glFogCoordPointer( GLenum type, GLsizei stride, const GLvoid* pointer);

         void glTexCoordPointer( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);

         void glEdgeFlagPointer( GLsizei stride, const GLvoid *pointer);

         注意:gl*Pointer()函数的stride(跨距)参数告诉OpenGL如何访问指针数组中的数据,特别再混合数组中指定相同类型的下一组数据的的偏移量。

       (3)、用这些数据绘制几何图形,解引用和渲染

         在顶点数组的内容被解引用(即提取指针所指向的数据)之前,数组一直保存在客户端中,它们的内容很容易进行修改。在该步骤中,数组中的数据被提取,接着发送到服务器,然后发送到图形处理管线进行渲染。

        可以从单个数组元素(索引位置)提起数据;也可以从一个有序的数组元素列表(可能被限制为整个顶点数组数据的一个子集)中提取数据,或者从一个数组元素序列中提取数据。

        3-1、解引用单个数组元素

        void  glArrayElement( GLint ith);//获取当前所有已启用数组的一个顶点(第ith个)的数据。

        注意:glArrayElement()通常在glBegin()和glEnd()之间调用,否则,glArrayElement()函数就会设置所有启动的数组的当前状态(顶点除外,因为它不存在当前状态)。

        例如:

         使用glArrayElement()定义颜色和顶点。

glEnableClientState( GL_COLOR_ARRAY );glEnableClientState( GL_VERTEX_ARRAY);glColorPointer( 3, GL_FLOAT, 0, colors);glVertexPointer( 2, GL_INT, 0, vertices);glBegin( GL_TRIANGLES);glArrayElement( 2 );glArrayElement( 3 );glArrayElement( 5 );glEnd();//当这段代码执行时,最后5行代码和下面的代码具有相同的效果:glBegin( GL_TRIANGLES );     glColor3fv( colors + (2 * 3 ) );     glVertex2iv( vertices + ( 2 * 2) );     glColor3fv( colors + (3 * 3));     glVertex2iv( vertices + (3 * 2) );     glColor3fv( colors + (5 * 3) );     glVertex2iv( vertices + (5 * 2));  glEnd();
     注意:如果数组的内容在glBegin()和glEnd()之间进行修改,就无法保证所获得的是最初的数据还是经过修改的数据。为了安全起见,在图元绘制完成之前,不要修改任何可能被访问的数组元素的内容。

       3-2、解引用数组元素的一个列表

       glArrayElement()对于随机存取数据的数组是非常有效的。与它类似的函数,例如glDrawElement()、glmultiDrawRangeElements()和glDrawRangeElements()则采用了一种更为有序的方式对数据数组进行随机存取。

       void glDrawElements( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);

       使用count个元素定义一个几何图元系列,这些元素的索引值保存在indices数组中。type必须是GL_UNSIGNED_BYTE、GL_UNSIGNED_SHORT或GL_UNSIGNED_INT,表示indices数组的数据类型。mode参数指定了被创建的是哪些类型的图元,它的值和glBegin()函数所接受的参数值相同,例如GL_POLYGON、GL_LINE_LOOP、GL_LINES和GL_POINTS等。

       glDrawElements()的效果差不多相当于下面这段代码:

       glBegin( mode );

             for(i=0; i<count; i++)

                  glArrayElement( indices[i] );

       glEnd();

       glDrawElements()还会执行检查,确保mode、count和type参数的值都是合法的。另外,和前一个代码序列不同,执行glDrawElements()会使几个状态处于不确定。在执行glDrawElements()之后,如果相应的数组被启用,当前的RGB颜色、辅助颜色、颜色索引、法线坐标、雾坐标、纹理坐标和边界标志将处于不确定状态。

       glDrawElements()的两种用法:

            static GLubyte frontIndices[] = { pt1, pt2, pt3, pt4};

            static Glubyte  backIndices[] = { pt5, pt6, pt7, pt8};

            glDrawElements( GL_QUADS, 4, GL_UNSIGNED_BTYE, frontIndices );

            glDrawElements( GL_QUADS, 4, GL_UNSIGNED_BTYE, backIndices );

       另一种方法:把几个索引列表压缩在一起,放在同一个数组中。如:

            static GLubyte  allIndices[] = { pt1, pt2, pt3, pt4, pt5, pt6, pt7, py8};

            glDrawElements( GL_QUADS, 8, GL_UNSIGNED_BYTE,  allIndices);      

      注意:除了GL_QUADS,对于其他的图元类型,把几个数组的索引值压缩在一个数组中可能会导致不同的渲染结果。例如:

            static Glubyte oneIndices[] = { pt0, pt1, p2, pt3, pt4, pt5, pt6};

            static Glubyte twoIndices[] = { pt7, pt8, pt9, pt10, pt11};

            glDrawElements( GL_LINE_STRIP, 7, GL_UNSIGNED_BYTE, oneIndices);

            glDrawElements( GL_LINE_STRIP, 6, GL_UNSIGNED_BYTE, twoIndices);

       注:以GL_LINE_STRIP为参数两次调用glDrawElements()将会渲染两条直线串。如果简单地组合这两个数组并只调用glDrawElements()函数一次,这样做的结果将只是一条直线带。


       glMultiDrawElements() 函数的作用是把几个glDrawElements()调用合并到1个函数调用中。可以避免上述的问题:

       void  glMultiDrawElements( GLenum mode, GLsizei *count, GLenum type, const GLvoid **indices, GLsizei primcount);//调用一系列的glDrawElements函数(数量为primcount个)。

       参数:indices是一个指针数组,包含了数组元素的列表。count是一个数组,包含了每个相应的数组元素列表中能够找到的顶点数量。mode(图元类型)和type( 数据类型)与它们在glDrawElements()函数中的含义相同。

       其效果相当于:

       for( i=0; i<primcount; i++) 

       {

              if( count[i] >0 )

                   glDrawElements( mode, count[i], type, indices[i] );

       }    

      例子:

       static GLubyte oneIndices[] = { p0, p1, p2, p3, p4, p5, p6};

       static GLubyte twoIndices[] = { p7, p1, p8, p9, p10, p11};

       static GLsizei count[] = { 7, 6};

       static GLvoid* indices[ 2 ] = { oneIndices, twoIndices };

       glMultiDrawElements( GL_LINE_STRIP, count, GL_UNSIGNED_BYTE, indices, 2);


       glDrawRangeElements()

       该函数也适用于随机存取的数据数组,用于对它们的内容进行渲染。 glDrawRangeElements()函数还对它所接受的合法索引值引入了范围限制,这可以提高程序的性能。为了实现优化的性能,有些OpenGL实现能够预先提取(在渲染之前获取)有限数量的顶点数组数据。glDrawRangeElements()允许指定预先提取的顶点的范围。

       void  glDrawRangeElements( GLenum mode, CLuint start, GLunit end, GLsizei count, GLenum type, const GLvoid *indices);

       参数:mode、count、type、indices和glDrawElements相同,start、end,指定indices可以接受的值的范围。indices数组中的值必须位于start和end之间才是合法的。

       注:调用glGetIntegerv()函数,指定GL_MAX_ELEMENTS_VERTICES参数,可以获取推荐的可以预先提取的最大顶点数量;

               指定GL_MAX_ELEMENTS_INDICES为参数,可以获取推荐的可以被引用的索引值的最大数量。


       3-3  解引用一个数组元素序列

       glDrawArrays不能对数据数组进行随机存取,只能按顺序访问它们。

       void  glDrawArrays( GLenum mode,  GLint first,  GLsizei count );//创建一个几何图元序列,使用每个被启用的数组中从first开始,到first + count - 1结束的数组元素。

        参数:mode指定创建的图元类型。

        该函数效果与下面代码差不多:(不同之处是错误检查,启动数组的不确定状态,与glDrawElements相似 )

        glBegin( mode );

             for(i=0; i<count; i++)

                   glArrayElement(first + i );

        glEnd();


       void glMultiDrawArrays( GLenum mode, GLint *first, GLsizei *count , GLsizei primcount);//调用一系列的glDrawArrays函数。

       相当于:

              for( i=0; i<primcount; i++ )

              {

                      if(count[i] >0)

                            glDrawArrays( mode, first[i], count[i]);

              }


6、重启图元

       OpenGl3.1通过指定一个专门由OpenGL处理的特定的值(图元重启索引),增加了在同一绘图调用中重启图元的能力。

       void  glPrimitiveRestartIndex(  GLuint index);//指定一个顶点数组元素索引,用来表示一个新的图元在渲染时的开始位置。当顶点数组元素索引的处理中遇到和index匹配的一个值的时候,就没有顶点数据需要处理了,当前的图元就终止了,相同类型的一个新图元开始。


7、实例化绘制

       void glDrawArrayInstanced( GLenum mode, GLint first, GLsizei count, GLsizei primcount);//primcount次有效调用glDrawArrays(), 在每次调用前设置GLSL顶点着色器gl_InstanceID。mode指定图元类型。first和count指定了传递给glDrawArrays()数组元素的范围。

      glDrawArrayInstanced()和如下的连续调用具有相同的效果(只不过我们的应用程序不必手动更新gl_InstanceID):

      for( i=0;  i<primcount; i++)

     {

             gl_InstanceID = i;

             glDrawArrays(mode, first, count);

     }

     gl_InstanceID = 0;

    

     void glDrawElementsInstanced( GLenum mode, GLsize count, GLenum type, const void *indicies, GLsizei primcount);

     该函数执行同样的操作,但是允许随机访问顶点数组中的数据。

     功能等同于:

     for( i=0; i<primcount; i++)

    {

            gl_InstanceID = i;

            glDrawElements( mode, count, type, indicies);

    }

    gl_InstanceID = 0;



补充:

绘制几何图元时,GL_LINES 与GL_LINE_STRIP的区别:

        1、GL_LINES:一对顶点被解释为一条直线;  GL_LINE_STRIP:一系列的连接直线;

        2、当绘制的点只有两个:V1、V2时,设置GL_LINES与设置GL_LINE_STRIP的效果是一样的,如:

         *使用GL_LINES:

glBegin( GL_LINES);

glVertex*( V1);

glVertex*( V2);

                glEnd();

                *使用GL_LINE_STRIP:

glBegin( GL_LINE_STRIP );

glVertex*( V1);

glVertex*( V2);

                        glEnd();

3、当连续绘制的点有多个时,二者会有明显的差异:

如:有一组顶点数据:V1、V2、V3、V4、V5、V6

                *使用GL_LINES:

                 glBegin( GL_LINES );

glVertex*( V1);

                                glVertex*( V2);

glVertex*( V3);

                                     ....

glVertex*(V6)

glEnd();

                 绘制结果:每一对顶点之间有直线连接,例如 V1与V2之间是直线连接的,V3与V4之间是直线连接的,V2与V3之间没有直线连接;

*使用GL_LINE_STRIP:

  glBegin( GL_LINE_STRIP );

glVertex*( V1);

                                glVertex*( V2);

glVertex*( V3);

                                     ....

glVertex*(V6)

                        glEnd();

绘制结果:相邻点之间都有直线连接,即V1与V2之间、V2与V3之间、V3与V4等都有直线连接。

0 0
原创粉丝点击