OpenGL笔记7

  今天要讲的是OpenGL光照的基本知识。虽然内容显得有点多,但条理还算比较清晰,理解起来应该没有困难。即使对于一些内容没有记住,问题也不大——光照部分是一个比较独立的内容,它的学习与其它方面的学习可以分开,不像视图变换那样,影响到许多方面。课程的最后给出了一个有关光照效果的动画演示程序,我想大家会喜欢的。
  从生理学的角度上讲,眼睛之所以看见各种物体,是因为光线直接或间接的从它们那里到达了眼睛。人类对于光线强弱的变化的反应,比对于颜色变化的反应来得灵敏。因此对于人类而言,光线很大程度上表现了物体的立体感。
  请看图1,图中绘制了两个大小相同的白色球体。其中右边的一个是没有使用任何光照效果的,它看起来就像是一个二维的圆盘,没有立体的感觉。左边的一个是使用了简单的光照效果的,我们通过光照的层次,很容易的认为它是一个三维的物体。

图1

OpenGL对于光照效果提供了直接的支持,只需要调用某些函数,便可以实现简单的光照效果。但是在这之前,我们有必要了解一些基础知识。
一、建立光照模型
在现实生活中,某些物体本身就会发光,例如太阳、电灯等,而其它物体虽然不会发光,但可以反射来自其它物体的光。这些光通过各种方式传播,最后进入我们的眼睛——于是一幅画面就在我们的眼中形成了。

目前的计算机而言,要准确模拟各种光线的传播,这是无法做到的事情。比如一个四面都是粗糙墙壁的房间,一盏电灯所发出的光线在很短的时间内就会经过非常多
次的反射,最终几乎布满了房间的每一个角落,这一过程即使使用目前运算速度最快的计算机,也无法精确模拟。不过,我们并不需要精确的模拟各种光线,只需要
找到一种近似的计算方式,使它的最终结果让我们的眼睛认为它是真实的,这就可以了。
OpenGL在处理光照时采用这样一种近似:把光照系统分为三
部分,分别是光源、材质和光照环境。光源就是光的来源,可以是前面所说的太阳或者电灯等。材质是指接受光照的各种物体的表面,由于物体如何反射光线只由物
体表面决定(OpenGL中没有考虑光的折射),材质特点就决定了物体反射光线的特点。光照环境是指一些额外的参数,它们将影响最终的光照画面,比如一些
光线经过多次反射后,已经无法分清它究竟是由哪个光源发出,这时,指定一个“环境亮度”参数,可以使最后形成的画面更接近于真实情况。
在物理学
中,光线如果射入理想的光滑平面,则反射后的光线是很规则的(这样的反射称为镜面反射)。光线如果射入粗糙的、不光滑的平面,则反射后的光线是杂乱的(这
样的反射称为漫反射)。现实生活中的物体在反射光线时,并不是绝对的镜面反射或漫反射,但可以看成是这两种反射的叠加。对于光源发出的光线,可以分别设置
其经过镜面反射和漫反射后的光线强度。对于被光线照射的材质,也可以分别设置光线经过镜面反射和漫反射后的光线强度。这些因素综合起来,就形成了最终的光
照效果。

二、法线向量
根据光的反射定律,由光的入射方向和入射点的法线就可以得到光的出射方向。因此,对于指定的物体,在指定了光源后,即可计算出光的反射方向,进而计算出光照效果的画面。在OpenGL中,法线的方向是用一个向量来表示。
不幸的是,OpenGL并不会根据你所指定的多边形各个顶点来计算出这些多边形所构成的物体的表面的每个点的法线(这话听着有些迷糊),通常,为了实现光照效果,需要在代码中为每一个顶点指定其法线向量。

定法线向量的方式与指定颜色的方式有雷同之处。在指定颜色时,只需要指定每一个顶点的颜色,OpenGL就可以自行计算顶点之间的其它点的颜色。并且,颜
色一旦被指定,除非再指定新的颜色,否则以后指定的所有顶点都将以这一向量作为自己的颜色。在指定法线向量时,只需要指定每一个顶点的法线向
量,OpenGL会自行计算顶点之间的其它点的法线向量。并且,法线向量一旦被指定,除非再指定新的法线向量,否则以后指定的所有顶点都将以这一向量作为
自己的法线向量。使用glColor*函数可以指定颜色,而使用glNormal*函数则可以指定法线向量。
注意:使用glTranslate*
函数或者glRotate*函数可以改变物体的外观,但法线向量并不会随之改变。然而,使用glScale*函数,对每一坐标轴进行不同程度的缩放,很有
可能导致法线向量的不正确,虽然OpenGL提供了一些措施来修正这一问题,但由此也带来了各种开销。因此,在使用了法线向量的场合,应尽量避免使用
glScale*函数。即使使用,也最好保证各坐标轴进行等比例缩放。
三、控制光源

OpenGL中,仅仅支持有限数量的光源。使用GL_LIGHT0表示第0号光源,GL_LIGHT1表示第1号光源,依次类推,OpenGL至少会支持
8个光源,即GL_LIGHT0到GL_LIGHT7。使用glEnable函数可以开启它们。例如,glEnable(GL_LIGHT0);可以开启
第0号光源。使用glDisable函数则可以关闭光源。一些OpenGL实现可能支持更多数量的光源,但总的来说,开启过多的光源将会导致程序运行速度
的严重下降,玩过3D
Mark的朋友可能多少也有些体会。一些场景中可能有成百上千的电灯,这时可能需要采取一些近似的手段来进行编程,否则以目前的计算机而言,是无法运行这
样的程序的。
每一个光源都可以设置其属性,这一动作是通过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表示了光源的位置。这种光源称为位置性光源。对于位置性光源,设置其位置与设置多边形顶点的方式相似,各种矩阵变换函数例
如:glTranslate*、glRotate*等在这里也同样有效。方向性光源在计算时比位置性光源快了不少,因此,在视觉效果允许的情况下,应该尽
可能的使用方向性光源。
(3)GL_SPOT_DIRECTION、GL_SPOT_EXPONENT、GL_SPOT_CUTOFF属性。表示
将光源作为聚光灯使用(这些属性只对位置性光源有效)。很多光源都是向四面八方发射光线,但有时候一些光源则是只向某个方向发射,比如手电筒,只向一个较
小的角度发射光线。GL_SPOT_DIRECTION属性有三个值,表示一个向量,即光源发射的方向。GL_SPOT_EXPONENT属性只有一个
值,表示聚光的程度,为零时表示光照范围内向各方向发射的光线强度相同,为正数时表示光照向中央集中,正对发射方向的位置受到更多光照,其它位置受到较少
光照。数值越大,聚光效果就越明显。GL_SPOT_CUTOFF属性也只有一个值,表示一个角度,它是光源发射光线所覆盖角度的一半(见图2),其取值
范围在0到90之间,也可以取180这个特殊值。取值为180时表示光源发射光线覆盖360度,即不使用聚光灯,向全周围发射。

图2

(4)GL_CONSTANT_ATTENUATION、
GL_LINEAR_ATTENUATION、GL_QUADRATIC_ATTENUATION属性。这三个属性表示了光源所发出的光线的直线传播特性
(这些属性只对位置性光源有效)。现实生活中,光线的强度随着距离的增加而减弱,OpenGL把这个减弱的趋势抽象成函数:
衰减因子 = 1 / (k1 + k2 * d + k3 * k3 * d)

中d表示距离,光线的初始强度乘以衰减因子,就得到对应距离的光线强度。k1, k2, k3分别就是GL_CONSTANT_ATTENUATION,
GL_LINEAR_ATTENUATION,
GL_QUADRATIC_ATTENUATION。通过设置这三个常数,就可以控制光线在传播过程中的减弱趋势。

属性还真是不少。当然了,如果是使用方向性光源,(3)(4)这两类属性就不会用到了,问题就变得简单明了。
四、控制材质
材质与光源相似,也需要设置众多的属性。不同的是,光源是通过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模式要复杂,并且使用范围较小,这里不做讨论。
五、选择光照模型

里所说的“光照模型”是OpenGL的术语,它相当于我们在前面提到的“光照环境”。在OpenGL中,光照模型包括四个部分的内容:全局环境光线(即那
些充分散射,无法分清究竟来自哪个光源的光线)的强度、观察点位置是在较近位置还是在无限远处、物体正面与背面是否分别计算光照、镜面颜色(即
GL_SPECULAR属性所指定的颜色)的计算是否从其它光照计算中分离出来,并在纹理操作以后在进行应用。
以上四方面的内容都通过同一个函数glLightModel*来进行设置。该函数有两个参数,第一个表示要设置的项目,第二个参数表示要设置成的值。
GL_LIGHT_MODEL_AMBIENT表示全局环境光线强度,由四个值组成。
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。后者通常可以使画面效果更为逼真(当然,如果本身就没有执行任何纹理操作,这样的分离就没有任何意义)。

六、最后的准备
到现在可以说是完事俱备了。不过,OpenGL默认是关闭光照处理的。要打开光照处理功能,使用下面的语句:
glEnable(GL_LIGHTING);
要关闭光照处理功能,使用glDisable(GL_LIGHTING);即可。
七、示例程序
到现在,我们已经可以编写简单的使用光照的OpenGL程序了。

们仍然以太阳、地球作为例子(这次就不考虑月亮了^-^),把太阳作为光源,模拟地球围绕太阳转动时光照的变化。于是,需要设置一个光源——太阳,设置两
种材质——太阳的材质和地球的材质。把太阳光线设置为白色,位置在画面正中。把太阳的材质设置为微微散发出红色的光芒,把地球的材质设置为微微散发出暗淡
的蓝色光芒,并且反射蓝色的光芒,镜面指数设置成一个比较小的值。简单起见,不再考虑太阳和地球的大小关系,用同样大小的球体来代替之。
关于法线向量。球体表面任何一点的法线向量,就是球心到该点的向量。如果使用glutSolidSphere函数来绘制球体,则该函数会自动的指定这些法线向量,不必再手工指出。如果是自己指定若干的顶点来绘制一个球体,则需要自己指定法线响亮。
由于我们使用的太阳是一个位置性光源,在设置它的位置时,需要利用到矩阵变换。因此,在设置光源的位置以前,需要先设置好各种矩阵。利用gluPerspective函数来创建具有透视效果的视图。我们也将利用前面课程所学习的动画知识,让整个画面动起来。

下面给出具体的代码:
#include <gl/glut.h>

#define WIDTH 400
#define HEIGHT 400

static GLfloat angle = 0.0f;

void myDisplay(void)
{
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// 创建透视效果视图
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
     gluPerspective(90.0f, 1.0f, 1.0f, 20.0f);
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     gluLookAt(0.0, 5.0, -10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

// 定义太阳光源,它是一种白色的光源
     {
     GLfloat sun_light_position[] = {0.0f, 0.0f, 0.0f, 1.0f};
     GLfloat sun_light_ambient[]   = {0.0f, 0.0f, 0.0f, 1.0f};
     GLfloat sun_light_diffuse[]   = {1.0f, 1.0f, 1.0f, 1.0f};
     GLfloat sun_light_specular[] = {1.0f, 1.0f, 1.0f, 1.0f};

glLightfv(GL_LIGHT0, GL_POSITION, sun_light_position);
     glLightfv(GL_LIGHT0, GL_AMBIENT,   sun_light_ambient);
     glLightfv(GL_LIGHT0, GL_DIFFUSE,   sun_light_diffuse);
     glLightfv(GL_LIGHT0, GL_SPECULAR, sun_light_specular);

glEnable(GL_LIGHT0);
     glEnable(GL_LIGHTING);
     glEnable(GL_DEPTH_TEST);
     }

// 定义太阳的材质并绘制太阳
     {
         GLfloat sun_mat_ambient[]   = {0.0f, 0.0f, 0.0f, 1.0f};
         GLfloat sun_mat_diffuse[]   = {0.0f, 0.0f, 0.0f, 1.0f};
         GLfloat sun_mat_specular[] = {0.0f, 0.0f, 0.0f, 1.0f};
         GLfloat sun_mat_emission[] = {0.5f, 0.0f, 0.0f, 1.0f};
         GLfloat sun_mat_shininess   = 0.0f;

glMaterialfv(GL_FRONT, GL_AMBIENT,    sun_mat_ambient);
         glMaterialfv(GL_FRONT, GL_DIFFUSE,    sun_mat_diffuse);
         glMaterialfv(GL_FRONT, GL_SPECULAR,   sun_mat_specular);
         glMaterialfv(GL_FRONT, GL_EMISSION,   sun_mat_emission);
         glMaterialf (GL_FRONT, GL_SHININESS, sun_mat_shininess);

glutSolidSphere(2.0, 40, 32);
     }

// 定义地球的材质并绘制地球
     {
         GLfloat earth_mat_ambient[]   = {0.0f, 0.0f, 0.5f, 1.0f};
         GLfloat earth_mat_diffuse[]   = {0.0f, 0.0f, 0.5f, 1.0f};
         GLfloat earth_mat_specular[] = {0.0f, 0.0f, 1.0f, 1.0f};
         GLfloat earth_mat_emission[] = {0.0f, 0.0f, 0.0f, 1.0f};
         GLfloat earth_mat_shininess   = 30.0f;

glMaterialfv(GL_FRONT, GL_AMBIENT,    earth_mat_ambient);
         glMaterialfv(GL_FRONT, GL_DIFFUSE,    earth_mat_diffuse);
         glMaterialfv(GL_FRONT, GL_SPECULAR,   earth_mat_specular);
         glMaterialfv(GL_FRONT, GL_EMISSION,   earth_mat_emission);
         glMaterialf (GL_FRONT, GL_SHININESS, earth_mat_shininess);

glRotatef(angle, 0.0f, -1.0f, 0.0f);
         glTranslatef(5.0f, 0.0f, 0.0f);
         glutSolidSphere(2.0, 40, 32);
     }

glutSwapBuffers();
}
void myIdle(void)
{
     angle += 1.0f;
     if( angle >= 360.0f )
         angle = 0.0f;
     myDisplay();
}

int main(int argc, char* argv[])
{
     glutInit(&argc, argv);
     glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
     glutInitWindowPosition(200, 200);
     glutInitWindowSize(WIDTH, HEIGHT);
     glutCreateWindow("OpenGL光照演示");
     glutDisplayFunc(&myDisplay);
     glutIdleFunc(&myIdle);
     glutMainLoop();
     return 0;
}
小结:
本课介绍了OpenGL光照的基本知识。OpenGL把光照分解为光源、材质、光照模式三个部分,根据这三个部分的各种信息,以及物体表面的法线向量,可以计算得到最终的光照效果。
光源、材质和光照模式都有各自的属性,尽管属性种类繁多,但这些属性都只用很少的几个函数来设置。使用glLight*函数可设置光源的属性,使用glMaterial*函数可设置材质的属性,使用glLightModel*函数可设置光照模式。
GL_AMBIENT、GL_DIFFUSE、GL_SPECULAR这三种属性是光源和材质所共有的,如果某光源发出的光线照射到某材质的表面,则最终的漫反射强度由两个GL_DIFFUSE属性共同决定,最终的镜面反射强度由两个GL_SPECULAR属性共同决定。
可以使用多个光源来实现各种逼真的效果,然而,光源数量的增加将造成程序运行速度的明显下降。

使用OpenGL光照过程中,属性的种类和数量都非常繁多,通常,需要很多的经验才可以熟练的设置各种属性,从而形成逼真的光照效果。(各位也看到了,其
实这个课程的示例程序中,属性设置也不怎么好)。然而,设置这些属性的艺术性远远超过了技术性,往往是一些美术制作人员设置好各种属性(并保存为文件),
然后由程序员编写的程序去执行绘制工作。因此,即使目前无法熟练运用各种属性,也不必过于担心。如果条件允许,可以玩玩类似3DS
MAX之类的软件,对理解光照、熟悉各种属性设置会有一些帮助。
在课程的最后,我们给出了一个样例程序,演示了太阳和地球模型中的光照效果。

时间: 2024-08-03 21:24:39

OpenGL笔记7的相关文章

OpenGL笔记12

OpenGL入门学习[十二] 片断测试其实就是测试每一个像素,只有通过测试的像素才会被绘制,没有通过测试的像素则不进行绘制.OpenGL提供了多种测试操作,利用这些操作可以实现一些特殊的效果.我们在前面的课程中,曾经提到了“深度测试”的概念,它在绘制三维场景的时候特别有用.在不使用深度测试的时候,如果我们先绘制一个距离较近的物体,再绘制距离较远的物体,则距离远的物体因为后绘制,会把距离近的物体覆盖掉,这样的效果并不是我们所希望的.如 果使用了深度测试,则情况就会有所不同:每当一个像素被绘制,Op

OpenGL笔记2.1 角的顶点vertex

本次课程所要讲的是绘制简单的几何图形,在实际绘制之前,让我们先熟悉一些概念.向量:http://zh.wikipedia.org/wiki/%E7%9F%A2%E9%87%8F 一.点.直线和多边形我们知道数学(具体的说,是几何学)中有点.直线和多边形的概念,但这些概念在计算机中会有所不同. 数学上的点,只有位置,没有大小.但在计算机中,无论计算精度如何提高,始终不能表示一个无穷小的点.另一方面,无论图形输出设备(例如,显示器)如何精 确,始终不能输出一个无穷小的点.一般情况下,OpenGL中的

opengl 笔记(一)

参考<opengl入门教程>.<OpenGL之坐标转换>.<OpenGL绘制管线操作细节>等资料. 复习下留个备忘:) /*- * Opengl Demo Test * * Fredric : 2016-7-8 */ #include <GLUT/GLUT.h> void display_demo01(); void display_demo02(); void display_demo03(); void display_demo04(); /* * Ma

OpenGL笔记10

今天我们先简单介绍Windows中常用的BMP文件格式,然后讲OpenGL的像素操作.虽然看起来内容可能有点多,但实际只有少量几个知识点,如果读者对诸如“显示BMP图象”等内容比较感兴趣的话,可能不知不觉就看完了. 像素操作可以很复杂,这里仅涉及了简单的部分,让大家对OpenGL像素操作有初步的印象. 学过多媒体技术的朋友可能知道,计算机保存图象的方法通常有两种:一是“矢量图”,一是“像素图”.矢量图保存了图象中每一几何物体的位置.形状.大小等信 息,在显示图象时,根据这些信息计算得到完整的图象

OpenGL笔记2.2 镂空

在第二课中,我们学习了如何绘制几何图形,但大家如果多写几个程序,就会发现其实还是有些郁闷之处.例如:点太小,难以看清楚:直线也太细,不舒服:或者想画虚线,但不知道方法只能用许多短直线,甚至用点组合而成. 这些问题将在本课中被解决. 下面就点.直线.多边形分别讨论. 1.关于点 点的大小默认为1个像素,但也可以改变之.改变的命令为glPointSize,其函数原型如下: void glPointSize(GLfloat size); size必须大于0.0f,默认值为1.0f,单位为“像素”. 注

OpenGl笔记 12.1 stencil 模版 缓冲区

在OpenGL中存在着多种缓冲区,这些缓冲区大致分为: 深度缓冲区:存储每个像素的深度值,当启动深度测试时,片段像素深度值和深度缓冲区深度值进行比较,决定片段哪些像素点数据可以替换到颜色缓冲区中. 模板缓冲区(Stencil Buffer):与颜色缓冲区和深度缓冲区类似,模板缓冲区可以为屏幕上的每个像素点保存一个无符号整数值.这个值的具体意义视程序的具体应用而定.在渲染的过程中,可以用这个值与一个预先设定的参考值相比较,根据比较的结果来决定是否更新相应的像素点的颜色值.这个比较的过程被称为模板测

OpenGL笔记15 顶点数据

这次讲的所有内容都装在一个立方体中,呵呵.呵呵,绘制一个立方体,简单呀,我们学了第一课第二课,早就会了.先别着急,立方体是很简单,但是这里只是拿立方体做一个例子,来说明OpenGL在绘制方法上的改进.从原始一点的办法开始一个立方体有六个面,每个面是一个正方形,好,绘制六个正方形就可以了. glBegin(GL_QUADS);     glVertex3f(...);     glVertex3f(...);     glVertex3f(...);     glVertex3f(...); //

OpenGL笔记11

我们在前一课中,学习了简单的像素操作,这意味着我们可以使用各种各样的BMP文件来丰富程序的显示效果,于是我们的OpenGL图形程序也不再像以前总是 只显示几个多边形那样单调了.——但是这还不够.虽然我们可以将像素数据按照矩形进行缩小和放大,但是还不足以满足我们的要求.例如要将一幅世界地图绘制 到一个球体表面,只使用glPixelZoom这样的函数来进行缩放显然是不够的.OpenGL纹理映射功能支持将一些像素数据经过变换(即使是比较不规 则的变换)将其附着到各种形状的多边形表面.纹理映射功能十分强

OpenGL笔记9

今天介绍关于OpenGL混合的基本知识.混合是一种常用的技巧,通常可以用来实现半透明.但其实它也是十分灵活的,你可以通过不同的设置得到不同的混合结果,产生一些有趣或者奇怪的图象.混合是什么呢?混合就是把两种颜色混在一起.具体一点,就是把某一像素位置原来的颜色和将要画上去的颜色,通过某种方式混在一起,从而实现特殊的效果.假设我们需要绘制这样一个场景:透过红色的玻璃去看绿色的物体,那么可以先绘制绿色的物体,再绘制红色玻璃.在绘制红色玻璃的时候,利用“混合”功能,把将要绘制上去的红色和原来的绿色进行混

OpenGL笔记13

前一段时间里,论坛有位朋友问什么是状态机.按我的理解,状态机就是一种存在于理论中的机器,它具有以下的特点: 1. 它有记忆的能力,能够记住自己当前的状态. 2. 它可以接收输入,根据输入的内容和自己的状态,修改自己的状态,并且可以得到输出. 3. 当它进入某个特殊的状态(停机状态)的时候,它不再接收输入,停止工作. 理论说起来很抽象,但实际上是很好理解的. 首先,从本质上讲,我们现在的电脑就是典型的状态机.可以对照理解: 1. 电脑的存储器(内存.硬盘等等),可以记住电脑自己当前的状态(当前安装