5.3 基本计算机颜色

计算机显示器通过每个像素发射红、绿、蓝光的混合光线。当混合光线进入人的眼睛时会触碰到视网膜的某些区域,对锥感细胞产生刺激,神经触突会通过视觉神经传送到大脑。大脑会解释些信号并生成颜色。随着混合光线的变化,细胞会受到不同的刺激,从而在我们的思想意识中产生不同的颜色。图5.8说明了红、绿、蓝三色的混合方式以及不同强度的红色。通过为每个颜色分量指定不同的强度并对其进行混合,可以描述我们所要显示的真实图像中的所有颜色。

图5.8
图5.8 (上)对纯红、纯绿、纯蓝三种颜色进行混合,得到新的颜色。(下)通过控制红光的强度得到不同明暗程度的红色。

读者可以使用绘图软件(比如Adobe Photoshop)或Win32颜色对话框(图5.9)进一步了解如何使用RGB(red、green、blue)值来描述颜色。尝试使用不同的RGB组合,看一看它们产生的颜色。

图5.9
图5.9 颜色对话框。

显示器所能发射的红、绿、蓝光的强度有最大限制。我们使用从0到1的规范化区间来描述光线强度。0表示没有强度,1表示最高强度。中间值表示中等强度。例如,值(0.25,0.67,1.0)表示混合光由强度为25%的红光、强度为67%的绿和强度为100%的蓝光组成。如本例所示,我们可以通过3D向量(r,g,b)来表示颜色,其中0≤r,g,b≤1,三个颜色分量分别描述红、绿、蓝光的强度。

5.3.1 颜色运算

某些向量运算也适用于颜色向量。例如,我们可以把颜色向量加在一起得到一个新的颜色:

(0.0, 0.5, 0.0) + (0.0, 0.0, 0.25) = (0.0, 0.5, 0.25)

通过混合一个中等强度的绿色和一个低强度的蓝色,得到一个深绿色。也可以通过颜色相减来得到一个新的颜色:

(1, 1,1) − (1, 1,0) = (0, 0,1)

也就是,我们从白色中减去它的红色和绿色部分,得到最终的蓝色。

标量乘法也有意义。例如:

0.5(1, 1,1) = (0.5, 0.5, 0.5)

也就是,将白色乘以0.5,得到一个中等强度的灰色。而运算2(0.25, 0.0, 0.0) = (0.5, 0.0, 0.0),可使红色分量的强度增大一倍。

颜色向量的点积和叉积没有意义。不过,颜色向量有一种特殊的乘法运算,叫做分量乘法(componentwise multiplication)。其定义如下:

(cr,cg,cb)⨂(kr,kg,kb) = (crkr,cgkg,cbkb)

这一运算主要用于光照方程。例如,一个颜色为(r,g,b)的入射光,照射在一个平面上。该平面反射50%的红光、75%的绿和25%的蓝光,其余线均被平面吸收。则折回的反射光颜色为:

(r,g,b)⨂(0.5,0.75,0.25) = (0.5r,0.75g,0.25b)

我们可以看到,由于平面吸收了一些线,所以当光线照射在平面上时会丢失一些颜色。

当进行颜色运算时,某些颜色分量可能会超出[0,1]区间;例如,方程(1,0.1,0.6) + (0.0,0.3,0.5) = (1,0.4,1.1)。由于1.0表示颜色分量的最大强度,任何分量都不能大于该值。所以,我们要把1.1截取为1.0。同样,显示器不能发射负光,所以任何负的颜色分量(负值是由减法运算取得的结果)都必须截取为0.0。

5.3.2 128位颜色

通常,在颜色中会包含一个附加的颜色分量,叫做alpha分量。alpha分量用于表示颜色的不透明度,我们会在第9章“混合”中使用alpha分量。(由于我们目前还用不到混合,所以现在暂且将alpha分量设置为1。)

包含alpha分量意味着我们要使用4D向量(r,g,b,a)来表示颜色,其中0≤r,g,b,a≤1。要表示一个128位颜色,可以为每个分量指定一个浮点值。因为从数学上来说,颜色就是一个4D向量,所以我们可以在代码中使用XMVECTOR类型表示一个颜色,而且还可以利用XNA数学矢量函数所用的SIMD操作带来的优势进行颜色运算(例如颜色相加、相减、标量乘法)。对于分量乘法,XNA数学库提供了以下方法:

XMVECTOR XMColorModulate(// Returns (cr, cg, cb, ca) ⊗ (kr,kg,kb,ka)
    FXMVECTOR C1, // (cr, cg, cb, ca)
    FXMVECTOR C2 // (kr, kg, kb, ka) 
);

5.3.3 32位颜色

当使用32位表示一个颜色时,每个字节会对应于一个颜色分量。由于每个颜色分量占用一个8位字节,所以每个颜色分量可以表示256种不同的明暗强度——0表示没有强度,255表示最高强度,中间值表示中等强度。从表面上看,为每个颜色分量分配一个字节似乎很小,但是通过计算组合值(256×256×256 = 16,777,216)可以发现,这种方式可以表示上千万种不同的颜色。XNA数学库提供了以下结构用于存储32位颜色:

// ARGB Color; 8-8-8-8 bit unsigned normalized integer components packed into
// a 32 bit integer.  The normalized color is packed into 32 bits using 8 bit
// unsigned, normalized integers for the alpha, red, green, and blue components.
// The alpha component is stored in the most significant bits and the blue
// component in the least significant bits (A8R8G8B8):
// [32] aaaaaaaa rrrrrrrr gggggggg bbbbbbbb [0]
typedef struct _XMCOLOR
{
    union
    {
        struct
        {
            UINT b    : 8;  // Blue:    0/255 to 255/255
            UINT g    : 8;  // Green:   0/255 to 255/255
            UINT r    : 8;  // Red:     0/255 to 255/255
            UINT a    : 8;  // Alpha:   0/255 to 255/255
        };
        UINT c;
    };

#ifdef __cplusplus

    _XMCOLOR() {};
    _XMCOLOR(UINT Color) : c(Color) {};
    _XMCOLOR(FLOAT _r, FLOAT _g, FLOAT _b, FLOAT _a);
    _XMCOLOR(CONST FLOAT *pArray);

    operator UINT () { return c; }

    _XMCOLOR& operator= (CONST _XMCOLOR& Color);
    _XMCOLOR& operator= (CONST UINT Color);

#endif // __cplusplus

} XMCOLOR;

通过将整数区间[0,255]映射到实数区间[0,1],可以将一个32位颜色转换为一个128位颜色。这一映射工作是通过将每个分量除以255来实现。也就是,当n为0到255之间的一个整数时,对应于规范化区间[0,1]的分量值为0≤\(\frac{n}{{255}}\)≤1。例如,32位颜色(80,140,200,255)变为:

(80,140,200,255) → (\(\frac{{80}}{{255}},\frac{{140}}{{255}},\frac{{200}}{{255}},\frac{{255}}{{255}}\) ) ≈ (0.31,0.55,0.78,1.0)

另一方面,通过将每个颜色分量乘以255并进行四舍五入,可以将一个128位颜色转换为一个32位颜色。例如:

(0.3,0.6,0.9,1.0) → (0.3*255,0.6*255,0.9*255,1.0*255) = (77,153,230,255)

当把一个32位颜色转换为一个128位颜色或者进行反向转换时,通常要执行额外的位运算,因为8位颜色分量通常会被封装在一个32位整数中(例如,无符号整数),即在XMCOLOR中。XNA数学库使用以下函数处理一个XMCOLOR并以XMVECTOR的形式返回:

XMVECTOR XMLoadColor(CONST XMCOLOR* pSource); 
图5.10
图5.10:一个32位颜色,它为每个颜色分量分配一个字节。

图5.10说明了如何将4个8位颜色分量封装为一个无符号整数。注意,这只是用于封装颜色分量的方式之一。除使用ARGB外,还可以使用ABGR或RGBA。不过,XMCOLOR类使用ARGB格式。XNA数学库提供了一个函数可以将一XMVECTOR颜色转化为一个XMCOLOR

VOID XMStoreColor(XMCOLOR* pDestination,FXMVECTOR V);

通常,许多颜色运算(例如,在像素着色器中)使用的都是128位颜色值;通过这一方式,我们可以有足够多的二进制位来保证计算的精确度,减少算术错误的累积。不过,最终的像素颜色通常是存储在后台缓冲区的32位颜色值中;目前的物理显示设备还不能充分利用更高的分辨率颜色。

文件下载(已下载 1315 次)

发布时间:2014/7/27 20:03:37  阅读次数:4747

2006 - 2024,推荐分辨率1024*768以上,推荐浏览器Chrome、Edge等现代浏览器,截止2021年12月5日的访问次数:1872万9823 站长邮箱

沪ICP备18037240号-1

沪公网安备 31011002002865号