计算机色彩谈


这两天 ch_gamedev 这个 mail list 里大家讨论了一下有关游戏中使用色彩的问题, 接着讨论的势头一直波及到这儿的留言板;-) 我看看有必要将大家的讨论过程 整理一下, 便于后人查阅了 ;-D 在这里, 我们要感谢这次参与讨论的朋友: Wiliam Zero Tdlife Peng Cloud Wu Chen Shen Harrison 没有大家的讨论就没有这篇文章.

我们所使用的 PC 机的显示器的颜色显示采用的是 RGB 模式, 就是说那缤纷的色彩都是由红, 绿, 蓝 三种颜色构成的. 最初的机器内存(显存)昂贵, 所以采用调色板机制来节省显存, 使用的显示模式便是我们所熟知的 256 色模式. (标准 VGA 下的 0x13 模式即为 256 色的) 在这个模式下所有的点由 64 级红色, 64 级绿色, 64 级蓝色构成. 而将需要用到的 256 种颜色配好后 放到调色板中, 而显存里则存放调色板的序号(0~255). 用这种方式, 我们可以得到丰富的色彩, 又不必消耗太多的内存, 在以前内存昂贵, 硬件速度偏慢的年代,无疑是是一种既节约内存,又能提高处理图形速度的好方法. 而后来内存的价格急剧下降,显卡配上 1M 以上的显存已经不是什么奢侈的事, 而且主板上的内存也越来越多,能够处理的数据量也比以前大的好几倍; 而 CPU 更能处理 32 位数据, 这样 8 位(256色) 显示模式简直 毫无优势可言, 16 位色即将成为标准.

话说这 16 位色, 实际上就是直接用 16 bit 去描述屏幕上的每个点, 其中红色占 5 位,绿色占 6 位,蓝色占 5 位. (为了某些处理上的方便, 许多显卡支持所谓 15 位色, 就是将蓝色也用 5 bit 表示) 使用这种直接描述颜色的方式 最大的方便之处在于实时光影的效果,透明色的计算.例如在游戏中实时运算 爆破的火光和景物的叠加, 就可以利用 Alpha 混合算法 计算出火焰的色彩值直接反映在屏幕上. 另外, 象 3D 引擎中常用的 诸如雾化等都需要对颜色进行实时的运算, 所以如今的 3D 加速卡都没有支持 间接表现颜色的 256 色模式. 可话说回来, 在特定的情况下 256 色有着 64K (16 位)色无可比拟的地方, 它终究是 18 bit 色彩, 在红和绿色上拥有多出 64k 色下一倍的颜色级别, 运用得当, 将有更强的表现力.

当然机器足够扎实的话, 24bit 色是你无悔的选择, 每种基色 256 个级别, 相信再好的眼睛也无法分辨出相邻两级颜色. 故而, 24bit (16M) 色号称真彩. 在真彩模式下, 绘出一渐变绿色条,人眼不会有跳跃性颜色过渡的. (而在 64k 色模式下却有). 所以随着显示器的增大,玩家会去追求更高的分辨率 确不会要求超过 16M 色的色彩. 另一 32bit 色彩模式已经不再去增加基色 占有的位长, 它或是留下 8 位的 alpha 通道, 或是干脆空出 8 位, 充分利用 CPU 一次处理 32 bit 字长的威力, 所以 32bit 模式在一般情况下 都是以空间换时间的做法, 32bit 模式快于 24 bit 模式 ;-) 真彩唯一的缺陷是我们现今的机器还不足以飞快的处理,而游戏中使用的图象信息 的大小也会随着每点占字节数的增加而成倍的增大体积.

使用颜色技巧性最强的非 256 色莫属了. 何况 256 色模式下还能更容易的 实现淡入淡出这样的特效 :-) 如果游戏中没有实时光影需要计算, 没有实时的色彩混合, 却根本用不上更高的颜色模式. 君不见, 任何一张照片 使用合适的方法在 256 色模式下显示, 都不会虐待你的视觉. 如果某个游戏 仅仅是由于色彩数不够用而强迫玩家采用 64K 或以上的显示模式, 那只能说明开发人员的技术不够. 需要以 256 色显示写实的画面时, 一般先需要求出最优匹配的调色板. 循环的计算调色板去和真彩图片比较, 使图片中原始色的失真最小 (即每个原始色彩和调色板中最优匹配色差值总和最小). 然后可以简单的去以最优匹配来匹配每个点; 也可以使用抖动算法, 其一是采用固定样式数组, 用一个数组的每个元素来储存不同的匹配程度, (即采用调色板中接近程度多少的颜色匹配点). 这样在稍大块色块上, 使用 256 色匹配时不会采用同一(最接近的)颜色去匹配它, 而是根据固定样式数组中的匹配程度值来以不同而相近的色彩交替去匹配. 这样产生的混合色的效果往往更真实,而且没有消耗更多的时间, 但产生的图形上却会有网点的感觉. :-( 为了达到更好的效果, 我们可以采用误差扩散的方法. 即在匹配一个点时采用最优匹配, 而将匹配时产生的误差计算出来, 以特定的比例分配方式加在它右边和下边的点上, 以累加和来匹配后面的点. 这种方法的效果要好的多, 但需要消耗过多的时间, 不适合实时处理 :-( (难以预料以后的机器的速度将有多快, 你说呢? ;-)

即使是需要实时光影的地方, 256 色也不是难以胜任, Diablo 中的光影就做的不错; 天惑的 256 色模式下爆炸光环也相当的好. 所以灵活使用调色板, 更能体现程序员的功力 ;-) 以我的看法, 采用实时计算出特定效果时, 可以采用两种方法. 其一, 选择一个合适的调色板, 如果贪图简单, 伪真彩模式相当的简单, 使用 3 bit 描述红色, 3 bit 描述绿色, 2 bit 描述蓝色. 让调色板的序号和颜色直接挂上沟, 老实话, 这种模式的确不赖 ;-) 足够满足一般的要求. 如果细心点, 也可以自己选择一个好的调色板, 采用 16 组色彩, 每种 16 级. 加上灵活的使用将有上佳的表现. 观察<<仙剑奇侠传>>,<<神雕侠侣>> 这些 RPG, 无不是采用这样的方法; 其二, 我们可以采用动态调色板. 如果是象<<三国志 IV>>这样背景地图可以随季节变化的游戏,无非是将 256 色调色板里的一部分那出来专门描述地图. 计算好几组地图色调用调色板, 需要变化的时候,将这部分调色板替换掉就可以了 ;-) 而如果你的游戏中需要实时光影, 可以将调色板分成 192 + 64 两部分. 64 色可以随时变化, 以适应叠加光影效果后的颜色值, 这样可以比固定调色板有更大的灵活性.

花了许多时间完成这些,第一次写这种常识性的文章,难免经验不足. 如果有疏忽遗漏或错误的地方,请来信批评指正. 文章旨在向大家介绍一些常识,所以提到了许多算法都是一笔带过, 如果真都写出来,文章的篇幅就要成倍的增加,也不可能在短时间完成了. 如果有朋友感兴趣,我们再继续讨论 ;-)