最近一直在学习 Image Effects

FriendsofED - Foundation ActionScript 3.0 Image Effects (2009).pdf

很不错的书,riabook.cn 有下载

http://www.riabook.cn/en_book/Foundation-ActionScript-3-Image-Effects.htm

书中所有源代码下载

请在http://www.friendsofed.com/ 搜索Image Effects

 

讲解了很多计算机图形学的编程,而且还包含了很多使用actionsript实现photoshop的各种工具效果.

因为是纯英文的,所以就只偷偷懒.

所以只作个简单的 效果 ↔ 程序 的映射笔记
1. The Drawing API

简单的draw 请参见graphics的API

new:

将源 Graphics 对象中的所有绘画命令复制到执行调用的 Graphics 对象中。

copyGraphics();

示例:

shape.graphics.copyFrom(sourceGraphics);

ps:仅copy绘制命令 开销比bitmapData.draw() 小多了

 

通常,与使用一系列单个 lineTo()curveTo() 方法相比,使用 drawPath() 呈现绘图的速度会更快。

drawPath() 方法使用浮动计算,因此形状的旋转和缩放更准确,可以获得更好的结果。但是,通过使用 drawPath() 方法提交的曲线在与 lineTo()curveTo() 方法结合使用时,可能会存在小的子像素对齐误差。

drawPath(commands:Vector, data:Vector, winding:String = "evenOdd")

示例: 见AS3 API吧

PS: 这个很多教程都提到过(如:AS3动画教程),

当时看的时候唯一值得注意的地方是第三个参数 winding,决定了两种不同的填充方法

 

呈现一组三角形(通常用于扭曲位图),并为其指定三维外观。drawTriangles() 方法使用一组 (u,v) 坐标将当前填充或位图填充映射到三角形面。

drawTriangles(vertices:Vector, indices:Vector = null, uvtData:Vector = null, culling:String = "none")

示例: 同上

PS: 同上,初级的扭曲位图 in AS3动画教程.可以制作高效的仿3D效果(不可交互).

之后的矩阵操作带来更多灵活的方法.


2. Filters and Blend Modes

介绍了很多混合模式的实现原理.

定义两种颜色uint A,B

以下介绍各种模式:

混合模式    →    结果

normal(A,B)       A   

multiply(A,B)    (A * B) / 255

screen(A,B)    (255 - ((255 - A ) * ( 255 - B)) / 255)

hardlight(A,B)   (A > 127.5) ? screen(B,2 * A - 255) : multiply(B, 2 * A)

overlay(A,B)    hardlight(A,B)

add(A,B)      Math.min(255,A + B)

subtract(A,B)    Math.max(0, B - A)

lighten(A,B)    Math.max(A,B)

darken(A,B)    Math.min(A,B)

difference(A,B)    Math.abs(A - B)

invert(A,B)      255 - B

之后是 AS3带有的滤镜介绍

基本滤镜 略

使用 ColorMatrixFilter 类可以将 4 x 5 矩阵转换应用于输入图像上的每个像素的 RGBA 颜色和 Alpha 值,以生成具有一组新的 RGBA 颜色和 Alpha 值的结果。 该类允许饱和度更改、色相旋转、亮度为 Alpha 以及各种其它效果。 您可以将滤镜应用于任何显示对象(即,从 DisplayObject 类继承的对象),例如 MovieClip、SimpleButton、TextField 和 Video 对象,以及 BitmapData 对象。

ColorMatrixFilter

示例见API

主要介绍几个常用的颜色转换矩阵

Desaturating 稀释

   var matrix:Array = [
    0.3, 0.59, 0.11, 0, 0,
    0.3, 0.59, 0.11, 0, 0,
    0.3, 0.59, 0.11, 0, 0,
    0,     0,    0,      1, 0
   ];

 

Inverting to a negative 反色

   var matrix:Array = [
    -1,  0,  0, 0, 255,
     0, -1,  0, 0, 255,
     0,  0, -1, 0, 255,
     0,  0,  0, 1,  0
   ];

 

Tinting 老照片效果(可以更改第一列的4个参数 决定显示的颜色 默认 0.5 , 0.4 ,0.16 老照片的棕色)

var matrix:Array = [
      0.5, 0.59, 0.11, 0, 0,
      0.4, 0.59, 0.11, 0, 0,
    0.16, 0.59, 0.11, 0, 0,
         0,     0,    0,   1, 0
   ];

 

ConvolutionFilter 类应用矩阵盘绕滤镜效果。 卷积将输入图像的像素与相邻的像素合并以生成图像。 通过卷积,可以实现大量的图像效果,包括模糊、边缘检测、锐化、浮雕和斜角。 您可以将滤镜应用于任何显示对象(即,从 DisplayObject 类继承的对象),例如 MovieClip、SimpleButton、TextField 和 Video 对象,以及 BitmapData 对象。

ConvolutionFilter

示例见API

Blurring 模糊 3 x 3 (想要模糊效果更强烈 可以扩大到 7 x 7 以上)

   var matrix:Array = [
    1, 1, 1, 
    1, 1, 1, 
    1, 1, 1, 

 ];

 

Gaussian blur 高斯模糊

   var matrix:Array = [

  1, 1, 2,  2, 2, 1, 1,

  1, 1, 2,  4, 2, 1, 1,

  2, 2, 4,  8, 4, 2, 2,

  2, 4, 8,16, 8, 4, 2,

  2, 2, 4,  8, 4, 2, 2,

  1, 1, 2,  4, 2, 1, 1,

  1, 1, 2,  2, 2, 1, 1,

 ];

 

Sharpening 锐化 (扩展同模糊)

   var matrix:Array = [
     0, -1,  0, 
    -1,  5, -1, 
     0, -1,  0, 

 ];

 

Embossing 浮雕

   var matrix:Array = [
     -2, -1,  0, 
     -1,  0,  1, 
      0,  1,  2, 

 ];

 

Another embossing 另一种浮雕效果

  var matrix:Array = [
    1, 0, -1, 
    2, 0, -2, 
    1, 0, -1, 

 ];

 

DisplacementMapFilter 类使用指定的 BitmapData 对象(称为置换图图像)的像素值执行对象置换。 您可以使用此滤镜将扭曲或斑点效果应用于从 DisplayObject 类中继承的任何对象,例如 MovieClip、SimpleButton、TextField 和 Video 对象,以及 BitmapData 对象。

DisplacementMapFilter

示例见API

PS:主要用于使用某一颜色通道显示目标图像的凹凸感

 

3. Bitmaps and BitmapData

基本加载/嵌入bitmap

BitmapData基本操作 transform,copy,pixel操作 之类的

 

对图像执行倾倒填充操作,从 (x, y) 坐标开始,填充一种特定的颜色。 floodFill() 方法类似于各种绘图程序中的“颜料桶”工具。 该颜色是包含 Alpha 信息和颜色信息的 ARGB 颜色。

floodFill ()

填充

PS:网上有很多的填充算法之类的资料 有兴趣可以看一下...虽然API有提供这个方法,但是填充的工具中有 填充不闭合图形的方法 但是API中没有哦

 

Transforming color

想做各种绚丽的粒子效果 要熟悉颜色变化

ColorTransform中提供了很多现成的东西,那复杂的矩阵简化到只用输入关键的几个参数


4. Advanced Bitmap Manipulation

此章节的名字决定了 它没什么特别的东西...

有兴趣的话 自己看下这个章节吧...如果你正在做位图方面的各种效果实现..

此章节提供了一些鸡肋的应用

(有一些photoshop里的功能实现应用,不过本人觉得flash更适合处理动态,而不是photoshop一样的静态)

PS:有兴趣可以看下,里面的copyChannel例子还不错.不过会就足够了...没必要深入


5. Pixel Bender and Shaders

如果只是说Pixel Bender的话 我就准备略过的.

但是此章节中使用了AS3 API中的 proxy !!!!!!!!

不多说 直接放代码

没兴趣的话 可以直接跳过这里了...

了解怎么实用proxy 可以更好的了解AS3对象的结构,

在扩展外部接口时将更加方便,易懂

详情见下面的2个 override flash_proxy function 和 AS3 API

注意:类 前面有dynamic

 

代码
1 package {
2
3 import flash.display.Shader;
4 import flash.display.ShaderInput;
5 import flash.display.ShaderParameter;
6 import flash.events.Event;
7 import flash.events.EventDispatcher;
8 import flash.events.IEventDispatcher;
9 import flash.net.URLLoader;
10 import flash.net.URLLoaderDataFormat;
11 import flash.net.URLRequest;
12 import flash.utils.ByteArray;
13 import flash.utils.Proxy;
14 import flash.utils.flash_proxy;
15
16 /**
17 * Class to handle loading or embedding, and passing values to a shader
18 * to make it easier dealing with the quirks of the Shader class and bytecode.
19 */
20 dynamic public class ShaderProxy extends Proxy implements IEventDispatcher {
21
22 private var _shader:Shader;
23 private var _eventDispatcher:EventDispatcher;
24
25 /**
26 * Constructor. This accepts a path to a .pbj file to load or
27 * a shader bytecode class to instantiate. If a file needs to be loaded,
28 * the loading is initiated immediately. Completion of load will result in
29 * a COMPLETE event being fired.
30 *
31 * @param pathOrClass Either the path to a .pbj file or the shader bytecode class.
32 */
33 public function ShaderProxy(pathOrClass:Object) {
34 _eventDispatcher = new EventDispatcher();
35 var shaderClass:Class = pathOrClass as Class;
36 // if a class is passed, immediately instantiate it
37   if (shaderClass != null) {
38 createShader(ByteArray(new shaderClass()));
39 // if a file path is passed, immediately load it
40   } else if ((pathOrClass as String) != null) {
41 load(pathOrClass as String);
42 } else {
43 throw new Error("Invalid object passed to constructor.");
44 }
45 }
46
47 /**
48 * Creates the Shader instance from the bytecode.
49 *
50 * @param data The ByteArray containing the shader bytecode.
51 */
52 private function createShader(data:ByteArray):void {
53 _shader = new Shader(data);
54 dispatchEvent(new Event(Event.COMPLETE));
55 }
56
57 /**
58 * Loads the specified .pbj file.
59 *
60 * @param path The path to the .pbj file to load.
61 */
62 private function load(path:String):void {
63 var loader:URLLoader = new URLLoader();
64 loader.dataFormat = URLLoaderDataFormat.BINARY;
65 loader.addEventListener(Event.COMPLETE, onShaderLoaded);
66 loader.load(new URLRequest(path));
67 }
68
69 /**
70 * Handler for when the .pbj file completes loading.
71 *
72 * @param event Event dispatched by URLLoader.
73 */
74 private function onShaderLoaded(event:Event):void {
75 var loader:URLLoader = event.target as URLLoader;
76 createShader(loader.data as ByteArray);
77 }
78
79 /**
80 * Method that will be called any time this class instance is called accessing a property
81 * as an implicit getter that does not exist on this class.
82 *
83 * @param name The name of the property being accessed.
84 *
85 * @return The value for the property, if any, or null.
86 */
87 override flash_proxy function getProperty(name:*):* {
88 if (_shader) {
89 // first, check to see if property is a parameter on the shader
90   var result:Object = getParameter(name);
91 // if it is not a parameter, check to see if it is an input
92   if (result == null) {
93 result = getInput(name);
94 }
95 return result;
96 }
97 return null;
98 }
99
100 /**
101 * Method that will be called any time this class instance is called accessing a property
102 * as an implicit setter that does not exist on this class.
103 *
104 * @param name The name of the property being accessed.
105 * @param value The value for the property being accessed.
106 */
107 override flash_proxy function setProperty(name:*, value:*):void {
108 if (_shader) {
109 // first, check to see if property is a parameter on the shader
110   if (!setParameter(name, value)) {
111 // if it is not a parameter, check to see if it is an input
112   setInput(name, value);
113 }
114 }
115 }
116
117 /**
118 * Returns the value of the property if it is an input property on the shader.
119 *
120 * @param name The name of the input property being accessed.
121 *
122 * @return The value for the input property, if any, or null.
123 */
124 public function getInput(name:String):Object {
125 // only attempt to access the input property name if it is valid for the shader
126 if (_shader.data.hasOwnProperty(name) && _shader.data[name] is ShaderInput) {
127 return _shader.data[name].input;
128 }
129 return null;
130 }
131
132 /**
133 * Sets the value of the property if it is an input property on the shader.
134 *
135 * @param name The name of the input property being accessed.
136 * @param value The value for the input property.
137 *
138 * @return True if the input property existed on the shader.
139 */
140 public function setInput(name:String, value:Object):Boolean {
141 // only attempt to access the input property name if it is valid for the shader
142 if (_shader.data.hasOwnProperty(name) && _shader.data[name] is ShaderInput) {
143 _shader.data[name].input = value;
144 return true;
145 }
146 return false;
147 }
148
149 /**
150 * Returns the value of the specified parameter from the shader.
151 * This method ensures that float and int values are extracted from
152 * the Array that wraps them.
153 *
154 * @param name The name of the parameter to retrieve.
155 *
156 * @return The value of the parameter.
157 */
158 public function getParameter(name:String):Object {
159 // check to see if parameter exists and is a shader parameter
160 if (_shader.data.hasOwnProperty(name) && _shader.data[name] is ShaderParameter) {
161 var value:Object = _shader.data[name].value;
162 var type:String = _shader.data[name].type;
163 // if type is float or int, grab the only value from the array
164 if (type == "float" || type == "int") {
165 value = (value as Array)[0];
166 }
167 return value;
168 }
169 return null;
170 }
171
172 /**
173 * Sets the value of the specified parameter of the shader.
174 * This method ensures that all values are passed as arrays to the shader,
175 * even if the parameter is scalar.
176 *
177 * @param name The name of the parameter to set.
178 * @param value The value to give the parameter.
179 *
180 * @return True if the parameter was found and set.
181 */
182 public function setParameter(name:String, value:Object):Boolean {
183 // check to see if parameter exists and is a shader parameter
184 if (_shader.data.hasOwnProperty(name) && _shader.data[name] is ShaderParameter) {
185 // wrap scalar values in an array
186 if (!(value is Array)) {
187 value = [value];
188 }
189 _shader.data[name].value = value;
190 return true;
191 }
192 return false;
193 }
194
195 /**
196 * Registers an event listener object with an EventDispatcher object
197 * so that the listener receives notification of an event.
198 *
199 * @param type The type of event.
200 * @param listener The listener function that processes the event.
201 * @param useCapture Determines whether the listener works in the capture phase or the target and bubbling phases.
202 * @param priority The priority level of the event listener.
203 * @param useWeakReference Determines whether the reference to the listener is strong or weak.
204 */
205 public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=true):void {
206 _eventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
207 }
208
209 /**
210 * Removes a listener from the EventDispatcher object.
211 *
212 * @param type The type of event.
213 * @param listener The listener object to remove.
214 * @param useCapture Specifies whether the listener was registered for the capture phase or the target and bubbling phases.
215 */
216 public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void {
217 _eventDispatcher.removeEventListener(type, listener, useCapture);
218 }
219
220 /**
221 * Dispatches an event into the event flow.
222 *
223 * @param event The event object dispatched into the event flow.
224 *
225 * @return A value of true unless preventDefault() is called on the event, in which case it returns false.
226 */
227 public function dispatchEvent(event:Event):Boolean {
228 return _eventDispatcher.dispatchEvent(event);
229 }
230
231 /**
232 * Checks whether an event listener is registered with this EventDispatcher object
233 * or any of its ancestors for the specified event type.
234 *
235 * @param type The type of event.
236 *
237 * @return A value of true if a listener of the specified type will be triggered; false otherwise.
238 */
239 public function willTrigger(type:String):Boolean {
240 return _eventDispatcher.willTrigger(type);
241 }
242
243 /**
244 * Checks whether the EventDispatcher object has any listeners registered for a specific type of event.
245 *
246 * @param type The type of event.
247 *
248 * @return A value of true if a listener of the specified type is registered; false otherwise.
249 */
250 public function hasEventListener(type:String):Boolean {
251 return _eventDispatcher.hasEventListener(type);
252 }
253
254 /**
255 * Returns the Shader instance this class wraps.
256 *
257 * @return The Shader instance managed by this class.
258 */
259 public function get shader():Shader {
260 return _shader;
261 }
262
263 }
264
265 }


6. ActionScript in the Third Dimension

AS3 中的内置3D API(仅视觉)

后面还介绍了3D的向量,没数学基础知识和基本3D图形知识的可以看看

里面还讲了一些高级知识

例子pointAt中绘制了一个三角箭头,可以指向3D空间中的任意一点.

实现方法也很简单.(过去我指知道使用Math中的方法去计算角度来指向2D空间中的一点)

后面还给了pointAt的缓动例子

利用interpolateTo的方法实现的.

 

后面还有深度排序的例子

想必从事flash开发的人初学的时候都做过旋转木马式的图片旋转吧...

与这个例子对比:AS3的API慢慢在进化,

过去需要很复杂的实现的东西,现在可以利用api少写非常多的代码

而且新添加的这些东西 都和计算机图形学有很大的联系

 

再后面是一个使用drawTriangle绘制3D图形的

和原来不同的地方是使用了Matrix3D来改变3D坐标点

(素材有一面略暗,刚开始我还以为代码里实现了光照...结果看了素材才发现...在想要节约性能不去实现光照效果 可以考虑用这种方式'欺骗'用户的眼睛)

 

7. Using an Animation and Effects Library

介绍了一个tween的外部库 aeon (可操作动画序列,使用非常简单)

支持api中的矩阵缓动等...

此外还有aether 包括现成的滤镜缓动效果,图像操作...等(扩展特效非常简单)

但我谷哥不到什么内容,也没时间关注这个类.只略略看了下结构

 

最精华的部分还是作者自己写的Mesh3D这个类

写的非常简单易懂,代码量少 ,但是把渲染基本3D图形的框架都搭好了,

可以了解了这个过程后,对于初学其他3D引擎有很大的帮助

PS:我还是第一次见到不使用外部素材,

光使用actionsript 就画出一个带有丰富地表的星球的...

不知道你们有没看过用flash CS用遮罩做的旋转星球,这里就是用代码实现了这种旋转.而且还原度还更高

 

------------------------上面算是技术方面的东西,下面都是运用技术的实例----------------------------------------------------------------------------------
8. Elemental Animation Effects

感觉从这里开始都是一些正点的东西了,必须要自己去看书 执行下代码才能了解发生了些什么

1.动态燃烧字

2.缓动石化

3.旗子飘扬(这个感觉非常的实用,以前我写过水波纹的..这次可以借鉴这个方法优化下我的代码了)

4.下雨和下雪的例子都太生硬了(上面三个特效用的比较多,下雨 下雪还是用自己写的吧)


9. Text Effects

各种艺术字效果()(漂亮的内嵌字体或图片的话体积较大,而作者的方法用代码渲染出各种艺术字体)

代码不难...但是我需要去补习PS才能明白 色彩上发生了一些什么

后面还使用了之前的aeon的缓动做了动画艺术字的效果(从缓动结构来看,aeon做的很容易操作,但效率就不太清楚了)

PS:现在的AS编程都趋向与写逻辑了,广告公司又只要特效...

不知道大家有没时间看下这个 研究研究特效...

毕竟flash在浏览器中最大的优势就是图形渲染


10. Video Effects

将特效应用在视频上

例子没发现什么好借鉴的地方,不过里面包括了扩展aeon类库的新效果类实现的例子,证明aeon非常容易扩展

PS:因为之前做过...所以提醒大家关于draw方法:(有兴趣的话,请在NetStream里寻找下面这段话吧)

'如果从执行调用的 SWF 文件所在的域外部加载视频文件,而且需要使用 BitmapData.draw() 方法对视频进行像素级访问,则将此属性设置为 true。在加载时未将 checkPolicyFile 属性设置为 true 的情况下,如果调用 BitmapData.draw(),可能会收到一个 SecurityError 异常,因为没有下载所需的策略文件。'


11. Sound Visualization Effects

示波器...

(基本知识普及..true 频谱(左256,右256), false 声音波形)

例子做的简单易懂 加 标准...了解foobar DIY的朋友应该不陌生.

后面有个高级例子 做了很绚丽的万花筒效果.(使用了前面说过的aether类中的)

PS:看到这里突然有个想法,这个特效库非常容易扩展

如果能传播开,大家一起开发各种新的特效分享就好了.

刚刚的高级例子只用替换下效果类就可以显示出新的效果示波图了

在以后做这种示波图等 假如没灵感,就可以遍历一遍所有效果 寻找好看的那一个了


12. Interactive Effects ★★★

1.万花筒的例子...稍微加加工 就可以当做游戏玩了...(万花筒的形状 更换非常简单..直接改shape.graphics 就好了)

2. 将1例子中的特效代码直接改变为aether类中的万花筒特效

3.哈哈镜


13. (Appendix) Developing Within Flash and Flex Builder

 

posted @ 2010-07-07 11:15  yinaak  阅读(562)  评论(0编辑  收藏  举报