最近一直在学习 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