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

法线向量

物体的法线向量定义了他的表面在空间中的方向。具体地说定义了他相对于光源的方向。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_ARRAYGL_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()对于每个顶点只调用一次,因此他可能会减少函数的调用数量,从而提高程序总体性能。在绘图期间不要修改数组元素内容。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-04 22:54:46

顶点数组以及解引用单个数组的相关文章

5数组指针和引用:数组

数组 一维数组:数据类型  数组名 [常量表达式] 注意: 命名规则和变量名相同 数组后面一定是[],方括号内 是常量表达式 常量表达式表达元素的个数,即数组的长度 定义数组的常量表达式不能是变量 引用: 一维数组引用的一般形式:数组名[下标] 数组元素的下标起始值为0 初始化: 单个元素逐一赋值   a[10]=1;a[9]=100;...... 聚合方式赋值    int a[10]={1,2,.....10} ; int a[]={1,2,.....10}  ; int a[10]={1,

javascript数组详解(js数组深度解析)

Array 对象是一个复合类型,用于在单个的变量中存储多个值,每个值类型可以不同. 创建数组对象的方法: new Array(); new Array(size); new Array(element0, element1, ..., elementn); 1. 当索引值为负数时,会将其看作是对象的一个属性,若为非负的数字字符串,则会隐式转换为数字索引: var a= new Array(); a[-1.23]=true; a[1]="pomelo"; a["100"

shell 数组详解

数组 数组的介绍 平时的定义a=1,b=2,c=3:变量如果多了,再一个一个定义很费劲,并且取变量也很费劲. 简单说,数组就是相同数据类型的元素按一定顺序排序的集合 数组就是把有限的类型相同的变量用一个名字命名,然后用不同的编号区分他们的变量的集合,这个名字就是数组名,编号成为数组的下标,组成数组的各个变量成为数组的分量,也称为数组的元素. 由于有了数组,就可以用相同的名称引用一系列的变量,并用数组(索引)来识别他们,在许多场合,使用数组可以缩短和简化程序的开发,因为可以利用索引值设计一个循环,

ES6 之 数组的解构赋值

数组的解构赋值 基本用法 ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). 以前,为变量赋值,只能直接指定值. let a = 1;let b = 2;let c = 3; ES6允许写成下面这样. let [a, b, c] = [1, 2, 3]; 上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值. 本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值.下面是一些使用嵌套数组进行解构的例子

数组的解构赋值

基本用法 ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). 以前,为变量赋值,只能直接指定值. let a = 1; let b = 2; let c = 3; ES6 允许写成下面这样. let [a, b, c] = [1, 2, 3]; 上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值. 本质上,这种写法属于"模式匹配",只要等号两边的模式相同,左边的变量就会被赋予对应的值.下面是一些使用嵌套数组进行解构的例子

(转)awk数组详解及企业实战案例

awk数组详解及企业实战案例 原文:http://www.cnblogs.com/hackerer/p/5365967.html#_label03.打印数组:1. [[email protected] test]# awk 'BEGIN{array[1]="zhurui";array[2]="zhuzhu";for(key in array) print key,array[key]}'2. 1 zhurui3. 2 zhuzhu4. [[email protect

高级数据结构:优先队列、图、前缀树、分段树以及树状数组详解

优秀的算法往往取决于你采用哪种数据结构,除了常规数据结构,日常更多也会遇到高级的数据结构,实现要比那些常用的数据结构要复杂得多,这些高级的数据结构能够让你在处理一些复杂问题的过程中多拥有一把利器.同时,掌握好它们的性质以及所适用的场合,在分析问题的时候回归本质,很多题目都能迎刃而解了. 这篇文章将重点介绍几种高级的数据结构,它们是:优先队列.图.前缀树.分段树以及树状数组. 一.优先队列 1.优先队列的作用 优先队列最大的作用是能保证每次取出的元素都是队列中优先级别最高的,这个优先级别可以是自定

Javascript学习之数组详解

本文和大家分享的主要是javascript中数组相关内容,一起来看看吧,希望对大家学习javascript有所帮助. 设计数组的函数方法 toString, toLocaleString, valueOf, concat, splice, slice indexOf,lastIndexOf, push, pop, shift, unshift, sort, reverse map, reduce, reduceRight, filter, every, some, forEach 创建数组 ·

【Java学习笔记之五】java数组详解

数组 概念 同一种类型数据的集合.其实数组就是一个容器. 数组的好处 可以自动给数组中的元素从0开始编号,方便操作这些元素. 格式1: 元素类型[] 数组名 = new 元素类型[元素个数或数组长度]; 示例:int[] arr = new int[5]; 格式2: 元素类型[] 数组名 = new 元素类型[]{元素,元素,……}; int[] arr = new int[]{3,5,1,7}; int[] arr = {3,5,1,7}; 如果需要存储大量的数据,例如如果需要读取100个数,