注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

一江春水向西流

程序人生

 
 
 

日志

 
 
关于我

夫君子之行,静以修身,俭以养德.非澹泊无以明志, 非宁静无以致远.夫学须静也,才须学也,非学无以广才,非志无以成学,淫漫则不能励精,险躁则不能治性,年与时驰,意与日去,遂成枯落,多不接世,悲守穷庐,将复何及!

网易考拉推荐

基于VC++的OpenGL编程讲座之基本图元-3  

2009-05-09 15:42:48|  分类: C/C++ |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
  四、法向量的计算及指定

  法向量是几何图元的重要属性之一。几何对象的法向量是垂直与曲面切面的单位向量,它定义了几何对象的空间方向,特别定义了它相对于光源的方向,决定了在该点上可接受多少光照。

  OpenGL本身没有提供计算法向量的函数(计算法向量的任务由程序员自己去完成),但它提供了赋予当前顶点法向的函数。

  (一)平面法向的计算方法。

  在一个平面内,有两条相交的线段,假设其中一条为矢量W,另一条为矢量V,平面法向为N,则平面法向就等于两个矢量的叉积(遵循右手定则),即N=WxV。例如:一个三角形平面三个顶点分别为P0、P1、P2,相应两个向量为W、V,则三角平面法向的计算方式如下列代码所示:

void getNormal(GLfloat gx[3],GLfloat gy[3],
GLfloat gz[3],GLfloat *ddnv)
{
 GLfloat w0,w1,w2,v0,v1,v2,nr,nx,ny,nz;
 w0=gx[0]-gx[1]; w1=gy[0]-gy[1];w2=gz[0]-gz[1];
 v0=gx[2]-gx[1]; v1=gy[2]-gy[1];v2=gz[2]-gz[1];
 nx=(w1*v2-w2*v1);ny=(w2*v0-w0*v2);nz=(w0*v1-w1*v0);
 nr=sqrt(nx*nx+ny*ny+nz*nz); //向量单位化。
 ddnv[0]=nx/nr; ddnv[1]=ny/nr;ddnv[2]=nz/nr;
}

  以上函数的输出参数为指针ddnv,它指向法向的三个分量,并且程序中已经将法向单位化(或归一化)了。

  (二)曲面法向量的计算。

  对于曲面各顶点的法向计算有很多种,如根据函数表达式求偏导的方法等。但是,在大多数情况,OpenGL中的多边形并不是由曲面方程建立起来的,而是由模型数组构成,这时候求取法向量的办法是将曲面细分成多个小多边形,然后选取小多边形上相邻的三个点v1、v2、v3(当然三个点不能在同一直线上),按照平面法向量的求取方法就可以了。

  (三)法向量的定义。

  OpenGL法向量定义函数为:

void glNormal3{bsifd}(TYPE nx,TYPE ny,TYPE nz);
void glNormal3{bsifd}v(const TYPE *v);

  非向量形式定义法向采用第一种方式,即在函数中分别给出法向三个分量值nx、ny和nz;向量形式定义采用第二种,即将v设置为一个指向拥有三个元素的指针,例如v[3]={nx,ny,nz}。

  五、显示列表

  (一)定义显示列表。

  前面所举出的例子都是瞬时给出函数命令,OpenGL瞬时执行相应的命令,这种绘图方式叫做立即或瞬时方式(immediate mode)。OpenGL显示列表(Display List)是由一组预先存储起来的留待以后调用的OpenGL函数语句组成的,当调用显示列表时就依次执行表中所列出的函数语句。显示列表可以用在以下场合:

  1)矩阵操作

  大部分矩阵操作需要OpenGL计算逆矩阵,矩阵及其逆矩阵都可以保存在显示列表中。

  2)光栅位图和图像

  程序定义的光栅数据不一定是适合硬件处理的理想格式。当编译组织一个显示列表时,OpenGL可能把数据转换成硬件能够接受的数据,这可以有效地提高画位图的速度。

  3)光、材质和光照模型

  当用一个比较复杂的光照环境绘制场景时,因为材质计算可能比较慢。若把材质定义放在显示列表中,则每次改换材质时就不必重新计算了,因此能更快地绘制光照场景。

  4)纹理

  因为硬件的纹理格式可能与OpenGL格式不一致,若把纹理定义放在显示列表中,则在编译显示列表时就能对格式进行转换,而不是在执行中进行,这样就能大大提高效率。

  5)多边形的图案填充模式,即可将定义的图案放在显示列表中。

  OpenGL提供类似于绘制图元的结构即类似于glBegin()与glEnd()的形式创建显示列表,其相应的函数为:

void glNewList(GLuint list,GLenum mode);
void glEndList(void);

  glNewList()函数说明一个显示列表的开始,其后的OpenGL函数存入显示列表中,直至调用结束表的函数glEndList(void)。glNewList()函数中的参数list是一个正整数,它标志唯一的显示列表;参数mode的可能值有GL_COMPILE和GL_COMPILE_AND_EXECUTE;若要使列表中函数语句只存入而不执行,则用GL_COMPILE;若要使列表中的函数语句存入表中且按瞬时方式执行一次,则用GL_COMPILE_AND_EXECUTE。

  注意:并不是所有的OpenGL函数都可以在显示列表中存储且通过显示列表执行。一般来说,用于传递参数或返回数值的函数语句不能存入显示列表,因为这张表有可能在参数的作用域之外被调用;如果在定义显示列表时调用了这样的函数,则它们将按瞬时方式执行并且不保存在显示列表中,有时在调用执行显示列表函数时会产生错误。以下列出的是不能存入显示列表的OpenGL函数:

  glDeleteLists()    glIsEnable()
  glFeedbackBuffer()   glIsList()
  glFinish()       glPixelStore()
  glGenLists()      glRenderMode()
  glGet*()        glSelectBuffer()

  在建立显示列表以后就可以调用执行显示列表的函数来执行它,并且允许在程序中多次执行同一显示列表,同时也可以与其它函数的瞬时方式混合使用。显示列表执行的函数形式如下:

  void glCallList(GLuint list);

  参数list指定被执行的显示列表。显示列表中的函数语句按它们被存放的顺序依次执行;若list没有定义,则不会产生任何事情。

  (二)管理显示列表

  在实际应用中,一般调用函数glGenList()来创建多个显示列表,这样可以避免意外删除,产生一个没有用过的显示列表。此外,在管理显示列表的过程中,还可调用函数glDeleteLists()来删除一个或一个范围内的显示列表。

  1)GLuint glGenList(GLsizei range)

  该函数分配range个相邻的未被占用的显示列表索引。这个函数返回的是一个正整数索引值,它是一组连续空索引的第一个值。返回的索引都标志为空且已被占用,以后再调用这个函数时不再返回这些索引。若申请索引的指定数目不能满足或range为0则函数返回0。

  2)GLboolean glIsList(GLuint list)

  该函数询问显示列表是否已被占用的情况,若索引list已被占用,则函数返回TURE;反之,返回FAULSE。

  3)void glDeleteLists(GLuint list,GLsizei range)

  该函数删除一组连续的显示列表,即从参数list所指示的显示列表开始,删除range个显示列表,并且删除后的这些索引重新有效。

  (三)多级显示列表

  多级显示列表的建立就是在一个显示列表中调用另一个显示列表,也就是说,在函数glNewList()与glEndList()之间调用glCallList()。多级显示列表对于构造由多个元件组成的物体十分有用,尤其是某些元件需要重复使用的情况。但为了避免无穷递归,显示列表的嵌套深度最大为64(也许更高些,这依赖于不同的OpenGL实现),当然也可调用函数glGetIntegerv()来获得这个最大嵌套深度值。OpenGL也允许用一个显示列表包含几个低级的显示列表来模拟建立一个可编辑的显示列表。

  下面的一段代码使用了列表嵌套来显示一个三角形:

  glNewList(1,GL_COMPILE);
  glVertex3fv(v1);
  glEndList();
  glNewList(2,GL_COMPILE);
  glVertex3fv(v2);
  glEndList();

  glNewList(3,GL_COMPILE);
  glVertex3fv(v3);
  glEndList();

  glNewList(4,GL_COMPILE);
  glBegin(GL_POLYGON);
  glCallList(1);
  glCallList(2);
  glCallList(3);
  glEnd();
  glEndList();
  评论这张
 
阅读(205)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017