opengl 知识点3


点的法向量

没有顶点法向量信息,所以要自己计算;由立体几何知识可知,一个点的法向量应该等于以这个点为顶点的所有三角形的法向量之和,所以只要计算出每个三角形的法向量,再把这个法向量加到此三角形三个顶点的法向量里即可。

计算顶点法向量的过程记录:


        首先,我们要了解几个概念,平面法向量(平面上两个不平行。不共线的向量叉乘得到),顶点法向量(以这个点为顶点的全部三角形的法向量之和)。

    接着,我们就能够通过三个顶点求得两个向量,两个向量叉乘得到平面法向量。(平面法向量进行归一化)

        然后,统计每一个顶点的全部平面法向量之和。(顶点法向量进行归一化)


http://book.51cto.com/art/201206/341257.htm
//------------------------------------------------------------


OpenGL几种绘制方式

本文介绍了OpenGL的几种绘制方式及各自特点。绘制方式如下:

立即模式
显示列表
顶点数组
VBO

1、立即模式
最直接的方式,传统的使用glBegin...glEnd绘制的方式,如下所示:
glBegin( GL_TRIANGLES );
glVertex3f(-1.0f, -0.5f, -4.0f); 
glVertex3f( 1.0f, -0.5f, -4.0f); 
glVertex3f( 0.0f, 0.5f, -4.0f);
glEnd();
这种方式效率较低。原因是

glVertex函数每次调用只把一个顶点从客户端(CPU或内存)传输到服务端(GPU),而这个传输的过程相对于GPU处理数据的过程是很慢的。

glVertex函数的调用次数过多

2、显示列表
将图形绘制进行预编译,把绘制好的图形放到GPU,使用的时候直接调用。
初始化函数

displayList = glGenLists( 1 );  //请求显示列表名称
glNewList( displayList, GL_COMPILE );   //创建显示列表
glBegin( GL_TRIANGLES );
glVertex3f(-1.0f, -0.5f, -4.0f); 
glVertex3f( 1.0f, -0.5f, -4.0f); 
glVertex3f( 0.0f, 0.5f, -4.0f);
glEnd();

glEndList();
渲染函数

glCallList( displayList );
显示列表的优化策略是将图形绘制命令集(数据块)存储在GPU中,无须CPU到GPU间的数据传递,节省了时间。
然而显示列表虽然提升了绘制速度,但是它一旦创建了就是不可修改的,如果要修改,只能销毁并重新创建显示列表,所以它适用于那些静态的图形。


3、顶点数组
将数据保存在数组中,当执行绘制(glDrawArrays或glDrawElements)的时候一次性将数据从CPU传递到GPU中。

//初始化顶点数组
GLfloat vertices[ 3 ][3] = {0};
vertices[0][0] = -1.0f;
vertices[0][1] = -0.5f;
vertices[0][2] = -4.0f;
vertices[1][0] = 1.0f;
vertices[1][1] = -0.5f;
vertices[1][2] = -4.0f;
vertices[2][0] = 0.0f;
vertices[2][1] = 0.5f;
vertices[2][2] = -4.0f;
glEnableClientState( GL_VERTEX_ARRAY );         //启用顶点数组
glVertexPointer( 3, GL_FLOAT, 0, vertices );    //指定数据
glDrawArrays( GL_TRIANGLES, 0, 3);              //进行绘图
glDisableClientState( GL_VERTEX_ARRAY );    
顶点数据的优化策略是减少数据从CPU到GPU的传递次数,从而节省了时间。但是它仍然有数据的传递,所以绘制效率不如显示列表高。相比于显示列表它的优点是数据可以动态修改。


4、VBO
VBO将顶点数据存储在GPU缓存中,无须CPU到GPU的数据传递,并且可以动态修改。
初始化函数
//初始化顶点数组
GLfloat vertices[ 3 ][3] = {0};
vertices[0][0] = -1.0f;
vertices[0][1] = -0.5f;
vertices[0][2] = -4.0f;
vertices[1][0] = 1.0f;
vertices[1][1] = -0.5f;
vertices[1][2] = -4.0f;
vertices[2][0] = 0.0f;
vertices[2][1] = 0.5f;
vertices[2][2] = -4.0f;
glewInit();
glGenBuffers( 1, buffer );  //创建缓冲区

//指定缓冲区数据
glBindBuffer( GL_ARRAY_BUFFER, buffer );
glBufferData( GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 3, vertices, GL_DYNAMIC_DRAW );
渲染函数


glBindBuffer( GL_ARRAY_BUFFER, buffer );    //绑定缓冲区
glEnableClientState( GL_VERTEX_ARRAY ); //使用VBO必须开启顶点数组
glVertexPointer( 3, GL_FLOAT, 0, 0 );       
glDrawArrays( GL_TRIANGLES, 0, 3 ); //绘制
glDisableClientState( GL_VERTEX_ARRAY );
glBindBuffer( GL_ARRAY_BUFFER, 0 );     //取消绑定缓冲区
关于VBO的动态修改,可以将数据映射到客户端(内存)中,然后再进行修改。以下是一种刷新所有顶点数据的方法。


//初始化新数组
GLfloat newvertices[3][3] = {0};
newvertices[0][0] = 0.0f;
newvertices[0][1] = 0.0f;
newvertices[0][2] = 50.0f;
...


//映射缓冲区
glBindBuffer( GL_ARRAY_BUFFER, buffer] );
glBufferData( GL_ARRAY_BUFFER, sizeof( GLfloat ) * 3* 3, NULL, GL_STREAM_DRAW );
GLvoid* PositionBuffer = glMapBuffer( GL_ARRAY_BUFFER, GL_WRITE_ONLY ); 


//刷新数据
memcpy( PositionBuffer, newvertices, sizeof( GLfloat ) * 1002 * 3 );


//刷新到VBO
glBindBuffer( GL_ARRAY_BUFFER, buffer );
glUnmapBuffer( GL_ARRAY_BUFFER );
glVertexPointer( 3, GL_FLOAT, 0, 0 );

VBO结合了显示列表与顶点数组的优点,既在GPU保存数据避免数据传输,提高了绘制效率,又可以动态修改。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值