您的位置:首页 > 其它

顶点数组以及解引用单个数组

2015-08-27 13:11 225 查看
法线向量

物体的法线向量定义了他的表面在空间中的方向。具体地说定义了他相对于光源的方向。OpenGL使用法线向量确定了这个物体各个顶点所接受的光照。在定义物体的几何形状时,同时也定义了他的法线向量。可以使用glNormal*()函数,把当前法线向量设置为这个函数所标示的值,以后调用glVertex*()时,就会把当前法线向量分配给所指定的顶点。每个顶点尝尝具有不同的法线,所以需要交替调用这个函数。

glBegin(GL_POLYGON);
glNormal3fv(n0);
glVertex3fv(v0);
glNormal3fv(n1);
glVertex3fv(v1);
glNormal3fv(n2);
glVertex3fv(v2);
glNormal3fv(n3);
glVertex3fv(v3);
glEnd();


由于法线向量只表示方向,因此长度无关紧要。法线可以指定为任意长度,但是在执行光照计算之前,需要向量单位化。如果模型只涉及旋转和移动,法线向量就可以保证规范化。如果进行了不规则的变换,在变换之后OpenGL会自动对法线向量进行规范化。为了启用这个功能调用
glEnable(GL_NORMALIZE);
如果提供了单位长度的法线,并且只进行均匀缩放,就可以使用
glEnable(GL_RESCALE_NORMAL)
,用一个常量因子对法线缩放,恢复单位长度。

顶点数组

OpenGL需要大量的函数调用才能完成对几何图元的渲染,以及共享顶点的冗余处理问题。使用顶点数组,允许只用少数几个数组指定大量与顶点相关的数据,并用少量函数调用访问这些数据,把数据放在顶点数组可以提高应用程序的性能。

使用顶点数组对几何图元进行渲染需要三个步骤:

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

2. 把数据放入数组中。这些数组是通过它们的内存地址(指针)进行访问的。在客户机服务器模型中,这些数组存储在客户机的地址空间中,除非使用缓冲区对象,这时候数据存储在服务器内存中。

3. 用这些数据绘制几何图形。OpenGL通过指针从所有的被激活数组中获取数据。在客户机-服务器模型中,数据被传输到服务器地址空间中。有三种方式完成这个任务:

1. 访问单独数组元素

2. 创建一个单独数组元素的列表

3. 线性的处理数组元素

启用数组:

调用
glEnableClientState()
函数,激活选择的数组,在实践中同时可激活数组只有6个,有些数组不能同时激活,例如显示模式可以支持RGBA或颜色索引,但是不能同时支持这两种。

Void glEnableClientState(GLenum array
)array参数是一个符号常量。

例如需要使用光照,可能需要为每个顶点定义一条法线向量,这种情况下使用顶点数组时候,需要同时激活表面法线数组以及顶点坐标数组

glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);


如果在某个时刻需要关闭光照,需要调用glDisable()函数来关闭光照状态,在关闭光照状态之后,还需要停止更改表面法线状态的值,因为这种做法完全浪费

调用
gldisableClientState(GL_NORMAL_ARRAY);


指定数组数据:

用一条命令指定客户空间中的一个数组。共有8个函数可以用来指定数组,每个函数用于指定一个不同类型的数组。以glVertexpointer为例

void glVertexPointer(GLint size,GLenum type,GLsize stride,const Glvoid* pointer);


指定了需要访问的空间坐标数据。Size是每个顶点的坐标数量,必须是2,3,4.stride是连续顶点之间的字节偏移量,如果为0,数组中顶点便是紧密相连。type指定了数组中每个坐标的数据类型。Pointer是数组包含的第一个顶点的第一个坐标的内存地址。

使用顶点数组表示RGBA颜色和顶点坐标。RGB浮点值以及与它们对应的整型坐标值被加载到
GL_COLOR_ARRAY
GL_VERTEX_ARRAY
数组中。

static GLint vertices[]={
        25,25,
        100,325,
        175,25,
        175,325,
        250,25,
        325,325
    };

    static GLfloat colors[] ={1.0,0.2,0.2,
                              0.2,0.2,1.0,
                              0.8,1.0,0.2,
                              0.75,0.75,0.75,
                              0.35,0.35,0.35,
                              0.5,0.5,0.5
    };
    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_VERTEX_ARRAY);

    glColorPointer(3,GL_FLOAT,0,colors);
    glVertexPointer(2,GL_INT,0,vertices);


跨距

Gl*Pointer()函数的stride参数告诉OpenGL如何访问指针数组中的数据。他的值应该是两个连续的指针元素之间的字节数量。如果顶点的RGB值和顶点坐标存储在同一个数组中,如下所示

static GLfloat intertwined[]=
    {
        1.0,0.2,1.0,100.0,100.0,0.0,
        1.0,0.2,0.2,0.0,200.0,0.0,
        1.0,1.0,0.2,100.0,300.0,0.0,
        0.2,1.0,0.2,200.0,300.0,0.0,
        0.2,1.0,1.0,300.0,200.0,0.0,
        0.2,0.2,1.0,200.0,100.0,0.0
    };


如果只想引用数组中的颜色值或者顶点坐标则需要跳跃读取

glColorPointer(3,GL_FLOAT,6*sizeof(GLfloat),&intertwined[0]);
glVertexPointer(3,GL_FLOAT,6*sizeof(GLfloat),&intertwined[3]);


如果stride为0,数组中数据是一致的只包含颜色值,或者顶点坐标等。

3解引用和渲染

在顶点数组内容被解引用之前,数组一直保存在客户端,他们的内容很容易进行修改。在这一步骤中,数组中数据被提取,接着发送到服务器,然后发送到图形处理管线进行渲染。可以从单个数组元素提取数据,也可以从一个有序的数组元素列表中提取。

解引用单个数组

Void glArrayElement(Glint ith);


获取当前所有已启用数组的的第ith个顶点的数据

对于顶点坐标数组,对应的函数是
glVertex[size][type]v()
,其中size和type由
glvertexPointer()
函数定义的。其它启用的数组类似。

glArrayElement
通常在
glBegin()
glEnd()
之间调用,下面程序使用取自启用的顶点数组的第3,4,6个顶点绘制一个三角形。

void Init()
{
    glClearColor(0.0,0.0,0.0,0.0);
    glShadeModel(GL_FLAT);
}
void myDisplay()
{
    static GLint vertices[]={
        25,25,
        100,325,
        175,25,
        175,325,
        250,25,
        325,325
    };

    static GLfloat colors[] ={1.0,0.2,0.2,
                              0.2,0.2,1.0,
                              1.0,1.0,1.0,
                              1.0,1.0,1.0,
                              0.35,0.35,0.35,
                              1.0,1.0,1.0
    };

    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();
    glFlush();

    glColor3fv(colors +(2*3));
    glVertex2iv(vertices +(2*2));

}

void reshape(int w,int h)
{
    glViewport(0,0,(GLsizei) w,(GLsizei) h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0,(GLdouble) w,0.0,(GLdouble) h);

}

int _tmain(int argc, _TCHAR* argv[])
{

    glutInit(&argc,(char**)argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(400,400);
    glutCreateWindow("绘制三角形");
    Init();
    glutDisplayFunc(&myDisplay);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return 0;
}

运行结果生成一个白色的三角形
glColor3fv(colors +(2*3));
glVertex2iv(vertices +(2*2));
glColor3fv(colors +(3*3));
glVertex2iv(vertices +(3*2));
glColor3fv(colors +(5*3));
glVertex2iv(vertices+(5*2));


等价于解引用函数的那三行代码,由于glArrayElement()对于每个顶点只调用一次,因此他可能会减少函数的调用数量,从而提高程序总体性能。在绘图期间不要修改数组元素内容。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: