版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、OpenGL点光源在OpenGL场景描述中可以包含多个点光源, 光源的各种属性设置使用函数:void glLight(if (GLenum light, GLenum pname, TYPE param);void glLight(ifv (GLenum light, GLenum pname, TYPE *param);指定。其中,参数light指定进行参数设置的光源,其取值可以是符号常量GL_LIGHT0 ,GL_LIGHT1,GL_LIGHT7 ;参数pname指定对光源设置何种属性,其取值参见表10-1;参数param指定对于光源light的pname属性设置何值,非矢量版本中,它是一
2、个数值,矢量版本中,它是一个指针,指向一个保存了属性值的数组。表10-1参数pname的取值及其含义堆认伯t-X-GL AA BIENTto o. 0.0,6.0.1.0此漏中环境丈; .GL DIFFUSE(tjd. l.Oi 1A0A 0A 1.0元疆宰菱慎射咒分学-(IAIJO,LtL L0)莪 go.O Q. O O, L0GLPOSITION(0.0. OaLO-OjO元修的坐板宜置.1 SPOT DIRECTIONLO.Q.iJOM。卜珥点事知(T方向关GL_SPOT EXPONENT伊卜GL SPOT CITTCFFLSO.O就止#.1GL _L KE ARjWreNUATIg,
3、0A嫌慢曩娥闵子,GLjQUADRAnCjOTENUAngoo.二衣点滴因尹(1)点光源的颜色点光源的颜色由环境光、漫反射光和镜面光分量组合而成,在OpenGL中分别使用GL_AMBIENT、GL_DIFFUSE和GL_SPECULAR指定。其中,漫反射光成分对物体的影响 最大。(2)点光源的位置和类型点光源的位置使用属性GL_POSITION指定,该属性的值是一个由4个值组成的矢量(x, y, z, w)。其中,如果w值为0,表示指定的是一个离场景无穷远的光源,(x, y, z)指定了光源的方向,这种光源被称为方向光源,发出的是平行光;如果w值为1,表示指定 的是一个离场景较近的光源,(x,
4、 y, z)指定了光源的位置,这种光源称为定位光源。(3)聚光灯当点光源定义为定位光源时,默认情况下,光源向所有的方向发光。但通过将发射光限 定在圆锥体内,可以使定位光源变成聚光灯。属性GL_SPOT_CUTOFF用于定义聚光截止角,即光锥体轴线与母线之间的夹角,它的值只有锥体顶角值的1/2。聚光截止角的默认值为180.0,意味着沿所有方向发射光线。 除默认值外, 聚光截止角的取值范围为0.0 , 90.0。GL_SPOT_DIRECTION属性指定聚光灯光锥轴线的方向,其默认值是(0.0 , 0.0 , -1.0),即光线指向z轴负向。而GL_SPOT_EXPONENT属性可以指定聚光灯光锥
5、体内的光线聚集 程度,其默认值为0。在光锥的轴线处,光强最大,从轴线向母线移动时,光强会不断衰减,衰减的系数是:轴线与照射到顶点的光线之间夹角余弦值的聚光指数次方。(4)光强度衰减属性GL_CONSTANT_ATTENUATION、GL_LINEAR_ATTENUATION、GL_QUADRATIC_ATTENUATION分别指定了衰减系数c0, c1和c2 ,用于指定光强度的 衰减。在OpenGL中,必须明确启用或禁用光照。默认情况下,不启用光照,此时使用当前颜 色绘制图形,不进行法线矢量、光源、光照模型、材质属性的相关的计算。要启用光照,可 以使用函数:glEnable(GL_LIGHTI
6、NG);指定了光源的参数后,需要使用函数:glEnable(light);启用light指定的光源。当然也可以用light参数调用glDisable函数,禁用light指定的光源。 需要特别说明的是,点光源的位置和方向是定义在场景中的,与景物一起通过几何变换和观察变换变换到观察坐标系中,因此光源既可以与场景中对象的相对位置保持不变,也可以使光源随观察点一起移动。OpenGL全局光照在OpenGL中,还需要设定全局光照(相当于背景光)。OpenGL提供了下面的函数对全局光照的属性进行定义。void glLightMode(if (GLenum pname , TYPE param);void g
7、lLightMode(ifv (GLenum pname , TYPE *param);其中,参数pname指定全局光照的属性,其取值参见表10-2;参 数param指定进行设置的属性的值。表10-2参数pname的取值及含义pMinr VS-AXOL LIOKT MODEL .CBtEXTh0.2.0.2,0.2. 1.0).整卜炉肇苗鲂城光耽GLLIGHT MODEL LOCAL VtEUTRGL, FALSEM何计如.射第OL LIGHT XtODEL TWO SIDEGLJALSE-GL LIGHT MODEL. COLOR,CONTROLGLsPINOLE厦,忙生罚件基曹排立干豚*跚
8、色.属性GL_LIGHT_MODEL_AMBIENT指定OpenGL场景中的背景光,如果不指定,系统 使用低强度的白色(0.2, 0.2, 0.2, 1.0)光。镜面反射时需要几个矢量参数,包括从物体表面到观察位置的矢量V,它指出表面位置与观察位置的关系。矢量V的默认方向为正z方向(0.0, 0.0 , 1.0),如果不希望用默认值 而使用位于观察坐标原点的实际观察位置来计算V ,则将GL_LIGHT_MODEL_LOCAL_VIEWER属性值指定为GL_TRUE。在有些应用中,需要看到物体的后向面,例如实体的内部剖视图。此时需要打开双面光 照,即对物体的前向面和后向面都进行光照计算。在光照计
9、算中,通常是分别计算环境光、表面散射光、漫反射光和镜面反射光的贡献,然后将其叠加。 默认情况下, 纹理映射在光照处理之后进行。但这样镜面高光区的纹理图案会变得不太理想。为此,可以将GL_LIGHT_MODEL_COLOR_CONTROL指定为GL_SEPARATE_SPECULAR_COLOR,在纹理映射之后应用镜面颜色。这样,对于光照计算将生成两个颜色:镜面反射颜色和非镜面反射颜色。纹理图案先和非镜面反射颜色混合, 然后再和镜面反射颜色混合。OpenGL表面材质在启用了光照后,物体表面的颜色将由照射在其上的光的颜色以及物体的材质属性决定。所谓物体的材质属性,就是物体表面对各种光的反射系数。在
10、OpenGL中使用下面的函数设定:void glMaterial(if (GLenum face, GLenum pname, TYPE param);void glMaterial(ifv (GLenum face, GLenum pname, TYPE*param);其 中 ,face的 取 值 可 以 是 符 号 常 量GL_FRONT,GL_BACK,GL_FRONT_AND_BACK,指定当前设定的材质属性应用于物体表面的前向面、后向面还是前后向面,这使得可以对物体内外表面设置不同的材质属性,在打开双面光照的情况下产生特殊的效果。参数pname指定设置的材质属性,其取值参见表10-3
11、;参数param设置属性的值。表10-3参数pname的取值及含义pniaiuf敬就认酒GL AMBIENT(&X 0 2.0 2/1 Ok树都对环境尤的脱村隼花-GL_DIFFXJSE-(Q&O&O.&LOAHff/t事射止旷反时手ftQt AMBthXT WD_DI0.5, 0.5 0.5) = (0.25,0.5, 0.25)即将每个环境光源的成分与材质的环境反射率相乘。这样,物体表面的颜色为多项RGB值的叠加:包括材质对环境光的反射率与环境光结合的RGB值,材质对漫反射光的反射率与漫反射光结合的RGB值,材质对镜面光的反射率与镜面反射光结合的RGB值等。
12、当叠加的RGB中任何一个颜色分量的值大于1.0,那么就用1.0计算。但是,在这种设定下,有时很难判断出物体在光照环境中的颜色,为此OpenGL提供了另一种材质模式,即颜色材质模式,可以通过函数:void glColorMaterial (GLenum face, GLenum mode);设置。其中,参数face可以取GL_FRONT , GL_BACK ,GL_FRONT_AND_BACK,指定 物体的哪个面的材质属性使用颜色材质模式;而参数mode允许的取值是GL_AMBIENT、GL_DIFFUSE、GL_SPECULAR、GL_AMBIENT_AND_DIFFUSE或GL_EMISSI
13、ON ,指定 将更新哪种材质属性。在使用了颜色材质模式后,需要调用:glE nable(GL_COLOR_MATERIAL);这样,可以通过glColor函数来指定物体表面的颜色,而相应的材质属性将通过颜色值和光源的RGB值计算出来。光照效果是光线与表面共同作用的结果。在 OpenG序,光线被假定成红绿蓝三种原色光的组合,因此,光源的颜色就由 它所发出的这三种原色光的含量决定, 而物理表面的颜色则由其反射的这三种光 的含量决定。OpenGL勺光照模型尽管只是一个近似,但它很管用且计算速度很 快。如果你需要一个更精确的模型, 那么只好自己编程计算了, 不过模型越精确 则计算速度越慢。在场景中,O
14、penGlM以放置若干个光源,每个光源都可以被单独地打开或关闭。 照在物体上的光线有些是直接来自光源, 而另一些是光源的光经过若干次反射而 来。这些多次反射的光被称为环境光(Ambient Light),它们已经变得很“散”,以致丁无法确定其初始方向,不过当某个光源(产生它们的光源)被关闭后,它们 也就消失了。不同的物理表面对光线有不同的反射特性, 那些通常看起来很光泽的表面能够将 入射光很好地向某一特定方向反射,而另外一些则将入射光均衡地散射向各个方 向。大部分表面的特性是介丁这两者之间的。 当然有些表面也会自己发光,比如 汽车前灯。OpenGlM 光照效果的计算是由四个独立的部分叠加而成的
15、,它们是:出射光 自 发光(emitted)、环境光(ambient)、漫反射光(diffuse)、镜面光(specular)。出射光是最简单的,它从物体发出且不受任何其它光源的影响。环境光从光源发出并经过多次反射形成的, 它均匀从周围环境入射至物体表面并 朝各个方向等量反射。漫反射光是直接从特定光源入射并朝各个方向等量反射的光, 入射角越小它看起 来越亮,同时从各个角度来看它的亮度是一样的。镜面光也是直接从特定光源入射的, 但在反射时只朝特定的方向反射(遵从镜面反射定理)。一束平行激光在高质量的镜面上可以几乎被 100泌反射。表面光泽 的金届或塑料都有很高的镜面反射成份,而象粉笔或地毯之类的
16、光泽度差的物品 则几乎没有。尽管同一光源出射的光的频率分布是一定的, 但照在不同的表面上产生的环境 光、漫反射光、镜面光分量却可能不同。比如白光照在房间的红色墙壁上,被散射的光就会趋丁红色。OpenGL允许对各个反射光分量的 RGB值分别作独立的 调整。6.1.2 材质颜色OpenG序近似认为材质的颜色由它的反射光中的红绿蓝三色所占的白分比决 定。比如:一个理想的红色球将反射入射的所有红光并吸收所有绿色和蓝色光。这样的球在白光(含红绿蓝三色光)和纯红光的照射下的表现是一致的-都是 红色球, 然而在不含红光成份的光(如纯绿光)的照射下则呈现为黑色(因为没有光被反射)。与光线对应, 材质有独立的环
17、境反射、 漫反射和镜面反射颜色成份,分别决定了 材质对环境光、漫反射光和镜面光的反射能力。环境反射和漫反射决定了物体的 颜色,这两种成份很相象,甚至可以当作一种来处理。镜面反射色通常为白色或 灰色,因此镜面反射的高光(highlights)通常是光源的镜面光成份的颜色和强度决定。 想象一束白光照射在一个有光泽的红色金届球上, 球体的大部分将表现为 红色,而高光处则为白色。 6.1.3 光线与材质的 RGBS光线颜色的 RGB定义于材质的 RGBS 定义有所不同。对光线来说, RGEfi 的大小对应于该色光强度与其最高强度的比例白分数。比如 一束光的 RGEO是 1.0,那么它就是最强的白光;如
18、果这些值都为 0.5,则整束 光的颜色还是白色,只不过强度减半,看起来是灰色。如果R=G=1.0而 B=0.0,那么就是最强的黄光。对材质来说, RGEfi 的大小对应于材质对该色光的反射比例白分数。比如某材质 的 R=1.0, G=0.5, B=0.0,则它反射入射的所有红光,一半的绿光,不反射蓝光。换句话来说,如果一束光的 RGEfi 为(LR,LG, LB),被照材质的RGEfi为(MR, MG, MB),则在不考虑其它反射效果的情况下,眼睛所看到的颜色由 (LR*MR, LG*MG, LB*MB 决定。类似地,如果到达眼睛的两束光的 RG皱份分别为(R1, G1, B1)和(R2, B
19、2, G2), 则 OpenGK 相应的成份相加,得到(R1+R2,G1+G2,B1+B2)。如果任何一个相加 结果大于 1(表明这样的光强是显示设备不能实现的),则被认为是 1。 6.2 简例:渲染一个球体向场景中加入光照的步骤如下:1.定义所有物体每个顶点的法向量方向。这些法向量决定了物体表面与光源的 相对取向。2.建立、选择并放置一个或多个光源。3.建立并选择一个光照模型, 它决定了全局环境光照的程度以及视点的有效位 置(用于光照计算)。4.定义场景中物体的材质。例 6-1将显示一个在独立光源照射下的球体,如前面的图6-1所示例 6-1 :光照下的球体:#include #include
20、 #include aux.hvoid myinit(void)GLfloat 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
21、);glEnable(GL_LIGHTING);glEnable(GL_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
22、= h)glOrtho (-1.5, 1.5, -1.5*(GLfloat)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 |
23、AUX_DEPTH);auxInitPosition (0, 0, 500, 500);auxInitWindow (argv0);myinit();auxReshapeFunc (myReshape);auxMainLoop(display);与光照有关的调用写在函数 myinit()中,下面我们将会简单地讨论它们的用法, 在后面的章节中还会仔细研究。在例 6-1 中需要注意的一点是,它使用了 RGBA 颜色模式,而不是颜色索引模式(color-index) 。OpenGlM这两种模型的光照计 算是不同的,而且实际上颜色索引模式的光照表现力是很有限的,因此RGBA!比较受推崇的光照模式,本章
24、中的所有例子都使用该模式。 需要对颜色索引模式 作进一步了解的请参阅“颜色索引模式中的光照” 一节。场景中物体的材质特性决定了光线是如何被反射的从而表现出它是用什么材料 做的。因为入射光线与物体材质表面的作用相当复杂,所以通过设置物体的材质特性而使它“看起来象那么会事”就是一件很技术的活了。 你需要制定一种材质 的环境光反射色、漫射光反射色、镜面光反射色(这里说XX反射色的意思是指对 某种光的某个颜色分量的反射能力)以及它的光泽度。在这个例子中,只有最后 两个特性镜面光反射颜色和光泽度被明确地指定(通过使用 glMaterialfv()函数)。 在“定义材质特性” 一节中会描述所有的材质特性参
25、数并给出例子。重点江息:在写你自己的光照程序时, 记住可以修改一些参数值, 而另一些参数使用其缺省 值。 当然, 不要忘记使你定义的光源生效(enable之),同时允许光照计算。最 后,记住你可以使用显示列表以提高在改变光源位置时的计算效率(参阅“显示歹 0表设计”一节) 6.3 创建光源光源有如下届性:颜色、位置和方向。下面将讨论如何控制这些届性一达到期望 的效果。我们用来设置光源的所有届性的函数是 glLight*(),它有三个参数, 分别用来代表光源标识、需设置的届性及期望的届性值。函数形式为:void glLightifv(GLenum light, GLenum pname, TYP
26、E param);light是光源的标识,例如:GL_LIGHT0,GL_LIGHT1.GL_LIGHT7 一 股地, GL_LIGHTi代表第 i 号光源。pname 代表需设有的届性,其及举值和对应的届性 意义见表 6-1 oparam代表需要给 pname 弋表的届性设置的值。注意,TYP 昵 param 的类型,它由 glLight 函数名后面跟的字母决定,i 就是 int , f 就是 float , v(就 是 vectro)可选,选了说明 param代表指向一组参数的指针,不选则说明是单一 参数。表 6-1 glLight*()的 pname数及其缺省值(本表系从yxy (田丝丝
27、#冬眠的小肥鹰)的教程中拷贝而来,改了一点点,呵呵 )pname缺省值说明GL_AMBIENT0,0,0,1RGBAK式的环境光GL_DIFFUSE1,1,1,1RGBAK式的漫反射光GL_SPECULAR1,1,1,1RGBAK式的镜面光GL_POSTION1,0,1,0光源位置齐次坐标(x,y,z,w)GL_SPOT_DIRECTION0,0,-1聚光灯聚光方向欠量GL_SPOT_EXPONENT0聚光灯聚光指数GL_SPOT_CUTOFF180聚光灯聚光发散半角GL_CONSTANT_ATTENUATIO N1常数衰减因子GL_LINER_ATTENUATION0线性衰减因子GL_QUA
28、DRATIC_ATTENUATION平方哀减因子表 6-1 中相对 GL_DIFFUSIK GL_SPECULAft 缺省值只对GL_LIGHT0t效,对丁 其它的光源,它们的缺省值都是 (0.0, 0.0,0.0, 1.0)。卜面是使用 glLight*() 的一个例子:GLfloat light_ambient = 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_position = 1.0,
29、1.0, 1.0, 0.0 ;glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);glLightfv(GL_LIGHT0, GL_POSITION, light_position);数组被用来给参数赋值,通过反复调用glLightfv()给不同的参数赋值。在这个例子里, 前三条语句是多余的, 因为它们设置的分别是那三个参数的缺省值。记住要用 glEnable
30、打开每个光源。 要了解更多的相关操作, 请参阅“使光源生 效” 一节。在下面的部分中将解释 glLight*()的所有参数和它们可能的取值。这些参数和 定义全局光照模型以及物体材质特性的参数息息相关。请参阅“选择光照模型” 和“定义材质特性”以获取更多的知识。在“光照的数学”中,将从数学的角度 解释这些参数是如何相互作用的。 6.3.1 颜色OpenGLA许对光源的三个不同的与颜色相关的参数:GL_AMBIENT, GL_DIFFUSE和 GL_SPECULAR 行调整。GL_AMBIENT 数代表场景中某光源的环境光的 RGB 点个分量强度。象表 6-1 中 列而那样,缺省情况下是没有环境光
31、的,因为 GL_AMBIENT(0.0, 0.0, 0.0, 1.0)。例 6-1 中使用的正是这样的值。如果程序将环境光设为蓝光,应该这样GLfloat light_ambient = 0.0, 0.0, 1.0, 1.0;glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);那么产生的结果如附录 J中图 J-14所示。GL_DIFFUSET 能是与“光的颜色”联系最大的参数了,它定义了特定光源提供 的漫反射光的 RGB 濒色值。缺省情况下,光源GL_LIGHT0 勺 GL_DIFFUSfit 是 (1.0,1.0, 1.0, 1.0) ,即产生明亮
32、的白光,如附录 J 中图 J-14。而其它光源 (GL_LIGHT1 到GL_LIGHT7)勺缺省值都是(0.0, 0.0, 0.0, 0.0)。GL_SPECULAR 数影响物体上的高光点颜色。现实世界中的典型例子如玻璃瓶子 上而高光点显示的就是照在上面的光的颜色。因此,如果你想获得逼真的效果,应该将 GL_SPECULAW设得和 GL_DIFFUSE 样(为什么?我想是获得逼真的金 届光泽效心巴。 )所有的光源的GL_SPECULAR数缺省值和GL_DIFFUS缺省值 也是一样的。 6.3.2 位置与衰减光源的位置有两种。一种是离场景无限远,另一种是在附近。前者被称为方向光 源,它射到物体
33、上的光可以认为是平行的。现实生活中,太阳就是这样的光源。后者被称为位置光源, 因为它的确切位置决定了它对场景的作用效果,尤其是决 定了光线的投射方向。台灯就是位置光源。从附录 J图 J-16 中你可以看到这两 种光源的不同作用效果。在例 6-1中使用的是方向光源:GLfloat light_position = 1.0, 1.0, 1.0, 0.0 ;glLightfv(GL_LIGHT0, GL_POSITION, light_position);如上所示, 你给 GL_POSITIOI#数提供了一个四个值的向量(x, y,z, w)。如果 最后一个值 w 是 0,则相应的光源为方向光源,且
34、(x,y, z) 决定其方向。这个 方向将被透视模型(modelview,这个词俺不知该怎么翻,根据后面的描述,模型 变换是指旋转变换,透视变换是只位移变换)矩阵转化到视点坐标系中, 就好象 它是一个被标准化的向量一样。GL_POSITION 勺缺省值为(0,0, 1, 0) ,指向 Z轴的负方向。(注:你当然可以定义诸如(0,0,0)的方向,但这对处理光照是没有 意义的)如果 w是非零值,光源就是位置型的。而(x,y,z)代表光源位置的齐次坐标(参见 附录 G)。该位置将被透视模型矩阵转换到视点坐标系中 (参见“控制光源的位置 和方向”一节以了解更多的有关位置转换的知识 )。在缺省意义下,光
35、源的光是 向各个方向发出的,不过你也可以定义一个聚光灯使其发射锥光,这将在下一节“聚光灯”中解释。请注意, 具有光滑阴影效果的多边形表面各部分的颜色是由其各顶点的颜色计算 决定的。正因为如此,你需要避免在局部光源附近使用大多边形-如果光源位 置在多边形的中部,各顶点会因为距离光源太远而接收不到足够的光照,从而整个多边形看起来要比你相象的要暗。 要解决这个问题, 就得把大多边形分解成许 多小块。在现实世界中, 光线的强度会随着传播距离的增加而减弱。 方向光源是从无限远 处射来的,对它谈距离衰减意义不大,所以衰减计算对方向光源是无效的。 然而, 对位置光源则必须考虑这个问题。OpenGL!过给光源
36、的光乘上一个因子来达到 衰减的目的。衰减因子 =其中,d为光源到顶点的距离 kc为 GL_CONSTANT_ATTENUATIONki为 GL_LINEAR_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,
37、 0.5);注意,环境光、漫反射光和镜面光都会被衰减,只有出射光和全局环境光不被衰 减。 6.3.3 聚光灯前面曾提到,你可以将一个位置光源定义成一个聚光灯, 也就是说可以将光的发 射形状调整为圆锥形。创建聚光灯,你需要定义需要的锥光的跨度。(记住,因为聚光灯是位置光源,你还是需要为它定义一个位置。 你当然也可以方向光源定 义为聚光灯, 从语法上没有错, 但是无意义) 。定义锥光的散射角(即圆锥中轴和 边的夹角),需要使用GL_SPOT_CUTOF 敝,圆锥的顶角是该值的两倍,见图 6-2。图 6-2 GL_SPOT_CUTO 廖数示意注意光线不能超越圆锥的边界。缺省时没有聚光灯效果,因为GL
38、_SPOT_CUTOFF参数被默认为 180 度, 也就意味着光线是超各个方向发射的(此时两锥的顶角为 360,已经不成“锥” 了)。GL_SPOT_CUTOF的取值范围是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);方向是用齐次坐标表示的,缺省
39、情况下为(0, 0,1),所以如果你不显式设置 GL_SPOT_DIRECTIOW,聚光灯光线将射向 z 轴负向。同时,这个方向将被透 视模型矩示其标准化后的值转换到视点坐标系中(参见“控制光源的位置和方向”一节以了解更多的有关位置转换的知识)。除了聚光灯的散射角和方向外, 你还可以控制光线在圆锥内的强度分布。有两个办法,首先,你可以先设置光线衰减因子,我们前面提到过,它将与光强相乘; 你也可以设置聚光指数,即GL_SPOT_EXPONENT,它决定了光线的集中性, 缺省值为 0o光线在圆锥的中心最强, 应靠边越弱, 其衰减与该光线与圆锥中轴 的夹角的 COSfi 的 GL_SPOT_EXPO
40、NENT 次方成正比。 因此聚光指数越大,锥 光的集中性越好。请参向“光照的数学” 一节以了解光强计算的细节。 6.3.4 多光源如前所述,你可以在你的场景中至少使用8 个光源(当然可以更多,这取决于你的需要)。因为 OpenGLB 要对每个顶点从所有光源接收的光进行计算,所以增加 光源的数目无疑会使系统处理效率下降。用来代表个光源的常量为GL_LIGHT0,GL_LIGHT1,GL_LIGHT2,GL_LIGHT 辞等。在前面的讨论中,已经对与 GL_LIGHT0 相又的参数进行 7 设置。如弟要增加光源,则必须对其参数进行设置。不过要记 住,其他光源的缺省参数与 GL_LIGHT0 勺是不
41、同的,如表 6-2 所示。下面的代码 定义了一个衰减的白色聚光灯。GLfloat light1_ambient = 0.2, 0.2, 0.2, 1.0 ;GLfloat light1_diffuse = 1.0, 1.0, 1.0, 1.0 ;GLfloat light1_specular = 1.0, 1.0, 1.0, 1.0 ;GLfloat light1_position = -2.0, 2.0, 1.0, 1.0 ;GLfloat spot_direction = -1.0, -1.0, 0.0 ;glLightfv(GL_LIGHT1, GL_AMBIENT, light1_am
42、bient);glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);glLightfv(GL_LIGHT1, GL_POSITION, light1_position);glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.5);glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.5);glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION
43、, 0.2);glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 45.0);glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 2.0);glEnable(GL_LIGHT1);如果将这些代码加入例 6-1 中, 那么其中的球体将被两个光源照射,一个是方向型的,另一个是位置型的。可以尝试一下,修改例 6-1 ,将原来的白色方向光源修改为一个位置型有色光源加入一个有色聚光灯。提示:可以参考上面的代码感觉一下这两种改动对整体效果的影响 6.3
44、.5 控制光源位置和方向OpenGlM光源的位置和方向的处理与它对基本的几何形体的处理是类似的。换 句话说,光源与基本形体有着相同的矩阵变换。进一步讲,当使用 glLight*()来指定光源的位置和方向时,这些位置和方向就通过当前的透视模型矩阵转换到 视点坐标系中。这意味着你可以通过修改当前透视模型矩阵栈中的内容来控制光 源的位置和方向(注: 投影矩阵不会对光源的位置和方向产生影响)。 本节将介绍 如何通过修改程序中对光源位置的设置来获得三种不同的效果,这是与模型和透视变换相关的。这些效果是:固定位置光源环绕固定物体运动的光源和视点一起运动的光源例 6-1作为最简单的例子,演示了固定位置光源。
45、要达到这个效果,你只需要在 使用了透视或(和)模型变换后设置光源位置。下面是 myinit()和 myReshape() 函数中的相关语句:glMatrixMode (GL_PROJECTION);glLoadIdentity();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);glLoadIdentity();/* later in myInit()
46、*/GLfloat light_position = 1.0, 1.0, 1.0, 1.0 ;glLightfv(GL_LIGHT0, GL_POSITION, position);视窗和投影矩阵被首先确定。 然后, 单位阵被调入作为透视模型矩阵, 接下来设 置光源位置。因为使用了单位阵,因此光源的初始位置 (1.0, 1.0, 1.0) 和它相 乘并没有变化。在这之后,光源位置和透视模型矩阵都没有改变,所以光源还放 在(1.0,1.0,1.0)的位置。现在假设你要旋转或移动光源的位置使其相对一个静态的物体运动。一个办法是在模型变换后设置光源位置, 光源位置改变的效果是通过模型变换阵的改变来实
47、 现的。你仍可以在程序开头使用上面的 init()函数。然后,一般是在程序消息 循环里加入你想要的模型变换(利用透视模型栈)从而确定光源的新位置。下面是 一段可能的代码:void display(GLint 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
48、.0);glLightfv(GL_LIGHT0, GL_POSITION, light_position);glPopMatrix();auxSolidTorus(0.275, 0.85);glPopMatrix();glFlush();display()函数重画场景,重画时光源好象是绕静态圆环面转过了spin 代表的角度。请注意两对 glPushMatrix()和 glPopMatrix()函数,它们是用来隔离透视和 模型变换的,之所以要隔离是因为需要画的圆环面是不旋转的,即画它时只受到glTranslatef(0.0,0.0,-5.0);这条语句的影响。 在本例中视点保持不变,所 以当前的
49、变亦阵被压栈,然后由 glTranslatef() 完成透视变换(实际就是位移),将现在的变换阵压栈,再由 glRotated()完成模型变换(其实就是旋转变换)。此 时设置新的光源位置,由于此位置是在旋转后的坐标系中定义的,所以变换回原坐标系中后就好象光源被旋转了一样(注: 原也就是视点坐标系,与之对应的变 换阵一直被压在栈里)。在光源位置定义完毕后,与透视变换对应的矩阵被弹出, 此时再画圆环面,就象前面所说的那样,转换到原坐标系中,圆环面只有位置变 换而无旋转变换,所以看起来就有了光源环绕圆环面旋转的效果。为了创建和视点一起移动的光源, 你需要在透视模型变换之前设置光源位置,这样,变换就会
50、按相同的方式一起变换视点和光源。让我们在myinit()函数中,作一些小改动来达到这个效果:GLfloat light_position = 0.0, 0.0, 1.0, 1.0 ; /这样光源好象是放在视点的位正上glViewport(0, 0, w-1, h-1);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(40.0, (GLfloat) w/(GLfloat) h, 1.0, 100.0);glMatrixMode(GL_MODELVIEW);glLightfv(GL_LIGHT0, GL_POSITION, l
51、ight_position);然后对 display()函数修改如下:void display(GLint spin)glClear(GL_COLOR_BUFFER_MASK |GL_DEPTH_BUFFER_MASK);glPushMatrix();glTranslatef (0.0, 0.0, -5.0);glRotatef (GLfloat) spin, 1.0, 0.0, 0.0);auxSolidTorus(0.275, 0.85);glPopMatrix();glFlush();当被照的圆环面重画时,光源和视点都被移动了spin 角度。因为我们是在视点的坐标系中, 所以看到的效果是
52、一个旋转的圆环面被固定的视点的光源照射的效 果。可以尝试一下,修改下面的例子 6-1 :*让光源只是相对物体移动而不是环绕其转动。 提示: 在 display()中用glTranslated()代替 glRotated(),同时找一个合适的参数代替 spin改变光源衰减模式,使光源远离物体时物体上的光照会减弱。提示:加入glLight*()设置相应参数例 6-1:通过模型变换移动光源:movelight.c#include #include #include aux.h static int spin = 0;void movelight (AUX_EVENTREC *event)(spin
53、= (spin + 30) % 360;void myinit (void)(glEnable(GL_LIGHTING);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 ()
54、;glRotated (GLdouble) spin, 1.0, 0.0, 0.0);glRotated (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 ();glF
55、lush ();void myReshape(GLsizei w, GLsizei h)glViewport(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,
56、0, 500, 500);auxInitWindow (argv0);myinit();auxMouseFunc (AUX_LEFTBUTTON, AUX_MOUSEDOWN,movelight);auxReshapeFunc (myReshape);auxMainLoop(display);6.4 选择光照模型OpenGLL勺光照模型概念有如下三个方面:全局环境光强度,视点位置在场景内还是可以被认为是无限远处对物体表面的正反面光照计算是否不同本节介绍如何设置光源,同时介绍如何起用之即如何告诉OpenGLL需要对相应光照进行计算。 6.4.1 全局环境光如前所述,每个光源都对场景的环境光有贡献
57、。 同时,还有一种环境光不是由光 源提供的,这就是全局环境光。设置全局环境光的 RGB 眦度,需要按下面的方 式使用GL_LIGHT_MODEL_AMBIBNT:GLfloat lmodel_ambient = 0.2, 0.2, 0.2, 1.0 ;glLightModelfv(GL_LIGHT_MODEL_AMBIENT,lmodel_ambient);本例中lmodel_ambient的参数值都是GL_LIGHT_MODEL_AMBIENT 省值。因为 这些数值会产不少量的环境光,所以即使不定义其它光源你也可以看到场景中的物体。附录 J中图 J-18演示了设置不同强度全局环境光的效果。6
58、.4.2 局部和无穷远视点视点位置影响到由丁镜面反射导致的高光点计算。更具体地讲,高光点的强度由 三个因素决定:被照顶点的法向量、从光源到顶点的光线方向、视点和顶点的连 线方向。有一点要明白,使用各种光照命令后,实际上移动的并不是视点,你所 做的是改变了投影方式, 使视点看起来被移动了(请参阅“投影变换” 一节)。不 过,在光照计算中,很多地方是假设光源位置改变的。对丁无穷远视点来说,它和某顶点的连线方向是个常数。局部视点的效果更趋丁真实,但由丁它要对每个顶点的方向分别计算,就大大增加了程序的负担。缺省状态下, 视点都是在无穷远处的。 下面的语句可以把它改成局部的:glLightModeli(
59、GL_LIGHT_MODEL_LOCAL_VIEWER,GL_TRUE);这条语句把视点放在视点坐标系的(0,0,0)位置。想变回无穷远视点,只要把最 后一个参数改成 GL_FALS 就行了。6.4.3 双侧光照光照计算是对所有多边形表面进行的, 不管是正面还是反面。 由于通常设置的都 是正面的光照性质,背面的光照效果往往都是不正确的。 在例 6-1中,被照物体 是球面,可以看到的永远是其正面,也就是球的外表面,所以背面的光照效果根 本看不到,也就无所谓了。如果球面被切开,其内侧就会被看到,那么你一定希 望里面的光照效果和外面定义的一致, 你也许还需要给内表面贴上一种不同的材 质。起用双侧光照
60、的语句如下:glLightModeli(LIGHT_MODEL_TWO_SIDE, GL_TRUE);OpenGlL把正面顶点的法向量反过来作为背面的法向量。 这样,所有多边形的 光照效果就正确了。关闭双侧光照,只需把前面语句中的GL_TRU换成GL_FALS即可。参阅“定义材质特性”一节以了解如何给双侧设置材质特性。 你还可以通过glFrontFace()命令设置哪个表面被 OpegG以为是正面,参阅“Reversing andCulling Polygon Faces” 一节,那里对该命令会详细解释。 6.4.4 起用光照在 OpenG序你需要显式地起用(或取消)光照计算。如果光照没有被起用,当前 的颜色只是简单地被映
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年杭州市农村信用社联合社秋季校园招聘笔试备考题库(浓缩500题)(含答案详解)
- 2026年蚌埠市农村信用社联合社秋季校园招聘笔试备考题库(浓缩500题)含答案详解(综合卷)
- 2026年六安市农村信用社联合社秋季校园招聘笔试备考题库(浓缩500题)含答案详解(综合题)
- 2026年铜陵市农村信用社联合社秋季校园招聘笔试备考题库(浓缩500题)含答案详解(能力提升)
- 鹤壁市农村信用社联合社秋季校园招聘笔试备考题库(浓缩500题)有完整答案详解
- 2026年嘉兴市农村信用社联合社秋季校园招聘笔试备考题库(浓缩500题)及答案详解(网校专用)
- 通辽市农村信用社联合社秋季校园招聘笔试备考题库(浓缩500题)附答案详解(能力提升)
- 和田地区农村信用社联合社秋季校园招聘笔试备考题库(浓缩500题)及一套答案详解
- 新货物运输合同范本3篇
- 广东省农村信用社联合社秋季校园招聘笔试备考题库(浓缩500题)附答案详解(模拟题)
- 初中英语固定搭配大全
- 中国地面气候标准值数据集台站表(全国2160站点)
- 古诗文默写-中考语文专项复习(湖北专版)(带答案)
- 影视部岗位职责
- 《病理心血管疾病》课件
- 房屋拆迁补偿合同范本
- 分红股东合伙协议书范本
- 北师大版八年级物理上册期中考试及答案【可打印】
- 挖掘铲运和桩工机械司机-国家职业标准(2023年版)
- 2024智能网联汽车自动驾驶功能仿真试验方法及要求
- 第一单元测试 高中日语华东理工版新编日语教程1
评论
0/150
提交评论