• 常用的opengl函数(三)


    glBlendFunc 定义像素算法。
     
    void WINAPI glBlendFunc(GLenum sfactor,GLenum dfactor);

    参数编辑

    sfactor
    指定红绿蓝和 alpha 源混合因子如何计算。初始值为GL_ONE。 接受了九个符号常量: GL_ONE_MINUS_DST_ALPHA,GL_ZERO GL_ONE,GL_DST_COLOR GL_ONE_MINUS_DST_COLOR,GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA,GL_DST_ALPHA 和 GL_SRC_ALPHA_SATURATE。
    dfactor
    指定红绿蓝和 alpha 目标混合因子如何计算。初始值为GL_ZERO。 接受了八个符号常量: GL_ZERO GL_ONE,GL_SRC_COLOR GL_ONE_MINUS_SRC_COLOR,GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA,GL_DST_ALPHA,和 GL_ONE_MINUS_DST_ALPHA。
    一、源因子和目标因子
    前面我们已经提到,混合需要把原来的颜色和将要画上去的颜色找出来,经过某种方式处理后得到一种新的颜色。这里把将要画上去的颜色称为“源颜色”,把原来的颜色称为“目标颜色”
    OpenGL 会把源颜色和目标颜色各自取出,并乘以一个系数(源颜色乘以的系数称为“源因子”,目标颜色乘以的系数称为“目标因子”),然后相加,这样就得到了新的颜 色。(也可以不是相加,新版本的OpenGL可以设置运算方式,包括加、减、取两者中较大的、取两者中较小的、逻辑运算等,但我们这里为了简单起见,不讨 论这个了)
    下面用数学公式来表达一下这个运算方式。假设源颜色的四个分量(指红色,绿色,蓝色,alpha值)是(Rs, Gs, Bs,  As),目标颜色的四个分量是(Rd, Gd, Bd, Ad),又设源因子为(Sr, Sg, Sb, Sa),目标因子为(Dr, Dg, Db,  Da)。则混合产生的新颜色可以表示为:
    (Rs*Sr+Rd*Dr, Gs*Sg+Gd*Dg, Bs*Sb+Bd*Db, As*Sa+Ad*Da)
    当然了,如果颜色的某一分量超过了1.0,则它会被自动截取为1.0,不需要考虑越界的问题。

    源因子和目标因子是可以通过glBlendFunc函数来进行设置的。glBlendFunc有两个参数,前者表示源因子,后者表示目标因子。这两个参数可以是多种值,下面介绍比较常用的几种。
    GL_ZERO:     表示使用0.0作为因子,实际上相当于不使用这种颜色参与混合运算。
    GL_ONE:      表示使用1.0作为因子,实际上相当于完全的使用了这种颜色参与混合运算。
    GL_SRC_ALPHA:表示使用源颜色的alpha值来作为因子。
    GL_DST_ALPHA:表示使用目标颜色的alpha值来作为因子。
    GL_ONE_MINUS_SRC_ALPHA:表示用1.0减去源颜色的alpha值来作为因子。
    GL_ONE_MINUS_DST_ALPHA:表示用1.0减去目标颜色的alpha值来作为因子
    除 此以外,还有GL_SRC_COLOR(把源颜色的四个分量分别作为因子的四个分量)、GL_ONE_MINUS_SRC_COLOR、 GL_DST_COLOR、GL_ONE_MINUS_DST_COLOR等,前两个在OpenGL旧版本中只能用于设置目标因子,后两个在OpenGL 旧版本中只能用于设置源因子。新版本的OpenGL则没有这个限制,并且支持新的GL_CONST_COLOR(设定一种常数颜色,将其四个分量分别作为 因子的四个分量)、GL_ONE_MINUS_CONST_COLOR、GL_CONST_ALPHA、 GL_ONE_MINUS_CONST_ALPHA。另外还有GL_SRC_ALPHA_SATURATE。新版本的OpenGL还允许颜色的alpha 值和RGB值采用不同的混合因子。但这些都不是我们现在所需要了解的。毕竟这还是入门教材,不需要整得太复杂~

    举例来说:
    如果设置了glBlendFunc(GL_ONE, GL_ZERO);,则表示完全使用源颜色,完全不使用目标颜色,因此画面效果和不使用混合的时候一致(当然效率可能会低一点点)。如果没有设置源因子和目标因子,则默认情况就是这样的设置。
    如果设置了glBlendFunc(GL_ZERO, GL_ONE);,则表示完全不使用源颜色,因此无论你想画什么,最后都不会被画上去了。(但这并不是说这样设置就没有用,有些时候可能有特殊用途)
    如 果设置了glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);,则表示源颜色乘以自身的alpha 值,目标颜色乘以1.0减去源颜色的alpha值,这样一来,源颜色的alpha值越大,则产生的新颜色中源颜色所占比例就越大,而目标颜色所占比例则减 小。这种情况下,我们可以简单的将源颜色的alpha值理解为“不透明度”。这也是混合时最常用的方式。
    如果设置了glBlendFunc(GL_ONE, GL_ONE);,则表示完全使用源颜色和目标颜色,最终的颜色实际上就是两种颜色的简单相加。例如红色(1, 0, 0)和绿色(0, 1, 0)相加得到(1, 1, 0),结果为黄色。
    注意:
    所 谓源颜色和目标颜色,是跟绘制的顺序有关的。假如先绘制了一个红色的物体,再在其上绘制绿色的物体。则绿色是源颜色,红色是目标颜色。如果顺序反过来,则 红色就是源颜色,绿色才是目标颜色。在绘制时,应该注意顺序,使得绘制的源颜色与设置的源因子对应,目标颜色与设置的目标因子对应。不要被混乱的顺序搞晕 了。

    三、实现三维混合
    也许你迫不及待的想要绘制一个三维的带有半透明物体的场景了。但是现在恐怕还不行,还有一点是在进行三维场景的混合时必须注意的,那就是深度缓冲。
    深 度缓冲是这样一段数据,它记录了每一个像素距离观察者有多近。在启用深度缓冲测试的情况下,如果将要绘制的像素比原来的像素更近,则像素将被绘制。否则, 像素就会被忽略掉,不进行绘制。这在绘制不透明的物体时非常有用——不管是先绘制近的物体再绘制远的物体,还是先绘制远的物体再绘制近的物体,或者干脆以 混乱的顺序进行绘制,最后的显示结果总是近的物体遮住远的物体。
    然而在你需要实现半透明效果时,发现一切都不是那么美好了。如果你绘制了一个近距离的半透明物体,则它在深度缓冲区内保留了一些信息,使得远处的物体将无法再被绘制出来。虽然半透明的物体仍然半透明,但透过它看到的却不是正确的内容了。
    要 解决以上问题,需要在绘制半透明物体时将深度缓冲区设置为只读,这样一来,虽然半透明物体被绘制上去了,深度缓冲区还保持在原来的状态。如果再有一个物体 出现在半透明物体之后,在不透明物体之前,则它也可以被绘制(因为此时深度缓冲区中记录的是那个不透明物体的深度)。以后再要绘制不透明物体时,只需要再 将深度缓冲区设置为可读可写的形式即可。嗯?你问我怎么绘制一个一部分半透明一部分不透明的物体?这个好办,只需要把物体分为两个部分,一部分全是半透明 的,一部分全是不透明的,分别绘制就可以了。
    即使使用了以上技巧,我们仍然不能随心所欲的按照混乱顺序来进行绘制。必须是先绘制不透明的物体,然 后绘制透明的物体。否则,假设背景为蓝色,近处一块红色玻璃,中间一个绿色物体。如果先绘制红色半透明玻璃的话,它先和蓝色背景进行混合,则以后绘制中间 的绿色物体时,想单独与红色玻璃混合已经不能实现了。
    总结起来,绘制顺序就是:首先绘制所有不透明的物体。如果两个物体都是不透明的,则谁先谁后 都没有关系。然后,将深度缓冲区设置为只读。接下来,绘制所有半透明的物体。如果两个物体都是半透明的,则谁先谁后只需要根据自己的意愿(注意了,先绘制 的将成为“目标颜色”,后绘制的将成为“源颜色”,所以绘制的顺序将会对结果造成一些影响)。最后,将深度缓冲区设置为可读可写形式。
    调用glDepthMask(GL_FALSE);可将深度缓冲区设置为只读形式。调用glDepthMask(GL_TRUE);可将深度缓冲区设置为可读可写形式。
    一 些网上的教程,包括大名鼎鼎的NeHe教程,都在使用三维混合时直接将深度缓冲区禁用,即调用glDisable(GL_DEPTH_TEST);。这样 做并不正确。如果先绘制一个不透明的物体,再在其背后绘制半透明物体,本来后面的半透明物体将不会被显示(被不透明的物体遮住了),但如果禁用深度缓冲, 则它仍然将会显示,并进行混合。NeHe提到某些显卡在使用glDepthMask函数时可能存在一些问题,但可能是由于我的阅历有限,并没有发现这样的 情况。

    那么,实际的演示一下吧。我们来绘制一些半透明和不透明的球体。假设有三个球体,一个红色不透明的,一个绿色半透明的,一个蓝色半透明的。红色最远,绿色 在中间,蓝色最近。根据前面所讲述的内容,红色不透明球体必须首先绘制,而绿色和蓝色则可以随意修改顺序。这里为了演示不注意设置深度缓冲的危害,我们故 意先绘制最近的蓝色球体,再绘制绿色球体。
    为了让这些球体有一点立体感,我们使用光照。在(1, 1, -1)处设置一个白色的光源。代码如下:
    void setLight(void)
    {
        static const GLfloat light_position[] = {1.0f, 1.0f, -1.0f, 1.0f};
        static const GLfloat light_ambient[]  = {0.2f, 0.2f, 0.2f, 1.0f};
        static const GLfloat light_diffuse[]  = {1.0f, 1.0f, 1.0f, 1.0f};
        static const GLfloat light_specular[] = {1.0f, 1.0f, 1.0f, 1.0f};
    
        glLightfv(GL_LIGHT0, GL_POSITION, light_position);
        glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
        glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
        glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
    
        glEnable(GL_LIGHT0);
        glEnable(GL_LIGHTING);
        glEnable(GL_DEPTH_TEST);
    }
    每一个球体颜色不同。所以它们的材质也都不同。这里用一个函数来设置材质。
    void setMatirial(const GLfloat mat_diffuse[4], GLfloat mat_shininess)
    {
        static const GLfloat mat_specular[] = {0.0f, 0.0f, 0.0f, 1.0f};
        static const GLfloat mat_emission[] = {0.0f, 0.0f, 0.0f, 1.0f};
    
        glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_diffuse);
        glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
        glMaterialfv(GL_FRONT, GL_EMISSION,  mat_emission);
        glMaterialf (GL_FRONT, GL_SHININESS, mat_shininess);
    }
    有了这两个函数,我们就可以根据前面的知识写出整个程序代码了。这里只给出了绘制的部分,其它部分大家可以自行完成。
    void myDisplay(void)
    {
        // 定义一些材质颜色
        const static GLfloat red_color[] = {1.0f, 0.0f, 0.0f, 1.0f};
        const static GLfloat green_color[] = {0.0f, 1.0f, 0.0f, 0.3333f};
        const static GLfloat blue_color[] = {0.0f, 0.0f, 1.0f, 0.5f};
    
        // 清除屏幕
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        // 启动混合并设置混合因子
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
        // 设置光源
        setLight();
    
        // 以(0, 0, 0.5)为中心,绘制一个半径为.3的不透明红色球体(离观察者最远)
        setMatirial(red_color, 30.0);
        glPushMatrix();
        glTranslatef(0.0f, 0.0f, 0.5f);
        glutSolidSphere(0.3, 30, 30);
        glPopMatrix();
    
        // 下面将绘制半透明物体了,因此将深度缓冲设置为只读
        glDepthMask(GL_FALSE);
    
        // 以(0.2, 0, -0.5)为中心,绘制一个半径为.2的半透明蓝色球体(离观察者最近)
        setMatirial(blue_color, 30.0);
        glPushMatrix();
        glTranslatef(0.2f, 0.0f, -0.5f);
        glutSolidSphere(0.2, 30, 30);
        glPopMatrix();
    
        // 以(0.1, 0, 0)为中心,绘制一个半径为.15的半透明绿色球体(在前两个球体之间)
        setMatirial(green_color, 30.0);
        glPushMatrix();
        glTranslatef(0.1, 0, 0);
        glutSolidSphere(0.15, 30, 30);
        glPopMatrix();
    
        // 完成半透明物体的绘制,将深度缓冲区恢复为可读可写的形式
        glDepthMask(GL_TRUE);
    
        glutSwapBuffers();
    }
    

      



    大家也可以将上面两处glDepthMask删去,结果会看到最近的蓝色球虽然是半透明的,但它的背后直接就是红色球了,中间的绿色球没有被正确绘制。

    小结:
    本课介绍了OpenGL混合功能的相关知识。
    混合就是在绘制时,不是直接把新的颜色覆盖在原来旧的颜色上,而是将新的颜色与旧的颜色经过一定的运算,从而产生新的颜色。新的颜色称为源颜色,原来旧的颜色称为目标颜色。传统意义上的混合,是将源颜色乘以源因子,目标颜色乘以目标因子,然后相加。
    源 因子和目标因子是可以设置的。源因子和目标因子设置的不同直接导致混合结果的不同。将源颜色的alpha值作为源因子,用1.0减去源颜色alpha值作 为目标因子,是一种常用的方式。这时候,源颜色的alpha值相当于“不透明度”的作用。利用这一特点可以绘制出一些半透明的物体。
    在进行混合时,绘制的顺序十分重要。因为在绘制时,正要绘制上去的是源颜色,原来存在的是目标颜色,因此先绘制的物体就成为目标颜色,后来绘制的则成为源颜色。绘制的顺序要考虑清楚,将目标颜色和设置的目标因子相对应,源颜色和设置的源因子相对应。
    在进行三维混合时,不仅要考虑源因子和目标因子,还应该考虑深度缓冲区。必须先绘制所有不透明的物体,再绘制半透明的物体。在绘制半透明物体时前,还需要将深度缓冲区设置为只读形式,否则可能出现画面错误。
     
     

    void glBindVertexArray( GLuint array);

    绑定顶点数组对象

    array:指定顶点数组绑定的名称。

    Description

    glBindVertexArray binds the vertex array object with name arrayarray is the name of a vertex array object previously returned from a call to glGenVertexArrays, or zero to break the existing vertex array object binding.

    If no vertex array object with name array exists, one is created when array is first bound. If the bind is successful no change is made to the state of the vertex array object, and any previous vertex array object binding is broken.

    Errors

    GL_INVALID_OPERATION is generated if array is not zero or the name of a vertex array object previously returned from a call to glGenVertexArrays.

    glClear and glClearColor

    函数原型:

          void glClear(GLbitfield mask);

    参数说明:

          GLbitfield:可以使用 | 运算符组合不同的缓冲标志位,表明需要清除的缓冲,例如glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)表示要清除颜色缓冲以及深度缓冲,可以使用以下标志位

    •       GL_COLOR_BUFFER_BIT:    当前可写的颜色缓冲
    •       GL_DEPTH_BUFFER_BIT:    深度缓冲
    •       GL_ACCUM_BUFFER_BIT:   累积缓冲
    •   GL_STENCIL_BUFFER_BIT: 模板缓冲

    函数说明:

          glClear()函数的作用是用当前缓冲区清除值,也就是glClearColor或者glClearDepth、glClearIndex、glClearStencil、glClearAccum等函数所指定的值来清除指定的缓冲区,也可以使用glDrawBuffer一次清除多个颜色缓存。比如:

      glClearColor(0.0,0.0,0.0,0.0);

      glClear(GL_COLOR_BUFFER_BIT);

      第一条语句表示清除颜色设为黑色,第二条语句表示实际完成了把整个窗口清除为黑色的任务,glClear()的唯一参数表示需要被清除的缓冲区。注意(glclearColor()中的四个参数中,前三个分别代表红、绿、蓝所占的分量,范围从0.0f~1.0f,最后一个参数是透明度Alpha值,范围也是0.0f~1.0f。)

          像素检验、裁剪检验、抖动和缓存的写屏蔽都会影响glClear的操作,其中,裁剪范围限制了清除的区域,而glClear命令还会忽略alpha函数、融合函数、逻辑操作、模板、纹理映射和z缓存;

     glDepthMask允许或禁止向深度缓冲区写入数据

    void glDepthMask(GLboolean  flag);

    Parameters 参数

    flag

    Specifies whether the depth buffer is enabled for writing.If flag is GL_FALSE,depth buffer writing is disabled.Otherwise, it is enabled.Initially, depth buffer writing is enabled.指定是否允许向深度缓冲区写入数据。如果flag是GL_FLASE,那么向深度缓冲区写入是禁止的。否则,就是允许的。初始时,是允许向深度缓冲区写入数据的。

     

    Description 描述

    glDepthMask specifies whether the depth buffer is enabled for writing.If flag is GL_FALSE,depth buffer writing is disabled.Otherwise, it is enabled.Initially, depth buffer writing is enabled. glDepthMask指定是否允许向深度缓冲区写入数据。如果flag是GL_FLASE,那么向深度缓冲区写入是禁止的。否则,就是允许的。初始时,是允许向深度缓冲区写入数据的。

     

    Errors

    GL_INVALID_OPERATION is generated if glDepthMask is executed between the execution of glBegin and the corresponding execution of glEnd.如果在glBegin和glEnd之间执行glDepthMask,会产生GL_INVALID_OPERATION。

    glDepthFunc用于指定深度缓冲比较值

    参数取值范围

    GL_NEVER,GL_LESS,GL_EQUAL,GL_LEQUAL,GL_GREATER,GL_NOTEQUAL,GL_GEQUAL,GL_ALWAYS,缺省值GL_LESS。
    GL_NEVER,不通过(输入的深度值不取代参考值)
    GL_LESS,如果输入的深度值小于参考值,则通过
    GL_EQUAL,如果输入的深度值等于参考值,则通过
    GL_LEQUAL,如果输入的深度值小于或等于参考值,则通过
    GL_GREATER,如果输入的深度值大于参考值,则通过
    GL_NOTEQUAL,如果输入的深度值不等于参考值,则通过
    GL_GEQUAL,如果输入的深度值大于或等于参考值,则通过
    GL_ALWAYS,总是通过(输入的深度值取代参考值)

    错误码

    GL_INVALID_ENUM:参数值不合法。
    GL_INVALID_OPERATION:在glBegin和glEnd之间调用。
     
    glTexParameter纹理过滤函数

    功能

    图象从纹理图象空间映射到帧缓冲图象空间时,需要重新构造纹理图像,就会造成应用到多边形上的图像失真。这些函数相当于进行优化,以解决这类问题。

    简介编辑

    glTexParameter*,是OpenGL纹理过滤函数,共有以下几个(以下叙述以OpenGL ES2.0为例):
    void glTexParameteri(GLenum target, GLenum pname,GLint param);
    void glTexParameteriv(GLenum target, GLenum pname,const GLint *params);
    void glTexParameterf(GLenum target, GLenum pname,GLfloat param);
    void glTexParameterfv(GLenum target, GLenum pname,const GLfloat *params);
    参数说明:
    target:可以为GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D 和 GL_TEXTURE_CUBE_MAP。
    pname:此为要设置的纹理参数,可以取值如下:GL_TEXTURE_MAG_FILTER,GL_TEXTURE_MIN_FILTER,GL_TEXTURE_WRAP_S,GL_TEXTURE_WRAP_T。
    params:要设置的纹理参数的值。
    pname和params的取值对应关系如下:
    pname
    param
    GL_TEXTURE_MAG_FILTER
    GL_NEAREST、GL_LINEAR
    GL_TEXTURE_MIN_FILTER
    GL_NEAREST、GL_LINEAR、GL_NEAREST_MIPMAP_NEAREST、GL_NEAREST_MIPMAP_LINEAR、GL_LINEAR_MIPMAP_NEAREST、GL_LINEAR_MIPMAP_LINEAR
    GL_TEXTURE_WRAP_S、GL_TEXTURE_WRAP_T
    GL_REPEAT、GL_CLAMP_TO_EDGE、GL_MIRRORED_REPEAT

     GL_TEXTURE_2D: 操作2D纹理.
      GL_TEXTURE_WRAP_S: S方向上的贴图模式.
      GL_CLAMP: 将纹理坐标限制在0.0,1.0的范围之内.如果超出了会如何呢.不会错误,只是会边缘拉伸填充.
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
      这里同上,只是它是T方向
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      这是纹理过滤
      GL_TEXTURE_MAG_FILTER: 放大过滤
      GL_LINEAR: 线性过滤, 使用距离当前渲染像素中心最近的4个纹素加权平均值.
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
      GL_TEXTURE_MIN_FILTER: 缩小过滤
      GL_LINEAR_MIPMAP_NEAREST: 使用GL_NEAREST对最接近当前多边形的解析度的两个层级贴图进行采样,然后用这两个值进行线性插值.

    首先是GL_REPEAT,这个比较简单,就是重复边界的纹理。产生的效果如下:

    2. GL_CLAMP采用这种模式是,opengl就在一个2X2的加权纹理单元数组中使用取自边框的纹理单元。这时候的边框如果没有设置的话,应该就是原纹理的边界的像素值。

    3. GL_CLAMP_TO_EDGE,在这种模式下,边框始终被忽略。位于纹理边缘或者靠近纹理边缘的纹理单元将用于纹理计算,但不使用纹理边框上的纹理单元。在实验中,不管有没有设置边框,都与与上面的GL_CLAMP结果相同。在下面的参考文献中给了一个解释:因为很多硬件并不支持边界处理,所以实现GL_CLAMP_TP_EDGE和GL_CLAMP的效果好象是一样的。

    4.  GL_CLAMP_TO_BORDER如果纹理坐标位于范围[0,1]之外,那么只用边框纹理单元(如果没有边框,则使用常量边框颜色,我想常量边框颜色就是黑色)用于纹理。在靠近纹理坐标边缘的地方,无论是边框还是纹理内部都可能根据一个2X2的数组进行采样。

    5.   在GL_CLAMP_TO_BORDER的基础上使用上面的代码设置GL_TEXTURE_BORDER_COLOR(设置边框颜色为红色),可以得到下面的结果:

    glVertexAttribPointer---指定了渲染时索引值为 index 的顶点属性数组的数据格式和位置。

    void glVertexAttribPointer( GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,const GLvoid * pointer);
    参数:
     
    index
    指定要修改的顶点属性的索引值
    size
    指定每个顶点属性的组件数量。必须为1、2、3或者4。初始值为4。(如position是由3个(x,y,z)组成,而颜色是4个(r,g,b,a))
    type
    指定数组中每个组件的数据类型。可用的符号常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT,初始值为GL_FLOAT。
    normalized
    指定当被访问时,固定点数据值是否应该被归一化(GL_TRUE)或者直接转换为固定点值(GL_FALSE)。
     
    stride
    指定连续顶点属性之间的偏移量。如果为0,那么顶点属性会被理解为:它们是紧密排列在一起的。初始值为0。
    pointer
    指定第一个组件在数组的第一个顶点属性中的偏移量。该数组与GL_ARRAY_BUFFER绑定,储存于缓冲区中。初始值为0;

    描述 编辑

    glVertexAttribPointer 指定了渲染时索引值为 index 的顶点属性数组的数据格式和位置。size指定每个属性值的组件数量且必须为1、2、3、4之一。type指定每个组件的数据格式,stride指定了一个属性到下一个属性之间的步长(这就允许属性值被存储在单一数组或者不同的数组中)。当数组中的值被访问并被转换至浮点值时,如果normalized被设置为GL_TRUE,意味着整数型的值会被映射至区间[-1,1](有符号整数),或者区间[0,1](无符号整数),反之,这些值会被直接转换为浮点值而不进行归一化处理。
    如果一个名称非零的缓冲对象被绑定至GL_ARRAY_BUFFER目标(见glBindBuffer)且此时一个定点属性数组被指定了,那么pointer被当做该缓冲对象数据存储区的字节偏移量。并且,缓冲对象绑定(GL_ARRAY_BUFFER_BINDING)会被存为索引为index的顶点属性数组客户端状态(GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);(Also, the buffer object binding (GL_ARRAY_BUFFER_BINDING) is saved as generic vertex attribute array client-side state (GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING) for index index.)
    当一个顶点属性数组被指定时,除了当前的顶点数组缓冲对象绑定,size, type, normalized, stride, 和 pointer 也会被存为客户端状态
    要启用或者禁用顶点属性数组,调用glEnableVertexAttribArray和glDisableVertexAttribArray传入参数index。如果启用,那么当glDrawArrays或者glDrawElements被调用时,顶点属性数组会被使用。

    注意 编辑

    glDrawArrays或者glDrawElements被调用时,每个顶点属性数组初始状态是禁用的,不会被访问。
    glVertexAttribPointer一般在客户端实现。

    错误 编辑

    GL_INVALID_ENUM错误:如果 type 不是可接受的值。
    GL_INVALID_VALUE错误: 如果 index 大于等于 GL_MAX_VERTEX_ATTRIBS.
    GL_INVALID_VALUE错误: 如果 size 不是 1, 2, 3, 或 4.
    GL_INVALID_VALUE错误: 如果 stride 小于零.

    实例 编辑

    cocos2D-x中CCNode的画图函数
    void CCTexture2D::drawAtPoint(const CCPoint& point)
      {
      GLfloat coordinates[] = { 
      0.0f, m_fMaxT,
      m_fMaxS,m_fMaxT,
      0.0f, 0.0f,
      m_fMaxS,0.0f };
    GLfloat width = (GLfloat)m_uPixelsWide * m_fMaxS,
      height = (GLfloat)m_uPixelsHigh * m_fMaxT;
    GLfloat vertices[] = { 
      point.x, point.y,
      width + point.x, point.y,
      point.x, height + point.y,
      width + point.x, height + point.y };
    ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position | kCCVertexAttribFlag_TexCoords );
      m_pShaderProgram->use();
      m_pShaderProgram->setUniformsForBuiltins();
    ccGLBindTexture2D( m_uName );
    
      glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, vertices);
      glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, 0, coordinates);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
      }
  • 相关阅读:
    pkg_resources.DistributionNotFound: The 'catkin-pkg==0.4.9' distribution was not found
    gsl库安装
    json ubuntu下安装
    系统安装情况以及深度学习环境搭建
    ros 编程习惯
    ubuntu系统ftp连接 以及ssh连接
    redmine问题
    maven仓库私服配置
    SVN配置管理(trunk、branches、tags)
    Gitolite配置管理和GIT基本操作
  • 原文地址:https://www.cnblogs.com/Anita9002/p/4940052.html
Copyright © 2020-2023  润新知