精编OpenGL点光源资料

上传人:shug****ng1 文档编号:52745497 上传时间:2022-02-09 格式:DOC 页数:34 大小:375KB
收藏 版权申诉 举报 下载
精编OpenGL点光源资料_第1页
第1页 / 共34页
精编OpenGL点光源资料_第2页
第2页 / 共34页
精编OpenGL点光源资料_第3页
第3页 / 共34页
资源描述:

《精编OpenGL点光源资料》由会员分享,可在线阅读,更多相关《精编OpenGL点光源资料(34页珍藏版)》请在装配图网上搜索。

1、OpenGL点光源在OpenGL场景描述中可以包含多个点光源,光源的各种属性设置使用函数:void glLightif (GLe num light, GLenum pn ame, TYPE param);void glLightifv (GLe num light, GLenum pn ame, TYPE *param);指定。其中,参数 light指定进行参数设置的光源,其取值可以是符号常量GL_LIGHT0 ,GL_LIGHT1,GL_LIGHT7 ;参数pname指定对光源设置何种属性, 其取值参见表10-1 ;参数param指定对于光源light的pname属性设置何值,非矢量版本中

2、,它是一个数值,矢量版本中,它是一个指针,指向一个保存了属性值的数组。表10-1参数pname的取值及其含义(0.0.l-0GL DIFFUSE1 a l .o,1 0)軸D血 0.0, 0.0. 1GL SPECtTARi i.o. ia moo.o.o, i o.也用爭憶圉光井GL_PO$mON(0.0. DO. to.o ovGL_SPOT_D(RECT(OXgGL SPOT EXPONENT卜ISO止金GL COX STANTATION1.4GD世袁减因子-AT FEN1TAT1ONg子GL QUADRATIC ATTENL ATION二JX配廣因于丿(1) 点光源的颜色OpenGL中

3、分别使用点光源的颜色由环境光、漫反射光和镜面光分量组合而成,在GL_AMBIENT、GL_DIFFUSE和GL_SPECULAR 指定。其中,漫反射光成分对物体的影响 最大。(2) 点光源的位置和类型点光源的位置使用属性 GL_POSITION指定,该属性的值是一个由 4个值组成的矢量(X, y,乙w)。其中,如果 w值为0,表示指定的是一个离场景无穷远的光源,( x, y, z) 指定了光源的方向,这种光源被称为方向光源,发出的是平行光;如果w值为1,表示指定的是一个离场景较近的光源,(x, y, z)指定了光源的位置,这种光源称为定位光源。(3) 聚光灯当点光源定义为定位光源时,默认情况下

4、,光源向所有的方向发光。但通过将发射光限定在圆锥体内,可以使定位光源变成聚光灯。属性GL_SPOT_CUTOFF用于定义聚光截止角,即光锥体轴线与母线之间的夹角,它的值只有锥体顶角值的1/2。聚光截止角的默认值为180.0,意味着沿所有方向发射光线。除默认值外,聚光截止角的取值范围为0.0,90.0。GL_SPOT_DIRECTION 属性指定聚光灯光锥轴线的方向,其默认值是(0.0,0.0,-1.0),即光线指向z轴负向。而GL_SPOT_EXPONENT属性可以指定聚光灯光锥体内的光线聚集 程度,其默认值为0。在光锥的轴线处,光强最大,从轴线向母线移动时,光强会不断衰减,衰减的系数是:轴线

5、与照射到顶点的光线之间夹角余弦值的聚光指数次方。(4) 光强度衰减属性 GL_CONSTANT_ATTENUATION 、 GL_LINEAR_ATTENUATION 、 GL_QUADRATIC_ATTENUATION 分别指定了衰减系数 c0,c1和c2,用于指定光强度的 衰减。在OpenGL中,必须明确启用或禁用光照。默认情况下,不启用光照,此时使用当前颜 色绘制图形,不进行法线矢量、光源、光照模型、材质属性的相关的计算。要启用光照,可 以使用函数:glE nable(GL_LIGHTING);指定了光源的参数后,需要使用函数:glE nable(light);启用light指定的光源。

6、当然也可以用light参数调用glDisable函数,禁用light指定的光源。 需要特别说明的是,点光源的位置和方向是定义在场景中的,与景物一起通过几何变换和观察变换变换到观察坐标系中,因此光源既可以与场景中对象的相对位置保持不变,也可以使光源随观察点一起移动。OpenGL全局光照在OpenGL中,还需要设定全局光照(相当于背景光)。OpenGL提供了下面的函数对全局光照的属性进行定义。void glLightModeif (GLenum pname ,TYPE param);void glLightModeifv (GLenum pname,TYPE *param);其中,参数pname指

7、定全局光照的属性,其取值参见表10-2;参数param指定进行设置的属性的值。表10-2参数pname的取值及含义pfge职伍氏认佰-A X-P J .01- 鳖卜竹 坏遭先咗,GL,LIGHT1ODELuLCCALGL FALSt如借计MttTti.lt*.OLLIGKT XiODEI. FftO $DEOLFALSE-单 IE 克弔还垦収Ubt窗OL.LIOKT MODFLmC0LOR,CO!TROl. GLf SPOLF,柑甌的就射充前色.GE COLORXS0 1, 1属性GL_AMBIENT 和GL_DIFFUSE的值定义了物体表面对环境光和漫射光中R,G,B颜色分量的反射系数。如果

8、使用属性 GL_AMBIENT_AND_DIFFUSE ,那么物体表面的环境光和漫射光将使用相同的反射系数。镜面反射可以在物体表面形成高光区域。OpenGL中通过改变属性GL_SPECULAR的值改变物体表面对镜面反射光的反射率,还可以通过属性GL_SHININESS的值改变高光区域的形状和大小。GL_SHININESS属性值的取值范围为0.0 , 128.0,值越大,高光区域越小、 光线集中程度越高。在很多的应用中,有时希望物体亮一些,特别是对于一些表示光源的物体,此时可以通过GL_EMISSION属性使物体表面看起来有点发光。在设定了材质属性之后,物体的最终颜色是由其材质属性的RGB值和光

9、照属性的 RGB值共同决定的。例如,如果当前环境光源的RGB值为(0.5,1.0,0.5),而物体材质的环境反射系数为(0.5,0.5, 0.5),那么物体表面的环境光颜色为:(0.5 05,1.0 砂5,0.5 5) = (0.25,0.5,0.25)即将每个环境光源的成分与材质的环境反射率相乘。这样,物体表面的颜色为多项RGB值的叠加:包括材质对环境光的反射率与环境光结合的RGB值,材质对漫反射光的反射率与漫反射光结合的 RGB值,材质对镜面光的反射率与镜面反射光结合的RGB值等。当叠加的RGB中任何一个颜色分量的值大于1.0,那么就用1.0计算。但是,在这种设定下,有时很难判断出物体在光

10、照环境中的颜色,为此OpenGL提供了另一种材质模式,即颜色材质模式,可以通过函数:void glColorMaterial (GLe num face, GLenum mode);设置。其中,参数 face 可以取 GL_FRONT,GL_BACK,GL_FRONT_AND_BACK ,指定 物体的哪个面的材质属性使用颜色材质模式;而参数mode允许的取值是 GL_AMBIENT、GL_DIFFUSE、GL_SPECULAR、GL_AMBIENT_AND_DIFFUSE 或 GL_EMISSION,指定 将更新哪种材质属性。在使用了颜色材质模式后,需要调用:glE nable(GL_COLO

11、R_MATERIAL);这样,可以通过 glColor函数来指定物体表面的颜色,而相应的材质属性将通过颜色值和光源的RGB值计算出来。光照效果是光线与表面共同作用的结果 在OpenGL中,光线被假定成红绿蓝三种原色光的组合,因此,光源的颜色就由 它所发出的这三种原色光的含量决定,而物理表面的颜色则由其反射的这三种光 的含量决定。Ope nGL勺光照模型尽管只是一个近似,但它很管用且计算速度很 快。如果你需要一个更精确的模型,那么只好自己编程计算了,不过模型越精确 则计算速度越慢。在场景中,OpenGL可以放置若干个光源,每个光源都可以被单独地打开或关闭。 照在物体上的光线有些是直接来自光源,

12、而另一些是光源的光经过若干次反射而 来。这些多次反射的光被称为环境光(Ambient Light),它们已经变得很“散”, 以致于无法确定其初始方向,不过当某个光源(产生它们的光源)被关闭后,它们 也就消失了。不同的物理表面对光线有不同的反射特性, 那些通常看起来很光泽的表面能够将 入射光很好地向某一特定方向反射,而另外一些则将入射光均衡地散射向各个方 向。大部分表面的特性是介于这两者之间的。 当然有些表面也会自己发光,比如 汽车前灯。 光照分量Ope nGL寸光照效果的计算是由四个独立的部分叠加而成的,它们是:出射光 自 发光(emitted)、环境光(ambie nt)、漫反射光(diff

13、use)、镜面光(specular)。出射光是最简单的,它从物体发出且不受任何其它光源的影响。环境光从光源发出并经过多次反射形成的, 它均匀从周围环境入射至物体表面并 朝各个方向等量反射。漫反射光是直接从特定光源入射并朝各个方向等量反射的光,入射角越小它看起 来越亮,同时从各个角度来看它的亮度是一样的。镜面光也是直接从特定光源入射的,但在反射时只朝特定的方向反射(遵从镜面反射定理)。一束平行激光在高质量的镜面上可以几乎被 100%地反射。表面光泽 的金属或塑料都有很高的镜面反射成份,而象粉笔或地毯之类的光泽度差的物品 则几乎没有。尽管同一光源出射的光的频率分布是一定的,但照在不同的表面上产生的

14、环境 光、漫反射光、镜面光分量却可能不同。比如白光照在房间的红色墙壁上,被散射的光就会趋于红色。OpenGL允许对各个反射光分量的RGB值分别作独立的 调整。 材质颜色Ope nGL中近似认为材质的颜色由它的反射光中的红绿蓝三色所占的百分比决 定。比如:一个理想的红色球将反射入射的所有红光并吸收所有绿色和蓝色光。 这样的球在白光 (含红绿蓝三色光 ) 和纯红光的照射下的表现是一致的都是 红色球,然而在不含红光成份的光 ( 如纯绿光 ) 的照射下则呈现为黑色 (因为没有 光被反射 ) 。与光线对应, 材质有独立的环境反射、 漫反射和镜面反射颜色成份, 分别决定了 材质对环境光、 漫反射光和镜面光

15、的反射能力。 环境反射和漫反射决定了物体的 颜色,这两种成份很相象, 甚至可以当作一种来处理。 镜面反射色通常为白色或 灰色,因此镜面反射的高光 (highlights) 通常是光源的镜面光成份的颜色和强度 决定。想象一束白光照射在一个有光泽的红色金属球上, 球体的大部分将表现为 红色,而高光处则为白色。 光线与材质的RGB值光线颜色的RGB定义于材质的RGB值定义有所不同。对光线来说,RGB值的大小对应于该色光强度与其最高强度的比例百分数。比如 一束光的RG睹E是1.0,那么它就是最强的白光;如果这些值都为 0.5,则整束 光的颜色还是白色,只不过强度减半,看起来是灰色。如果R=G=1.0而

16、B=0.0 ,那么就是最强的黄光。对材质来说,RGB的大小对应于材质对该色光的反射比例百分数。比如某材质 的R=1.0, G=0.5, B=0.0,则它反射入射的所有红光,一半的绿光,不反射蓝光。换句话来说,如果一束光的RGB值为(LR, LG, LB),被照材质的RGB值为(MR, MG, MB),则在不考虑其它反射效果的情况下,眼睛所看到的颜色由 (LR*MR, LG*MG, LB*MB)决 定。类似地,如果到达眼睛的两束光的 RGB成份分别为(R1, G1, B1)和(R2, B2, G2), 则OpenGL将相应的成份相加,得到(R1+R2, G1+G2,B1+B2)。如果任何一个相加

17、 结果大于 1( 表明这样的光强是显示设备不能实现的 ) ,则被认为是 1 。 6.2 简例:渲染一个球体向场景中加入光照的步骤如下:1. 定义所有物体每个顶点的法向量方向。这些法向量决定了物体表面与光源的 相对取向。2. 建立、选择并放置一个或多个光源。3. 建立并选择一个光照模型,它决定了全局环境光照的程度以及视点的有效位 置( 用于光照计算 ) 。4. 定义场景中物体的材质 例 6-1 将显示一个在独立光源照射下的球体,如前面的图 6-1 所示 例 6-1 : 光照下的球体 :#include #include #include aux.hvoid myinit(void)GLfloat

18、 mat_specular = 1.0, 1.0, 1.0, 1.0 ;GLfloat mat_shininess = 50.0 ;GLfloat light_position = 1.0, 1.0, 1.0, 0.0 ; glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glEnable(GL_LIGHTING);glEnable(GL

19、_LIGHT0); glDepthFunc(GL_LEQUAL);glEnable(GL_DEPTH_TEST);void display(void)glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); auxSolidSphere(1.0);glFlush();void myReshape(GLsizei w, GLsizei h)glViewport(0, 0, w, h);glMatrixMode(GL_PROJECTION); glLoadIdentity();if (w = h)glOrtho (-1.5, 1.5, -1.5*(GL

20、float)h/(GLfloat)w, 1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0);elseglOrtho (-1.5*(GLfloat)w/(GLfloat)h, 1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0); glMatrixMode(GL_MODELVIEW);glLoadIdentity();int main(int argc, char* argv)auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH); auxInitPosition (

21、0, 0, 500, 500);auxInitWindow (argv0);myinit();auxReshapeFunc (myReshape); auxMainLoop(display);与光照有关的调用写在函数myinit()中,下面我们将会简单地讨论它们的用法, 在后面的章节中还会仔细研究。在例 6-1中需要注意的一点是,它使用了 RGBA 颜色模式,而不是颜色索引模式(color-index) 。OpenGL对这两种模型的光照计 算是不同的,而且实际上颜色索引模式的光照表现力是很有限的,因此RGB/是比较受推崇的光照模式,本章中的所有例子都使用该模式。需要对颜色索引模式 作进一步了解

22、的请参阅“颜色索引模式中的光照” 一节。场景中物体的材质特性决定了光线是如何被反射的从而表现出它是用什么材料 做的。因为入射光线与物体材质表面的作用相当复杂,所以通过设置物体的材质特性而使它“看起来象那么会事”就是一件很技术的活了。你需要制定一种材质 的环境光反射色、漫射光反射色、镜面光反射色(这里说XX反射色的意思是指对 某种光的某个颜色分量的反射能力)以及它的光泽度。在这个例子中,只有最后 两个特性镜面光反射颜色和光泽度被明确地指定(通过使用glMaterialfv()函数)。在“定义材质特性” 一节中会描述所有的材质特性参数并给出例子。重点注意:在写你自己的光照程序时,记住可以修改一些参

23、数值,而另一些参数使用其缺省 值。当然,不要忘记使你定义的光源生效(enable之),同时允许光照计算。最 后,记住你可以使用显示列表以提高在改变光源位置时的计算效率(参阅“显示列表设计” 一节)。 6.3创建光源光源有如下属性:颜色、位置和方向。下面将讨论如何控制这些属性一达到期望 的效果。我们用来设置光源的所有属性的函数是 glLight*(),它有三个参数, 分别用来代表光源标识、需设置的属性及期望的属性值。函数形式为:void glLightifv(GLe num light, GLenum pn ame, TYPE param);light 是光源的标识,例如:GL_LIGHT0,G

24、L_LIGHT1.GL_LIGHT7 般地,GL_LIGHTi代表第i号光源。pname代表需设置的属性,其枚举值和对应的属性 意义见表6-1 oparam代表需要给pname代表的属性设置的值。注意,TYPE是 param 的类型,它由glLight函数名后面跟的字母决定,i就是int ,f就是float ,v(就 是vectro)可选,选了说明param代表指向一组参数的指针,不选则说明是单一 参数。表 6-1 glLight*()的pname参数及其缺省值(本表系从yxy (田丝丝#冬眠的小肥鹰)的教程中拷贝而来,改了一点点,呵呵)pname| |缺省值|说明|gl ambient0,0

25、,0,1|RGBAg式的环境光|gl diffuse1,1,1,1RGBAg式的漫反射光|gl specular1,1,1,1RGBAg式的镜面光|gl postion1,0,1,0|光源位置齐次坐标(x,y,z,w)|gl_spot_direction10,0,-1|聚光灯聚光方向矢量|GL_SPOT_EXPONENT1I0|聚光灯聚光指数|gl spot cutoff180聚光灯聚光发散半角Gl_CONSTANT_ATTENUATIC1|常数衰减因子|gl liner attenuation0线性衰减因子Gl_QUADRATIC_ATTENUATI:N平方衰减因子表6-1中相对GL_DIF

26、FUSE口 GL_SPECULA的缺省值只对 GL_LIGHT(有效,对于 其它的光源,它们的缺省值都是(0.0, 0.0, 0.0, 1.0)。下面是使用glLight*() 的一个例子:GLfloat light_ambie nt = 0.0, 0.0, 0.0, 1.0 ;GLfloat light_diffuse = 1.0, 1.0, 1.0, 1.0 ;GLfloat light_specular = 1.0, 1.0, 1.0, 1.0 ;GLfloat light_positi on = 1.0, 1.0, 1.0, 0.0 ;glLightfv(GL_LIGHT0, GL_A

27、MBIENT, light_ambie nt);glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);glLightfv(GL_LIGHT0, GL_POSITION, light_positi on);数组被用来给参数赋值,通过反复调用 glLightfv()给不同的参数赋值。在这个例子里,前三条语句是多余的,因为它们设置的分别是那三个参数的缺省值。记住要用glEnable打开每个光源。要了解更多的相关操作,请参阅“使光源生 效” 一节。在下面的部分中

28、将解释glLight*()的所有参数和它们可能的取值。这些参数和 定义全局光照模型以及物体材质特性的参数息息相关。请参阅“选择光照模型”和“定义材质特性”以获取更多的知识。在“光照的数学”中,将从数学的角度 解释这些参数是如何相互作用的。 颜色OpenGL允许对光源的三个不同的与颜色相关的参数:GL_AMBIENT, GL_DIFFUSE和GL_SPECULA进行调整。GL_AMBIEN参数代表场景中某光源的环境光的 RGBA各个分量强度。象表6-1中 列的那样,缺省情况下是没有环境光的,因为GL_AMBIEN是(0.0, 0.0, 0.0,1.0) 。例 6-1 中使用的正是这样的值。如果程

29、序将环境光设为蓝光,应该这样GLfloat light_ambient = 0.0, 0.0, 1.0, 1.0;glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);那么产生的结果如附录J中图J-14所示。GL_DIFFUS可能是与“光的颜色”联系最大的参数了,它定义了特定光源提供 的漫反射光的RGBA色值。缺省情况下,光源 GL_LIGHT0的 GL_DIFFUS值是 (1.0,1.0, 1.0, 1.0),即产生明亮的白光,如附录J中图J-14。而其它光源(GL_LIGHT1 到 GL_LIGHT7的缺省值都是(0.0, 0.0, 0.0, 0.

30、0)。GL_SPECULAR数影响物体上的高光点颜色。现实世界中的典型例子如玻璃瓶子 上的高光点显示的就是照在上面的光的颜色。因此,如果你想获得逼真的效果, 应该将GL_SPECULAR值设得和GL_DIFFUS一样(为什么?我想是获得逼真的金 属光泽效果吧。)所有的光源的GL_SPECULAR数缺省值和GL_DIFFUS缺省值 也是一样的。位置与衰减光源的位置有两种。 一种是离场景无限远, 另一种是在附近。 前者被称为方向光 源,它射到物体上的光可以认为是平行的。现实生活中,太阳就是这样的光源。 后者被称为位置光源, 因为它的确切位置决定了它对场景的作用效果, 尤其是决 定了光线的投射方向。

31、台灯就是位置光源。从附录 J 图 J-16 中你可以看到这两 种光源的不同作用效果。在例 6-1 中使用的是方向光源:GLfloat light_position = 1.0, 1.0, 1.0, 0.0 ;glLightfv(GL_LIGHT0, GL_POSITION, light_position);如上所示,你给GL_POSITIO参数提供了一个四个值的向量(x, y,乙w)。如果 最后一个值w是0,则相应的光源为方向光源,且(x, y, z)决定其方向。这个方向将被透视模型(modelview,这个词俺不知该怎么翻,根据后面的描述,模型变换是指旋转变换,透视变换是只位移变换 ) 矩阵

32、转化到视点坐标系中,就好象 它是一个被标准化的向量一样。GL_POSITIO的缺省值为(0, 0, 1,0) ,指向Z轴的负方向。 (注:你当然可以定义诸如 (0,0,0) 的方向, 但这对处理光照是没有 意义的 )如果w是非零值,光源就是位置型的。而(x,y,z)代表光源位置的齐次坐标(参见 附录G)。该位置将被透视模型矩阵转换到视点坐标系中(参见“控制光源的位置 和方向”一节以了解更多的有关位置转换的知识 )。在缺省意义下,光源的光是 向各个方向发出的, 不过你也可以定义一个聚光灯使其发射锥光, 这将在下一节 “聚光灯”中解释。请注意,具有光滑阴影效果的多边形表面各部分的颜色是由其各顶点的

33、颜色计算 决定的。正因为如此, 你需要避免在局部光源附近使用大多边形如果光源位 置在多边形的中部, 各顶点会因为距离光源太远而接收不到足够的光照, 从而整 个多边形看起来要比你相象的要暗。 要解决这个问题, 就得把大多边形分解成许 多小块。在现实世界中, 光线的强度会随着传播距离的增加而减弱。 方向光源是从无限远 处射来的,对它谈距离衰减意义不大, 所以衰减计算对方向光源是无效的。 然而, 对位置光源则必须考虑这个问题。Ope nGL!过给光源的光乘上一个因子来达到 衰减的目的。衰减因子 =其中,d为光源到顶点的距离kc为 GL_CONSTANT_ATTENUATIONkl 为 GL_LINE

34、AR_ATTENUATIONkq为 GL_QUADRATIC_ATTENUATION缺省情况下,kc为1.0 , kl和kq都为0,当然也可以设置其它值,比如glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 2.0);glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 1.0);glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.5);注意,环境光、 漫反射光和镜面光都会被衰减, 只有出射光和全局环境光不被衰 减。聚光灯前面曾提到, 你可以将一个位置光源定义成一个聚光灯, 也就

35、是说可以将光的发 射形状调整为圆锥形。创建聚光灯,你需要定义需要的锥光的跨度。( 记住,因为聚光灯是位置光源, 你还是需要为它定义一个位置。 你当然也可以方向光源定 义为聚光灯,从语法上没有错, 但是无意义 ) 。定义锥光的散射角 (即圆锥中轴和 边的夹角),需要使用GL_SPOT_CUTO参数,圆锥的顶角是该值的两倍,见图 6-2。图6-2 GL_SPOT_CUTO参数示意注意光线不能超越圆锥的边界。缺省时没有聚光灯效果,因为 GL_SPOT_CUTOFF 参数被默认为 180 度,也就意味着光线是超各个方向发射的 ( 此时圆锥的顶角为 360,已经不成“锥”了)。 GL_SPOT_CUTC

36、一殳的取值范围是0.0, 90.0( 或 者就是取那个 180)。下面的语句将散射角置为 45度。glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 45.0);你还需要给出聚光灯的方向,即圆锥中轴的方向。GLfloat spot_direction = -1.0, -1.0, 0.0 ;glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);方向是用齐次坐标表示的,缺省情况下为 (0, 0, 1) ,所以如果你不显式设置 GL_SPOT_DIRECTION值,聚光灯光线将射向z轴负向。同时,这个方向将被透 视模型矩阵

37、按其标准化后的值转换到视点坐标系中 (参见“控制光源的位置和方 向”一节以了解更多的有关位置转换的知识 )。除了聚光灯的散射角和方向外, 你还可以控制光线在圆锥内的强度分布。 有两个 办法,首先,你可以先设置光线衰减因子,我们前面提到过,它将与光强相乘; 你也可以设置聚光指数,即 GL_SPOT_EXPONEN数,它决定了光线的集中性, 缺省值为 0。光线在圆锥的中心最强,越靠边越弱,其衰减与该光线与圆锥中轴 的夹角的COSfi的GL_SPOT_EXPONEN数次方成正比。因此聚光指数越大,锥 光的集中性越好。请参阅“光照的数学”一节以了解光强计算的细节。多光源如前所述,你可以在你的场景中至少

38、使用 8个光源(当然可以更多,这取决于你 的需要)。因为OpenGL需要对每个顶点从所有光源接收的光进行计算,所以增加光源的数目无疑会使系统处理效率下降。用来代表个光源的常量为 GL_LIGHT0, GL_LIGHT1,GL_LIGHT2,GL_LIGHT欝等。在前面的讨论中,已经对与GL_LIGHT0 相关的参数进行了设置。 如果要增加光源, 则必须对其参数进行设置。 不过要记 住,其他光源的缺省参数与 GL_LIGHT0勺是不同的,如表6-2所示。下面的代码 定义了一个衰减的白色聚光灯。GLfloat light1_ambient = 0.2, 0.2, 0.2, 1.0 ;GLfloat

39、 Iight1_diffuse = 1.0, 1.0, 1.0, 1.0 ;GLfloat Iight1_specular = 1.0, 1.0, 1.0, 1.0 ;GLfloat Iight1_positio n = -2.0, 2.0, 1.0, 1.0 ;GLfloat spot_directio n = -1.0, -1.0, 0.0 ;glLightfv(GL_LIGHT1, GL_AMBIENT, Iight1_ambie nt);glLightfv(GL_LIGHT1, GL_DIFFUSE, Iight1_diffuse);glLightfv(GL_LIGHT1, GL_SP

40、ECULAR, Iight1_specular);gILightfv(GL_LIGHT1, GL_POSITION, Iight1_positi on);gILightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.5);gILightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.5);gILightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.2);gILightf(GL_LIGHT1, GL_SPOT_CUTOFF, 45.0);gILightfv(GL_LIGHT0, GL_SPOT_DIR

41、ECTION, spot_directio n);gILightf(GL_LIGHT1, GL_SPOT_EXPONENT, 2.0);glE nabIe(GL_LIGHT1);如果将这些代码加入例6-1中,那么其中的球体将被两个光源照射,一个是方向型的,另一个是位置型的。可以尝试一下,修改例6-1,*将原来的白色方向光源修改为一个位置型有色光源*加入一个有色聚光灯。提示:可以参考上面的代码*感觉一下这两种改动对整体效果的影响 控制光源位置和方向Ope nGl对光源的位置和方向的处理与它对基本的几何形体的处理是类似的。换 句话说,光源与基本形体有着相同的矩阵变换。进一步讲,当使用 gILigh

42、t*() 来指定光源的位置和方向时,这些位置和方向就通过当前的透视模型矩阵转换到 视点坐标系中。这意味着你可以通过修改当前透视模型矩阵栈中的内容来控制光 源的位置和方向(注:投影矩阵不会对光源的位置和方向产生影响)。本节将介绍如何通过修改程序中对光源位置的设置来获得三种不同的效果,这是与模型和透视变换相关的。这些效果是:固定位置光源环绕固定物体运动的光源和视点一起运动的光源例6-1作为最简单的例子,演示了固定位置光源。要达到这个效果,你只需要在 使用了透视或(和)模型变换后设置光源位置。下面是 myinit()和myReshape() 函数中的相关语句:gIMatrixMode (GL_PRO

43、JECTION);glLoadlde ntity();if (w = h)glOrtho (-1.5, 1.5, -1.5*h/w, 1.5*h/w, -10.0, 10.0);elseglOrtho (-1.5*w/h, 1.5*w/h, -1.5, 1.5, -10.0, 10.0);glMatrixMode (GL_MODELVIEW);glLoadIde ntity();/* later in myI ni t() */GLfloat light_positi on = 1.0, 1.0, 1.0, 1.0 ;glLightfv(GL_LIGHT0, GL_POSITION, posi

44、tion);视窗和投影矩阵被首先确定。然后,单位阵被调入作为透视模型矩阵,接下来设 置光源位置。因为使用了单位阵,因此光源的初始位置 (1.0, 1.0, 1.0) 和它相 乘并没有变化。在这之后,光源位置和透视模型矩阵都没有改变, 所以光源还放 在(1.0, 1.0, 1.0)的位置。现在假设你要旋转或移动光源的位置使其相对一个静态的物体运动。一个办法是在模型变换后设置光源位置,光源位置改变的效果是通过模型变换阵的改变来实 现的。你仍可以在程序开头使用上面的ini t()函数。然后,一般是在程序消息 循环里加入你想要的模型变换(利用透视模型栈)从而确定光源的新位置。下面是 一段可能的代码:v

45、oid display(GL int spin)GLfloat light_position = 0.0, 0.0, 1.5, 1.0 ;glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glPushMatrix();glTranslatef(0.0, 0.0, -5.0);glPushMatrix();glRotated(GLdouble) spin, 1.0, 0.0, 0.0);glLightfv(GL_LIGHT0, GL_POSITION, light_position);glPopMatrix();auxSolidTorus(0.

46、275, 0.85);glPopMatrix();glFlush();display() 函数重画场景, 重画时光源好象是绕静态圆环面转过了 spin 代表的角 度。请注意两对 glPushMatrix() 和 glPopMatrix() 函数,它们是用来隔离透视和 模型变换的, 之所以要隔离是因为需要画的圆环面是不旋转的, 即画它时只受到 glTranslatef(0.0, 0.0, -5.0); 这条语句的影响。在本例中视点保持不变,所 以当前的变换阵被压栈, 然后由 glTranslatef() 完成透视变换 ( 实际就是位移 ) , 将现在的变换阵压栈,再由 glRotated() 完

47、成模型变换 ( 其实就是旋转变换 ) 。此 时设置新的光源位置, 由于此位置是在旋转后的坐标系中定义的, 所以变换回原 坐标系中后就好象光源被旋转了一样 ( 注:原也就是视点坐标系,与之对应的变 换阵一直被压在栈里 ) 。在光源位置定义完毕后, 与透视变换对应的矩阵被弹出, 此时再画圆环面, 就象前面所说的那样, 转换到原坐标系中, 圆环面只有位置变 换而无旋转变换,所以看起来就有了光源环绕圆环面旋转的效果。为了创建和视点一起移动的光源, 你需要在透视模型变换之前设置光源位置, 这 样,变换就会按相同的方式一起变换视点和光源。让我们在 myinit() 函数中, 作一些小改动来达到这个效果:G

48、Lfloat light_position = 0.0, 0.0, 1.0, 1.0 ; /这样光源好象是放在视点的位置上glViewport(0, 0, w-1, h-1);glMatrixMode(GL_PROJECTION);glLoadlde ntity();gluPerspective(40.0, (GLfloat) w/(GLfloat) h, 1.0, 100.0);glMatrixMode(GL_MODELVIEW);glLightfv(GL_LIGHT0, GL_POSITION, light_position);然后对display()函数修改如下:void display

49、(GL int spin)glClear(GL_COLOR_BUFFER_MASK | GL_DEPTH_BUFFER_MASK);glPushMatrix();glTra nslatef (0.0, 0.0, -5.0);glRotatef (GLfloat) spi n, 1.0, 0.0, 0.0);auxSolidTorus(0.275, 0.85);glPopMatrix();glFlush();当被照的圆环面重画时,光源和视点都被移动了spin角度。因为我们是在视点的坐标系中,所以看到的效果是一个旋转的圆环面被固定的视点的光源照射的效 果。可以尝试一下,修改下面的例子 6-1 :让

50、光源只是相对物体移动而不是环绕其转动。提示:在display。中用glTranslated() 代替glRotated(),同时找一个合适的参数代替 spin*改变光源衰减模式,使光源远离物体时物体上的光照会减弱。提示:加入glLight*() 设置相应参数例6-1:通过模型变换移动光源:movelight.c#include #include #include aux.hstatic int spin = 0;void movelight (AUX_EVENTREC *event)spin = (spin + 30) % 360;void myinit (void)glEnable(GL_L

51、IGHTING);glEnable(GL_LIGHT0);glDepthFunc(GL_LEQUAL);glEnable(GL_DEPTH_TEST);void display(void)GLfloat position = 0.0, 0.0, 1.5, 1.0 ;glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix ();glTranslatef (0.0, 0.0, -5.0);glPushMatrix ();glRotated (GLdouble) spin, 1.0, 0.0, 0.0);glRotated

52、(0.0, 1.0, 0.0, 0.0);glLightfv (GL_LIGHT0, GL_POSITION, position);glTranslated (0.0, 0.0, 1.5);glDisable (GL_LIGHTING);glColor3f (0.0, 1.0, 1.0);auxWireCube (0.1);glEnable (GL_LIGHTING);glPopMatrix ();auxSolidTorus (0.275, 0.85);glPopMatrix ();glFlush ();void myReshape(GLsizei w, GLsizei h)glViewpor

53、t(0, 0, w, h); glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(40.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0); glMatrixMode(GL_MODELVIEW);int main(int argc, char* argv)auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH); auxInitPosition (0, 0, 500, 500);auxInitWindow (argv0);myi nit();auxM

54、ouseFu nc (AUX_LEFTBUTTON, AUX_MOUSEDOWN, movelight); auxReshapeF unc (myReshape);auxMa in Loop(display); 6.4选择光照模型OpenGL的光照模型概念有如下三个方面:全局环境光强度视点位置在场景内还是可以被认为是无限远处对物体表面的正反面光照计算是否不同本节介绍如何设置光源,同时介绍如何起用之即如何告诉Ope nGL尔需要对相应光照进行计算。 全局环境光如前所述,每个光源都对场景的环境光有贡献。 同时,还有一种环境光不是由光 源提供的,这就是全局环境光。 设置全局环境光的RGB/强度,需要

55、按下面的方 式使用 GL_LIGHT_MODEL_AMBI参数:GLfloat lmodel_ambie nt = 0.2, 0.2, 0.2, 1.0 ;glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambie nt);本例中lmodel_ambient的参数值都是 GL_LIGHT_MODEL_AMBlEN抉省值。因为这些数值会产生少量的环境光,所以即使不定义其它光源你仍可以看到场景中的 物体。附录J中图J-18演示了设置不同强度全局环境光的效果。 局部和无穷远视点视点位置影响到由于镜面反射导致的高光点计算。更具体地讲,高光点的强度由三个因素决

56、定:被照顶点的法向量、从光源到顶点的光线方向、视点和顶点的连 线方向。有一点要明白,使用各种光照命令后,实际上移动的并不是视点,你所 做的是改变了投影方式,使视点看起来被移动了 (请参阅“投影变换”一节)。不 过,在光照计算中,很多地方是假设光源位置改变的。对于无穷远视点来说, 它和某顶点的连线方向是个常数。 局部视点的效果更趋于 真实,但由于它要对每个顶点的方向分别计算, 就大大增加了程序的负担。 缺省 状态下,视点都是在无穷远处的。下面的语句可以把它改成局部的:glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);这条语句把视点放在视点坐标

57、系的 (0,0,0) 位置。想变回无穷远视点,只要把最 后一个参数改成GL_FALS就行了。 双侧光照光照计算是对所有多边形表面进行的, 不管是正面还是反面。 由于通常设置的都 是正面的光照性质, 背面的光照效果往往都是不正确的。 在例 6-1 中,被照物体 是球面, 可以看到的永远是其正面, 也就是球的外表面, 所以背面的光照效果根 本看不到,也就无所谓了。如果球面被切开,其内侧就会被看到,那么你一定希 望里面的光照效果和外面定义的一致, 你也许还需要给内表面贴上一种不同的材 质。起用双侧光照的语句如下:glLightModeli(LIGHT_MODEL_TWO_SIDE, GL_TRUE)

58、;Ope nGl会把正面顶点的法向量反过来作为背面的法向量。这样,所有多边形的 光照效果就正确了。关闭双侧光照,只需把前面语句中的GL_TRU换成GL_FALS即可。参阅“定义材质特性”一节以了解如何给双侧设置材质特性。你还可以通过 glFrontFace() 命令设置哪个表面被 OpegGL认为是正面,参阅“ Reversing and Culling Polygon Faces” 一节,那里对该命令会详细解释。 起用光照在OpenGL中你需要显式地起用(或取消)光照计算。如果光照没有被起用,当前 的颜色只是简单地被映射到当前顶点上, 不会进行任何关于法向量、 光源、光照 模型,以及材质的计算。下面是起用光照的命令:glEnable(GL_LIGHTING);取消光照的命令为 glDisable(GL_LIGHTING); 。当你设置了你定义的每个光源后, 你必须显式地打开它们。 在例 6-1 中只使用了 一个光源,GL_LIGHT0打开它的语句为:glEnable(GL_LIGHT0); 6.5 定义材质特性 本节将介绍如何定义物体的材质:环境反射色、漫反射色和镜

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!