490 likes | 703 Views
OpenGL 中的颜色、光照和材质. 简单光照 OpenGL 简单光照光源分为:. 简单光照 OpenGL 简单光照光源分为: 辐射光 (Emitted Light) 是最简单的一种光,它直接从物体发出并且不受任何光源影响。 环境光 (Ambient Light) 是由光源发出经环境多次散射而无法确定其方向的光,即似乎来自所有方向。 漫射光 (Diffuse Light) 来自一个方向,它垂直于物体时比倾斜时更明亮。 镜面光 (Specular Light) 来自特定方向并沿另一方向反射出去。. 向场景中加入光照的步骤如下:.
E N D
简单光照 OpenGL简单光照光源分为: • 简单光照 OpenGL简单光照光源分为: • 辐射光(Emitted Light)是最简单的一种光,它直接从物体发出并且不受任何光源影响。 • 环境光(Ambient Light)是由光源发出经环境多次散射而无法确定其方向的光,即似乎来自所有方向。 • 漫射光(Diffuse Light)来自一个方向,它垂直于物体时比倾斜时更明亮。 • 镜面光(Specular Light)来自特定方向并沿另一方向反射出去。
向场景中加入光照的步骤如下: 1. 定义所有物体每个顶点的法向量方向。这些法向量决定了物体表面与光源的相对取向。2. 建立、选择并放置一个或多个光源。3. 建立并选择一个光照模型,它决定了全局环境光照的程度以及视点的有效位置(用于光照计算)。4. 定义场景中物体的材质。
向场景中加入光照的步骤(函数): 1.为顶点指定法向量:glNormal3fv(n0);glVertex3fv(v0); 不指定就是默认模式。 2.创建光源,指定位置:glLightfv(GL_LIGHT0,GL_POSITION,light_position); glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);注意,GL_POSITION的默认值为(0,0,1,0),它定义了一个指向Z轴负方向的定向光源. 3.选择光照模型:其包括四项内容,即全局环境光强度,观察点靠近场景还是位于无穷远处,对物体的正面和背面是否采用相同的光照计算,以及是否将镜面反射颜色同环境颜色和散射颜色分开,并在纹理操作后应用它.函数有glLightModelfv(GL_LIGHT_MODEL_AMBIENT,lmodel_ambient); glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER,lmodel_viewer)……,其中近视点还是远视点只影响镜面反射区的计算. 4.启用光照:glEnable(GL_LIGHTING);glEnable(GL_LIGHT0); 5.设置材质属性:用glMaterialfv(GLenum face, GLenum pname, Type* param)函数设置GL_AMBIENT, GL_DIFFUSE, GL_AMBIENT_AND_DIFFUSE, GL_SPECULAR, GL_SHINNESS, GL_EMISSION等值.
步骤1:设置光照 基础知识 • 创建光源 光源有许多特性,如颜色、位置、方向等。 • 设置光源特性参数的函数: • void glLight{if}[v]( GLenum light , GLenum pname , TYPE param ) • 参数light指定所创建的光源号,如 GL_LIGHT0 ,GL_LIGHT1 ,GL_LIGHT2 ... ...参数pname指定光源特性参数param设置相应光源特性值
步骤1:设置光照:glLightfv • glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient); //设置场景的环境光。第一个参数表示是对第0号光源GL_LIGHT0进行设置,第二个参数表示要设置的是环境光成分,第三个参数则是一个数组(表示光照属性值) • glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse); //设置在场景照射到粗糙表面时经过漫反射光。第一个参数表示是对第0号光源GL_LIGHT0进行设置,第二个参数表示要设置的是漫反射光成分,第三个参数则是一个数组(表示光照属性值) • glLightfv(GL_LIGHT0,GL_POSITION,light_position); • //设置光源的位置,第三个参数则是一个数组(表示光源的位置值)
定义光照属性值,分别用数组表示: • float lightAmbient[] = { 0.2f, 0.0f, 0.0f, 1.0f };//定义一个数组,表示整个光照环境,有4个值,分别表示光源中含有红、绿、蓝三种光线的成分 ,第四个参数为透明度值,一般也为1。 • float lightDiffuse[] = { 0.5f, 0.0f, 0.0f, 1.0f };//定义数组,用来表示光源的漫反射. • float lightSpecular[] = { 1.0f, 1.0f, 1.0f, 1.0f };////定义数组,用来表示光源的镜面反射
光源知识: • 每一个光源都可以设置其属性,这一动作是通过glLight*函数完成的。 • glLight*函数具有三个参数,第一个参数指明是设置哪一个光源的属性,第二个参数指明是设置该光源的哪一个属性,第三个参数则是指明把该属性值设置成多少。 • 光源的属性众多,下面将分别介绍光源的属性。
(1)GL_AMBIENT、GL_DIFFUSE、GL_SPECULAR属性。 • 这三个属性表示了光源所发出的光的反射特性(以及颜色)。 • 每个属性由四个值表示,分别代表了颜色的R, G, B, A值。 • GL_AMBIENT表示该光源所发出的光,经过非常多次的反射后,最终在整个光照环境中的强度(颜色)。GL_DIFFUSE表示该光源所发出的光,照射到粗糙表面时经过漫反射,所得到的光的强度(颜色)。GL_SPECULAR表示该光源所发出的光,照射到光滑表面时经过镜面反射,所得到的光的强度(颜色)。
(2)GL_POSITION属性。 • 表示光源所在的位置。由四个值(X, Y, Z, W)表示。 • 如果第四个值W为零,则表示该光源位于无限远处,前三个值表示了它所在的方向。这种光源称为方向性光源,通常,太阳可以近似的被认为是方向性光源。 • 如果第四个值W不为零,则X/W, Y/W, Z/W表示了光源的位置。这种光源称为位置性光源。
光源说明1: • 对于位置性光源,设置其位置与设置多边形顶点的方式相似,各种矩阵变换函数例如:glTranslate*、glRotate*等在这里也同样有效。方向性光源在计算时比位置性光源快了不少,因此,在视觉效果允许的情况下,应该尽可能的使用方向性光源。
光源说明2: • 在OpenGL中,仅仅支持有限数量的光源。 • 使用GL_LIGHT0表示第0号光源,GL_LIGHT1表示第1号光源,依次类推,OpenGL至少会支持8个光源,即GL_LIGHT0到GL_LIGHT7。
注:只有 GL_LIGHT0 的 GL_DIFFUSE 和 GL_SPECULAR 的缺省值为 ( 1.0 ,1.0 ,1.0 ,1.0 ) • 其他光源的 GL_DIFFUSE 和 GL_SPECULAR 缺省值均为 ( 0.0 ,0.0 ,0.0 ,1.0 )
步骤2:设置光照模型:函数glLightModel* • 函数glLightModel*有两个参数,第一个表示要设置的属性,第二个参数表示该属性要设置成的值(本例中用数组表示)。 • glLightModelfv(GL_LIGHT_MODEL_AMBIENT,Imodel_ambient); • glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE,Imodel_twoside);
补充:光照模型包括四个部分的内容 • 全局环境光线(即那些充分散射,无法分清究竟来自哪个光源的光线)的强度; • 观察点位置是在较近位置还是在无限远处; • 物体正面与背面是否分别计算光照; • 镜面颜色(即GL_SPECULAR属性所指定的颜色)的计算是否从其它光照计算中分离出来,并在纹理操作以后在进行应用。
光照模型的属性如下: • GL_LIGHT_MODEL_AMBIENT表示全局环境光线强度,由四个值组成。属性GL_LIGHT_MODEL_AMBIENT指定OpenGL场景中的背景光,如果不指定,系统使用低强度的白色(0.2,0.2,0.2,1.0)光。 • GL_LIGHT_MODEL_LOCAL_VIEWER表示是否在近处观看,若是则设置为GL_TRUE,否则(即在无限远处观看)设置为GL_FALSE。 • GL_LIGHT_MODEL_TWO_SIDE表示是否执行双面光照计算。如果设置为GL_TRUE,则OpenGL不仅将根据法线向量计算正面的光照,也会将法线向量反转并计算背面的光照。 • GL_LIGHT_MODEL_COLOR_CONTROL表示颜色计算方式。如果设置为GL_SINGLE_COLOR,表示按通常顺序操作,先计算光照,再计算纹理。如果设置为GL_SEPARATE_SPECULAR_COLOR,表示将GL_SPECULAR属性分离出来,先计算光照的其它部分,待纹理操作完成后再计算GL_SPECULAR。后者通常可以使画面效果更为逼真.
步骤3:启动光源函数: glEnable • 使用glEnable函数可以开启这些光源。 如:glEnable(GL_LIGHT0);可以开启第0号光源。 • 使用glDisable函数则可以关闭光源。 • 注意:一些OpenGL实现可能支持更多数量的光源,但总的来说,开启过多的光源将会导致程序运行速度的严重下降,
启动光源: • glEnable( GL_LIGHTING ); // 启用光照glEnable( GL_LIGHT0 ); // 启用指定光源
步骤四:设置材质属性函数:glMaterialfv • 用glMaterialfv(GLenum face, GLenum pname, Type* param)函数设置. • /*设置前面材质*/ • glMaterialfv(GL_FRONT,GL_DIFFUSE,front_mat_diffuse); • glMaterialfv(GL_FRONT,GL_SPECULAR,front_mat_specular); • glMaterialfv(GL_FRONT,GL_SHININESS,front_mat_shininess); • /*设置后面材质*/ • glMaterialfv(GL_BACK,GL_DIFFUSE,back_mat_diffuse); • glMaterialfv(GL_BACK,GL_SPECULAR,back_mat_specular); • glMaterialfv(GL_BACK,GL_SHININESS,back_mat_shininess);
材质知识点补充: • 材质与光源相似,也需要设置众多的属性。不同的是,光源是通过glLight*函数来设置的,而材质则是通过glMaterial*函数来设置的。
材质函数: • glMaterial*函数有三个参数。 • 第一个参数表示指定哪一面的属性。可以是GL_FRONT、GL_BACK或者GL_FRONT_AND_BACK。分别表示设置“正面”“背面”的材质,或者两面同时设置 • 第二、第三个参数与glLight*函数的第二、三个参数作用类似,表示属性和属性值。 • 下面分别说明glMaterial*函数可以指定的材质属性。
(1)GL_AMBIENT、GL_DIFFUSE、GL_SPECULAR属性。 • 这三个属性与光源的三个对应属性类似,每一属性都由四个值组成。 • GL_AMBIENT表示各种光线照射到该材质上,经过很多次反射后最终遗留在环境中的光线强度(颜色)。 • GL_DIFFUSE表示光线照射到该材质上,经过漫反射后形成的光线强度(颜色)。 • GL_SPECULAR表示光线照射到该材质上,经过镜面反射后形成的光线强度(颜色)。通常,GL_AMBIENT和GL_DIFFUSE都取相同的值,可以达到比较真实的效果。 • 使用GL_AMBIENT_AND_DIFFUSE可以同时设置GL_AMBIENT和GL_DIFFUSE属性。
(2)GL_SHININESS属性。 • 该属性只有一个值,称为“镜面指数”,取值范围是0到128。该值越小,表示材质越粗糙,点光源发射的光线照射到上面,也可以产生较大的亮点。该值越大,表示材质越类似于镜面,光源照射到上面后,产生较小的亮点。
(3)GL_EMISSION属性。 • 该属性由四个值组成,表示一种颜色。OpenGL认为该材质本身就微微的向外发射光线,以至于眼睛感觉到它有这样的颜色,但这光线又比较微弱,以至于不会影响到其它物体的颜色。
(4)GL_COLOR_INDEXES属性。 • 该属性仅在颜色索引模式下使用,由于颜色索引模式下的光照比RGBA模式要复杂,并且使用范围较小,这里不做讨论。
函数: glShadeModel • glShadeModel函数用于控制opengl中绘制指定两点间其他点颜色的过渡模式。 • 参数一般为GL_SMOOTH(默认),GL_FLAT。OpenGL默认是将制定的两点颜色进行插值,绘制之间的其他点。 • 如果两点的颜色相同,使用两个参数效果相同。如果两点颜色不同,GL_SMOOTH会出现过渡效果,GL_FLAT 则只是以指定的某一点的单一色绘制其他所有点。
glDepthFunc函数 • glDepthFunc()来设置深度测试函数 void glDepthFunc(GLenum func) 比较常用的深度测试函数有 GL_LESS 和 GL_LEQUAL 两者的区别在于当深度相同时是显示新的象素 还是老的象素。
注意: • glDepthFunc函数在每次绘制的时候都需要调用下
函数:glMatrixMode • glMatrixMode函数指定哪一个矩阵是当前矩阵void glMatrixMode(GLenum mode) • 参数mode 指定哪一个矩阵堆栈是下一个矩阵操作的目标,可选值: GL_MODELVIEW、GL_PROJECTION、GL_TEXTURE. • 说明glMatrixMode设置当前矩阵模式:GL_MODELVIEW,对模型视景矩阵堆栈应用随后的矩阵操作. GL_PROJECTION,对投影矩阵应用随后的矩阵操作. GL_TEXTURE,对纹理矩阵堆栈应用随后的矩阵操作. • glMatrixMode 与glLoadIdentity()一同使用glLoadIdentity():该函数的功能是重置当前指定的矩阵为单位矩阵。 在glLoadIdentity()之后我们为场景设置了透视图。glMatrixMode(GL_MODELVIEW)设置当前矩阵为模型视图矩阵,模弄视图矩阵储存了有关物体的信。
函数glColorMaterial 表示使用材质色跟踪当前颜色,指定了要改变的材质的属性,然后调用glColor*()去设置这些属性的值。glColor里的参数就是设置的值 • 函数: • void glColorMaterial(GLenum face,GLenum mode) • 参数的取值: face的取值: GL_FRONT 、GL_BACK 、GL_FRONT_AND_BACK mode的取值: GL_AMBIENT、 GL_DIFFUSE GL_AMBIENT_AND_DIFFUSE、 GL_SPECULAR GL_EMISSION
问题: • glColorMaterial需要在glEnable(GL_COLOR_MATERIAL);以后才可以用glColor设置材质,这时候的材质就是glColor*的值,如果没有Enable,那么就不能控制颜色的过渡值,颜色由最初给定的值来确定。
如果去掉这两句: // glColorMaterial(GL_FRONT,GL_AMBIENT); //glEnable(GL_COLOR_MATERIAL);效果如下:三只小球一样的颜色。这种颜色是由这几句语句决定的:glMaterialfv(GL_FRONT,GL_DIFFUSE,material_diffuse); glMaterialfv(GL_FRONT,GL_SPECULAR,material_specular); glMaterialfv(GL_FRONT,GL_SHININESS,high_shininess); glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);
注意: • 注释了// glColorMaterial(GL_FRONT,GL_AMBIENT); //glEnable(GL_COLOR_MATERIAL);语句后,无论怎么改变下面的值,都不能改变小球的颜色。 • GLfloat no_mat[]={0.0,0.0,0.0,1.0}; • GLfloat mat_grey_ambient[]={0.5,0.5,0.5,1.0}; • GLfloat mat_red_ambient[]={0.0,0.0,1.0,1.0};
可以通过以下修改定义颜色的语句来观察小球的颜色变化:可以通过以下修改定义颜色的语句来观察小球的颜色变化: • GLfloat light_position[]={0.0,3.0,6.0,0.0};//定义一行四列的数组 • GLfloat material_diffuse[]={0.8,0.2,0.5,1.0};//其实是控制环境光的颜色(除了高光外) • GLfloat material_specular[]={1.0,1.0,1.0,1.0};//其实是控制高光点的颜色: 如改变这个数组的值: GLfloat material_diffuse[]={0.0,0.0,0.5,1.0}; //其实是控制环境光的颜色(除了高光外)
本例总结: • 当需要改变场景中大部分方面的单个材质时,最好调用glColorMaterial() 。 • 当修改不只一个材质参数,最好调用glMaterial*()。
总结1:概念 • 环境光——经过多次反射而来的光称为环境光,无法确定其最初的方向,但当特定的光源关闭后,它们将消失. • 全局环境光——它们并非来自特定的光源,这些光经过了多次散射,已经无法确定其光源位于何处. • 散射光——来自同一方向,照射到物体表面后,将沿各个方向均匀反射,因此,无论从哪个方向观察,表面的亮度都相同. • 镜面反射光——来自特定方向,也被反射到特定方向.镜面反射度与之相关. • 材质发射光——用于模拟发光物体.在OpenGL光照模型中,表面的发射光增加了物体的亮度,它不受光源的影响,另外,发射光不会给整个场景中增加光线.
总结2: • OpenGL光照模型将光照分为四个独立的部分:环境光,散射光,镜面反射光和发射光,这四种光被分别计算,然后叠加起来. • 光线的R,G,B值表示各分量的强度,材质的R,G,B值表示材质对相应分量的反射比例. • 定向光源不存在三种光线的衰减,但是定位光源存在衰减. • 被照射的物体不会向其它物体发出光线.
总结3:OpenGL光照中的默认值 • 光源的环境光默认为(0.0,0.0,0.0,1.0),即没有环境光. • 光源的散射光默认为(1.0,1.0,1.0,1.0),即存在白色散射光. • 光源的环境反射光默认值有两种情况,一种对应于光源GL_LIGNT0,其GL_SPECULAR为(1.0,1.0,1.0,1.0),即白色光;另一种对应于其它光源,其默认值为(0.0,0.0,0.0,0.0).一般情况下,光源的GL_SPECULAR应该和GL_DIFFUSE值相同. • 默认情况下,定位光源向所有方向发射光,但可以将其设置为聚光灯,使之在锥体内发光. • 光照模型中,全局环境光默认为(0.2,0.2,0.2,1.0),即存在微弱的白光;视点位置默认为0.0或者GL_FALSE,即无穷远处;默认采用单面光照,即GL_LIGHT_MODEL_TWO_SIDE为0.0或GL_FALSE(在对物体存在切割时,要启用双面光照);默认情况下,镜面反射颜色在纹理映射之前完成,即GL_LIGHT_MODEL_COLOR_CONTROL的值为GL_SINGLE_COLOR. • 材质属性的默认值:GL_AMBIENT (0.2,0.2,0.2,1.0); GL_DIFFUSE (0.8,0.8,0.8,1.0); GL_SPECULAR (0.0,0.0,0.0,1.0); GL_SHINNESS 0.0; GL_EMISSION (0.0,0.0,0.0,1.0).
gluLookAt()函数:定义了视点矩阵 • void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble centery,GLdouble centerz,GLdouble upx,GLdouble upy,GLdouble upz); • gluLookAt()共有九个参数,分别是眼睛的位置,眼睛朝向的位置,以及相片朝上的方向。 • 这个函数是对模型矩阵进行变换(GL_MODELVIEW),而gluPerspective函数是对投影矩阵进行变换(GL_PROJECTION)。 可以用gluPerspective函数设置近平面、远平面