该段代码添加了两个不同颜色的光源,可以看到两个光源在景物表面形成了两个高光区。
以上我们完成了Lambert漫反射光照模型和Phong局部光照模型的实现。读者可以修改景物表面的光照属性和光源属性来了解其对光照效果的影响。我们这里就不更多的举例了。同时需要说明的是,在进行光照计算之前,实际上应该对景物表面三角剖分得到的三角面片进行消隐,其消隐算法可以采用前面所介绍的各种线面消隐算法。本章的重点在于光照模型的介绍,所以示例时只添加了一个球体景物,对于这一个球体景物只需进行背向视线面的消隐即可。如果读者想要在场景中加入更多的景物,就需要在进行光照计算之前首先进行消隐。消隐的实现读者可以参照前面章节的介绍。
9.3 色彩模型
前面我们实现Lambert漫反射光照模型和Phong局部光照模型时,已经对光照中的色彩进行了处理。在现实生活中,我们看到的绝大多数景物都是具有各种各样的色彩的,为了达到更好的真实效果,对色彩的处理是必不可少的。现在我们对真实感图形中色彩的处理作简要的介绍。
物体的颜色不仅取决于物体本身,它与光源、周围景物的颜色,以及观察者的视觉系统都有关系。例如,当一个只反射纯绿色的表面用纯红色照明时,该表面呈黑色,而从一块只透蓝光的表面后面观察一道红光,该红光也是呈黑色。从视觉的角度,颜色包含三个要素:色彩、饱和度和亮度。所谓色彩,就是我们通常所说的红、绿、蓝、黄等,是使一种颜色区别于另一种颜色的要素。饱和度就是颜色的纯度。在某种颜色中添加白色相当于减少该颜色的饱和度。例如,鲜红色的饱和度高,而粉红色的饱和度低。亮度即光的强度。
我们可以通过对光源发出的光作光谱分析和分析景物表面对不同波长的光的反射率来计算景物在光源照射下的色彩。光谱分析法可以准确的模拟景物在光照下的色彩,但是光谱采样和光谱至颜色的转换十分复杂,计算量相当大,而在多数应用场合中,并不需要如此精确的模拟,因而需要采用一些简单的计算方法。
在真实感图形中,通常采用某种颜色模型来模拟景物在光照下的色彩。所谓颜色模型指的是某个三维颜色空间的一个可见光子集,它包含某个颜色域的所有颜色。常见的颜色模型有RGB颜色模型、CMY颜色模型、HSV颜色模型和HSL颜色模型等。
RGB颜色模型是三维直角坐标颜色系统中的一个单位正方体。红、绿、蓝三原色是叠加性原色,即通过将不同程度的三种原色叠加在一起产生复合色(如图9.9(a)所示)。
RGB颜色模型通常可用一个单位立方体来表示(如图9.10所示)。在RGB立方体中各点坐标用(x,y,z) (0?x,y,z?1)来表示,x、y、z分别为红、绿、蓝三原色在该点色彩中所占分量的大小。在正方体的主对角线上,各原色的量相等,产生由暗到亮的白色,即灰度。(0,0,0)中不含三原色,所以为黑色,而在(1,1,1)中三种原色含量均为最大,所以是白色。调整x、y、在计算机中用于产生色彩的RGB函数的原理与z的大小就可以得到不同的色彩。RGB立方体相同:
色彩值=RGB(r,g,b)(0?r,g,b?25)
其中,r、g、b分别代表红、绿、蓝三原色在色彩中含量的大小。
在真实感图形中,可以假定入射光仅由红、绿、蓝三种不同波长的光组成,这样,在光照模型中,仅需考虑景物表面对这三种不同波长光的反射和透射,从而大大简化了光亮度的计算。我们前面实现局部光照模型时就采用了RGB颜色模型。
比如,在采用Phong局部光照模型计算给定的景物表面上每一可见点处的光亮度时,分别对红、绿、蓝三色作光亮度计算。此时,采用下面的方程来进行计算:
I(t)?Ia(t)?ka(t)?i?1?MfiIli(t)[kd(t)(N?Li)?ks(N?Hi)n]
其中,t?r,g,b分别表示光源入射光强和景物表面漫反射率的三基色分量。通过上式计算出反射光中三原色分量的大小后,就可以通过RGB函数显示景物在光照下的色彩。
CMY颜色模型与RGB颜色模型类似,只是其三原色与RGB模型的三原色不同。CMY颜色模型的三原色叠加效果如图9.9(b)所示,颜色立方体如图9.10所示。RGB颜色模型适用于发光体,而CMY颜色模型适用于彩色印刷、胶卷等非发光显示体。
RGB颜色模型和CMY颜色模型是面向硬件的,而HSV(Hue, Staturation, Value)颜色模型是面向用户的。HSV颜色模型对应于三维空间中的一个圆锥体,如图
9.11所示。
圆锥的顶面对应于V=1,包含着具有最大亮度值的各种颜色。色彩H由绕V轴的旋转角给定,红色对应于角度0度,绿色对应于角度120度,蓝色对应于角度240度。在HSV颜色模型中,每一种颜色和它的补色相差180度。饱和度S取值从0到1,由圆心向圆周过渡。在圆锥的顶点处,V=0,H和S无定义,代表黑色,圆锥顶面中心处S=0,V=1,H无定义,代表白色,从该点到原点代表亮度渐暗的白色,即不同灰度的白色。任何V=1,S=1的颜色都是纯色。
HSV颜色模型可以推广为HSL颜色模型,该模型对应的是三维空间中的一个双圆锥体,如图9.12所示。亮度值沿轴线方向逐渐变化,对应黑色的顶点处L=0,而白色的顶点处L=1。与HSV颜色模型一样,任何一个色彩的互补色都位于绕该圆锥轴再往前转过180度的位置上。同时,从该竖直轴线开始,可以辐射状地度
量饱和度,取值范围为从轴线上的0到表面上的1。
RGB颜色模型和HSV颜色模型及HSL颜色模型之间可以进行相互转换。在CReality类中添加如下的成员函数:
public:
//RGB颜色模型转换为HSV颜色模型
void RGBtoHSV(double r, double g, double b,
double *h, double *s, double *v);
//HSV颜色模型转换为RGB颜色模型
BOOL HSVtoRGB(double h, double s, double v,
double *r, double *g, double *b);
//RGB颜色模型转换为HSL颜色模型
void RGBtoHSL(double r, double g, double b,
double *h, double *s, double *L);
//HSL颜色模型转换为RGB颜色模型
BOOL HSLtoRGB(double h, double s, double L,
double *r, double *g, double *b);
double Max(double a, double b, double c);//返回传入参数的最大值 double Min(double a, double b, double c);//返回传入参数的最小值 //根据传入的参数值计算RGB分量
double RGBValue(double m, double n, double hue);
其中函数RGBtoHSV、HSVtoRGB、RGBtoHSL、HSLtoRGB用于完成颜色模型之间的转换,传入的参数r,g,b为RGB颜色模型中的红、绿、蓝三原色分量,对应于RGB颜色立方体,其取值范围为[0, 1]。参数h,s,v为HSV颜色模型中的色彩,饱和度,亮度,其中h取值范围为[0, 360],s和v的取值范围为[0, 1]。参数h,s,L为HSL颜色模型中的色彩,饱和度,亮度,其中h取值范围为[0, 360],s和L的取值范围为[0, 1]。函数Max和Min分别用于获得传入参数的最大值和最小值。函数RGBValue在函数HSLtoRGB中调用,用于根据传入的参数值计算RGB分量。函数实现代码如下:
//返回传入参数的最大值
double CReality::Max(double a, double b, double c) {
if (a >= b && a >= c) return a;
else if (b >= a && b >= c) return b; else return c; }
//返回传入参数的最小值
double CReality::Min(double a, double b, double c) {
if (a <= b && a <= c) return a;