《点睛:ActionScript3.0游戏互动编程》——1.2 ColorTransform对RGB数值的操作及应用

1.2 ColorTransform对RGB数值的操作及应用

flash.geom.ColorTransform是Flash内置的一个色彩变换类。它支持色彩通道值的线性变换。

所谓线性变换,是指一次函数模式的变换:dst = src * multiplier + offset。我们可以将每个通道的值与常量进行四则运算。对于ColorTransform类而言,通道的原数值和变换后的数值存在如下关系。

red(dst) = red(src) * redMultiplier + redOffset
green(dst) = green(src) * greenMultiplier + greenOffset
blue(dst) = blue(src) * blueMultiplier + blueOffset
alpha(dst) = alpha(src) * alphaMultiplier + alphaOffset

这当中,dst代表结果值,src代表初始值。

这个运算看起来并不复杂,我们也能手工实现。但是,自己写的算式无法直接应用于显示对象或者BitmapData上,我们必须逐个像素点地去修改颜色(当然,ColorMatrixFilter、自定义滤镜、颜色表等方法也能实现),并且对于矢量图而言,处理前还不得不先转换成位图。而用ColorTransform的话则非常方便,我们只要对指定对象应用了它,每个像素点的颜色就会自动做出相应的变化,从而实现图形色调、亮度等属性的整体变换乃至反色效果,而且不会丢失矢量信息。

此外,ColorTransform还支持通过color属性将对象的所有像素点设置成同一种颜色。假设myColorTransform.color = 0xFFFF00,被应用了myColorTransform的对象就会呈现为单一黄色的状态,它跟下面的代码完全等价。

代码清单1-2

myColorTransform.redMultiplier = myColorTransform.greenMultiplier = myColorTransform.blueMultipler = 0;
myColorTransform.redOffset = 255;
myColorTransform.greenOffset = 255;
myColorTransform.blueOffset = 0;

因为与src相乘的系数都被设置为0,所以不管src是多少,dst的值都不会受到任何影响,red(dst)和green(dst)始终等于255,blue(dst)始终等于0,于是所有像素点的RGB色彩值都等于0xFFFF00(黄色),而alpha(不透明度)则不发生变化。

ColorTransform最常用的地方有两处。

1 DisplayObject.transform.colorTransform = myColorTransform;
2 BitmapData.colorTransform(myColorTransform);

这里我们只测试第一项,第二项在BitmapData的相关章节再进一步深入讨论。

1.2.1 RGB测试用例的书写
新建一个ActionScript项目,名为ShapeColorTransformTest,我们在里面创建几个不同颜色的小圆,观察它们在应用了colorTransform之后的变化,代码如下。

代码清单1-3

package{
   [SWF(width = "800", height = "600")]
    public class ShapeColorTransformTest extends Sprite{
        private var _testSprite_src:Sprite; //用于测试的显示对象(变换前)
        private var _testSprite_dst:Sprite;  //用于测试的显示对象(变换后)
        private var _myColorTransform:ColorTransform;  //颜色转换对象
        public function ShapeColorTransformTest(){
            init();
        }
        private function init():void{
            _testSprite_src = getTestSprite();
            addChild(_testSprite_src);
            _testSprite_dst = getTestSprite();
            _testSprite_dst.x = 200;
            addChild(_testSprite_dst);
            applyTransform();
        }
        //创建用于测试的显示对象
        private function getTestSprite():Sprite{
            var _testSprite:Sprite = new Sprite();
            var _shape1:Shape = new Shape();  //添加一个黑色的矩形底
            _shape1.graphics.beginFill(0x000000);
            _shape1.graphics.drawRect(40, 30, 170, 290);
            _shape1.graphics.endFill();
            _testSprite.addChild(_shape1);
            /依次添加颜色分别为暗蓝、暗红、暗绿和纯白的4个圆/
            _testSprite.addChild(new Circle(50, 0x0000CC, 100, 200, "add"));
            _testSprite.addChild(new Circle(50, 0xCC0000, 150, 200, "add"));
            _testSprite.addChild(new Circle(50, 0x00CC00, 125, 250, 1,"add"));
            _testSprite.addChild(new Circle(37.5, 0xFFFFFF,125,100,1,add"));
            return _testSprite;
        }
        private function applyTransform():void{
            _myColorTransform = _testSprite_dst.transform.colorTransform; //初始化颜色变换对象(从显示对象里获取)
            _myColorTransform.redMultiplier = 1.5;
            _testSprite_dst.transform.colorTransform = _myColorTransform; //应用到显示对象上(变换后必须重新赋值,否则变换效果不起作用,详情可查阅帮助文档)
    }
}

在后续的章节中,我们会经常使用圆来表示一个点或者创建一个色块。为便于这一功能的重用,我们可以把这个可爱的圆封装成一个Circle类并放入到公共类库。

小提示
有的书喜欢用Ball来命名这样的类,这里统一取名为Circle,因为纯色的圆并没有球的那种立体感。
代码清单1-4

package com.gemei.display{
    public class Circle extends Sprite{
        //为节省本书篇幅,我把x,y,alpha, blendMode这些基本属性都封装到Circle类里面了,项目开发中不推荐这么做
        public function Circle(radius:Number = 50, color:uint = 0x000000, x:Number = 0, y:Number = 0, alpha:Number = 1, blendMode:String = BlendMode.NORMAL){
            super();
            this.x = x; this.y = y; this.blendMode = blendMode;
            graphics.beginFill(color, alpha);
            graphics.drawCircle(0, 0, radius);
            graphics.endFill();
        }
    }
}

以上代码创建了两个外观一模一样的显示对象,然后添加到舞台上显示(使用BlendMode只是为了方便创建多个色块,后续章节笔者会给出详细的介绍),我们用ColorTransform对其中一个进行变换,从而跟不变换的那个进行比较。

1.2.2 初始效果及颜色属性的测试
按F11/Ctrl+F11测试,效果如图1-2所示。如果左右两组小圆色彩上看起来有所差别,那就请大家校对一下是否在输入代码的过程中出现了笔误,同时注意检查显示器是否因为老化、视角等问题而导致同一种颜色在不同的位置有不同的效果。因为现在的代码仅仅做了一次赋值,中途并没有对ColorTransform进行其他处理。

下面我们先从效果最明显的color开始测试。设置一下_myColorTransform.color = 0xFFFF00看看,如图1-3所示。

整个显示对象都变黄了。此外,我们用下面的代码也能实现同样的效果。

代码清单1-5

_myColorTransform.redMultiplier = _myTransform.greenMultiplier = _myColorTransform.blueMultiplier = 0;
_myColorTransform.redOffset = _myColorTransform.greenOffset = 0xFF;

代码起作用了,我们尝试复杂一点的变换。

1.2.3 线性/倍乘提高降低亮度
线性提高亮度(见图1-4):_myColorTransform.redOffset = _myColorTransform.greenOffset = _myColorTransform.blueOffset = 100。

线性降低亮度(见图1-5):_myColorTransform.redOffset = _myColorTransform.greenOffset = _myColorTransform.blueOffset = -100。

倍乘提高亮度(见图 1-6):_myColorTransform.redMultiplier = _myColorTransform. greenMultiplier = _myColorTransform.blueMultiplier = 1.5。

倍乘降低亮度(见图 1-7):_myColorTransform.redMultiplier = _myColorTransform. greenMultiplier = _myColorTransform.blueMultiplier = 0.7。

我们可以看到,通过ColorTransform增大R、G、B这三个通道的值,能够使所有色彩都变得明亮;相反,减小它们的值,色彩就变暗。然而,这种感觉多少有点别扭,它们看起来更像是给图形蒙上了一层灰,效果特别不自然。倍乘提高亮度的感觉稍好一点,因为黑色和白色在经过运算之后,通道值都没有发生变化,黑色的RGB均为0,乘以1.5后不变;白色的RGB均为255,乘以1.5后大于上限255,于是结果仍为255。

我们可以尝试将线性变化和倍乘变化结合在一起,让亮度变暗的效果舒服些,比如让黑色的RGB结果小于0,而白色始终保持255。

代码清单1-6

_myColorTransform.redMultiplier = _myColorTransform.greenMultiplier = _myColorTransform. blueMultiplier = 1.5;
_myColorTransform.redOffset = _myColorTransform.greenOffset = _myColorTransform.blueOffset = - 127;

我们应用上了这个 ColorTransform 以后,255的变换结果等于 255,而 0 的变换结果等于−127,取下限之后就是 0,于是黑和白看起来就没有变化了,如图1-8所示。

然而,这始终是针对极端数值的权宜之计,局限性很大,对其他颜色的可控性较差,可能在单色的矢量图下感觉不明显,但如果换成色彩比较丰富的照片,那么效果依然不尽如人意,大家可以找些照片来测试一下。而且,从这些例子我们可以看出,RGB的数值跟人类的视觉系统并不协调,至少亮度处理方面是这样的情况。

以上例子对每个通道都做出了完全相同的变换,下面我们尝试给不同通道设置不同的值,看看有没有新的发现。

1.2.4 单个通道的线性/倍乘变化
线性提高红色的成分(见图1-9):_myColorTransform.redOffset = 127。

线性减弱红色的成分(见图1-10):_myColorTransform.redOffset = -127。

倍乘提高红色的成分(见图1-11):_myColorTransform.redMultiplier = 1.5。

倍乘降低红色的成分(见图1-12):_myColorTransform.redMultiplier = 0.7。

我们调整单个通道的值,图像的色彩发生了一些微妙的变化。因为现在只对单个通道进行计算,所以总的来说,反射出来的色光都会增多或者减少,如果想保持反射的色光总量不变,就应该多调整一个或者两个通道以抵消红色通道的改变。

1.2.5 ColorTransform在色彩处理方面的不足
在以上的测试中,有些本来不同的颜色在经过ColorTransform的转换以后变得出奇的一致。如果想给图像做变色效果,那这样的情况往往是我们需要避免的。此时,ColorTransform就有点心有余而力不足了。

归根到底,这还是因为RGB模式在人类的视觉体验方面做得不够友好。

接下来,我们看看之前没测试过的alpha变换。理所当然,之前的图像就不太适用了,因为图像里每个像素点的alpha都等于1。
**
1.2.6 Alpha测试用例的书写**
我们把ShapeColorTransformTest复制为ShapeColorTransform ForAlphaTest,然后对代码进行如下调整。

首先我们把getTestSprite修改为如下格式。

代码清单1-7

//创建用于测试的显示对象
private function getTestSprite():Sprite{
    var _f:Array = [new BlurFilter(80, 80)];
    var _testSprite:Sprite = new Sprite();
    /添加两个圆,颜色分别为白和黑/
    _testSprite.addChild(new Circle(50, 0xFFFFFF, 100, 100)).filters = _f;
    _testSprite.addChild(new Circle(50, 0xFFFFFF, 100, 250)).filters = _f;
    return _testSprite;
}

而applyTransform函数则调整如下。

代码清单1-8

private function applyTransform():void{
    _myColorTransform = _testSprite_dst.transform.colorTransform;
    _myColorTransform.alphaMultiplier = 0;
    _myColorTransform.alphaOffset = 127;
    _testSprite_dst.transform.colorTransform = _myColorTransform;
}

运行效果如图1-13所示。以上代码用模糊滤镜BlurFilter生成了带两个透明渐变圆的Sprite。本来这里用透明渐变填充会更加合理,但考虑到渐变代码比较复杂,而且这里还没介绍到,就先用模糊滤镜。

下面我们尝试一下alpha变换。

**
1.2.7 线性提高或降低alpha值**
提高alpha值(见图1-14):_myColorTransform.alphaOffset = 100。

降低alpha值(见图1-15):_myColorTransform.alphaOffset = -100。

粗略一看,它跟设置alpha似乎没什么两样,但仔细观察我们就会发现,当alphaOffset提高的时候,周边比较透明的像素会逐渐淡入到1;相反,降低的时候,周边会慢慢淡出到0。所以,虽然这仅仅是一个简单的线性变换,但是拿来做光圈或者黑洞的扩散/收缩效果将会相当不错。

下面,我们做个直接设置alpha的版本来对照一下效果。

1.2.8 设置alpha值
倍乘降低alpha(见图1-16):_myColorTransform.alphaMultiplier = 0.7。

注意,设置alpha跟设置颜色不同,它要在原有像素的基础上设置倍率才符合alpha的概念,效果才跟设置displayObject.alpha一致。

倍乘提高alpha(见图1-17):_myColorTransform.alphaMultiplier = 1.5。

我们可以看出,alpha的变换呈现为整体性,因此没有扩散收缩的效果,如果大家有跟着我们一起测试的话,就不妨用补间引擎或者enterFrame来测试两种效果在渐入渐出时的差别。我们认为alphaOffset的效果要比multiplier漂亮多了。

如果我们像设置颜色那样,把multiplier弄成0,像素点的透明度就统一起来了。这个效果虽然不甚美观,但是很适合用来做一些图像的预处理工作。

代码如下。

代码清单1-9

_myColorTransform.alphaMultiplier = 0;
_myColorTransform.alphaOffset = 127;

效果如图1-18所示。

在alpha通道方面,ColorTransform没让我们失望,毕竟它独立于色彩模式,而且只有一个值,所以运算的处理也相对容易把握一些。

1.2.9 用ColorTransform实现反色效果
本节的最后,笔者给大家介绍一个稍稍有点意思的效果——反色。这种颠覆性的变换,线性的ColorTransform也能做到吗?答案是肯定的!所谓的反色,就是白变黑,黑变白,浅变深,深变浅,它的计算公式也非常简单,用100%减去原值就能得到结果色,即

dst = 255 – src;

套到ColorTransform的计算公式中,就有如下格式。

red(dst) = red(src) * (-1) + 255。
green(dst) = green(src) * (-1) + 255
blue(dst) = blue(src) * (-1) + 255

换而言之,只要把offset都设为255、multiplier都设成−1,就可以得到所谓的反色效果了(可能有的读者还没想过将multiplier设置为负数吧)。

代码清单1-10

_myColorTransform.redMultiplier = -1;
_myColorTransform.greenMultiplier =-1;
_myColorTransform.blueMultiplier = -1;
_myColorTransform.redOffset = 255;
_myColorTransform.greenOffset = 255;
_myColorTransform.blueOffset = 255;

可出来的效果跟预期不一致,如图1-19所示。

经过将近两周的纠结,笔者终于找到了问题的症结所在——跟BlendMode发生冲突了。因为BlendMode.ADD也是像素运算,两者混合后的运算机制及其优先级规则有待作进一步的研究。

我们把BlendMode.ADD一句去掉之后,反色效果跃然屏上,如图1-20所示。

时间: 2024-11-01 21:47:49

《点睛:ActionScript3.0游戏互动编程》——1.2 ColorTransform对RGB数值的操作及应用的相关文章

《点睛:ActionScript3.0游戏互动编程》——导读

前言追溯至1946年,计算机在第三次工业革命的推动下得以诞生并发展,从此地球上多了一类人,他们的世界很简单,每天不是和0接触,就是跟1来往.他们低调做人.高调做事,他们务实为民.不求名利,他们就是可爱可人.可歌可泣的IT工作者--程序员!都说程序员不善表达,没错,离开0和1,程序员就几乎不会说话了.与此同时,程序员也恰恰是最善于表达的人,他们只用0和1这两个数字,就可以准确无误地将用户的需求传达给电脑并使其正确运行,其语言之简练,其算法之精准,其逻辑之严谨,其结果之准确,试问除了程序员,还有谁可

《点睛:ActionScript3.0游戏互动编程》——1.4 浅析亮度与灰度/明度的关系

1.4 浅析亮度与灰度/明度的关系 进入正题之前,我们先来了解一下灰度/明度. 1.4.1 灰度/明度的概念及其与HSB亮度的异同 在很多场合,灰度与明度的概念完全等价. "灰度"一词最初来源于摄影领域,在彩色显像技术问世以前,拍摄出来都是黑白照片,只有黑白灰3种颜色能完好无损地记录下来,其他颜色将根据其亮度呈现出不同深度的灰色.亮度越大灰色越浅,反之越深,把从黑到白的过渡区域划分为若干个级别,就会得到不同的"灰度等级".能呈现的灰度等级愈多,画面的层次感就愈丰富.

《点睛:ActionScript3.0游戏互动编程》——1.3 HSB模式及其与RGB间的转换

1.3 HSB模式及其与RGB间的转换 从前面的讨论可知,RGB模式是一个数理性质较强的概念,对于大部分色彩来说,我们很难通过RGB的数值得知它代表什么颜色以及它的明暗和鲜艳程度如何. <忆江南>中的景观之所以能直接用最简单的三原色来渲染,完全是因为它所描绘的江南美景足够的清澈纯净而且颜色的种类较少. 实际上,大多数情况下,颜色的种类远不止红绿蓝三种,例如北宋的苏东坡在以歌咏残秋季节景物为主题的<赠刘景文>一诗中就有这样的一句:"一年好景君须记,最是橙黄桔绿时."

《点睛:ActionScript3.0游戏互动编程》——2.2 Photoshop投影样式在Flash基本滤镜中的体现

2.2 Photoshop投影样式在Flash基本滤镜中的体现 作为上帝的另一个化身,Flash在图层样式方面自然也不甘示弱,不过在Flash里面,它有另外一个名字--滤镜(仅仅从概念上说,Flash的滤镜包含了Photoshop里的图层样式和滤镜). 下面打开Flash CS6/5.5,一起在滤镜里寻找Photoshop图层样式的影子,同时,我们先把Photoshop的图层样式暂时清除掉(把样式名称前面的复选框全部取消勾选即可). 我们先新建一个文档([文件]|[新建]或Ctrl+N),类型选

《点睛:ActionScript3.0游戏互动编程》——第2章 融会贯通—大话图层样式与滤镜2.1 Photoshop图层样式初体验

第2章 融会贯通-大话图层样式与滤镜 Photoshop和Flash都是杰出的软件,前者静得从容,后者动得洒脱,它们以不同的方式诠释着计算机时代的艺术.下面我们就从Photoshop的图层样式开始我们的艺术创作之路吧! 2.1 Photoshop图层样式初体验 我们打开Photoshop CS5,新建一个尺寸为600*100(单位:像素)的空白文档,使用[横排文字工具]E:\desktop\AS3 Text Effects\snapshots\第4章\4.1\横排文字工具.tif在画布上拖出一个

《点睛:ActionScript3.0游戏互动编程》——2.3 使用斜角滤镜模拟Photoshop的斜面样式

2.3 使用斜角滤镜模拟Photoshop的斜面样式 滤镜列表中,[斜角]似乎最接近斜面的含义,我们不妨点出来看看,如图2-45所示. 嗯,是这个效果了.现在把Photoshop的斜面样式重新打开,我们按之前对Photoshop的设置来修改Flash里的参数."大小"参数我们没有使用默认值,而是从原来的5改成了3.在Flash里我们也应用同样的设置,如图2-46所示. 出来的效果并不好看.细心的读者应该不难发现,斜角滤镜加上以后,整个字好像带上了重影一样,第一眼看上去还以为是自己的眼睛

《点睛:ActionScript3.0游戏互动编程》——1.5 小结

1.5 小结 本章主要介绍了色彩的基本组成以及RGB.HSB这两种最常用的色彩模式. 前者概念偏理性,计算方法和公式都相当明确,程序处理起来非常方便,但未能较为准确地反映出通道数值跟视觉感受的关系,无法指导色彩搭配.对于程序员来说,想要提高配色水平,除了使用配色软件以外,还可以参考一些现成的色码表. 后者则有效弥补了RGB模式的不足,但它本身偏感性,有种只可意会不可言传的特质.所以,能否用好HSB,一定程度上取决于经验积累的多少. 这当中,数值没有明显大小意义的色相值H比较难以捉摸.在此我们提供

《点睛:ActionScript3.0游戏互动编程》——2.4 本章小结

2.4 本章小结 从投影和斜面样式的模拟过程,我们不-难看出,跟Photoshop相比,Flash滤镜的能力真是相当有限,而且,默认参数出来的效果也不如Photoshop的好看,毕竟Flash不是纯粹的设计软件,在规划默认数值的时候,往往会偏向于选择较为极端或者较具数学意义的值(如45度). 另一方面,我们发现,Photoshop样式的参数种类要比Flash丰富得多,而且不同样式的设置面板,内容也不尽相同.但是在Flash里面,两个看起来毫不相干的滤镜却频频出现属性名的重复,而且这些相同的属性在

算法设计-猜猜我是谁游戏设计编程思想

问题描述 猜猜我是谁游戏设计编程思想 像微软小冰的读心术类似通过程序给出的几个问题选择是否来推出所猜的人,这要用什么数据结构 解决方案 这个是根据语义匹配等算法实现的.