3D text of fire
注意: Frocessing と Papervision3D が必要です
*
* @author yooKo@selflash
* @version 1.0.0
* @date 2009/10/24
* @see http://selflash.jp/
*
* Please click.
* The flame becomes deformed.
*
* クリックすると炎でできたテキストが変形します
* 変形中は激重いので注意
* 誰かが最適化してくれる事を望む
/**
* Copyright selflash ( http://wonderfl.net/user/selflash )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/wzim
*/
/**
* 注意: Frocessing と Papervision3D が必要です
*
* @author yooKo@selflash
* @version 1.0.0
* @date 2009/10/24
* @see http://selflash.jp/
*
* Please click.
* The flame becomes deformed.
*
* クリックすると炎でできたテキストが変形します
* 変形中は激重いので注意
* 誰かが最適化してくれる事を望む
**/
package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.BlendMode;
import flash.display.DisplayObject;
import flash.display.StageQuality;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.filters.BlurFilter;
import flash.filters.BitmapFilterQuality;
import flash.filters.ColorMatrixFilter;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.events.MouseEvent;
import flash.geom.ColorTransform;
import flash.geom.Point;
import flash.geom.Matrix;
import flash.geom.Rectangle;
import flash.utils.Timer;
import flash.utils.getTimer;
import org.papervision3d.cameras.*;
import org.papervision3d.view.BasicView;
import org.papervision3d.view.layer.ViewportLayer;
import org.papervision3d.view.layer.BitmapEffectLayer;
import org.papervision3d.core.effects.BitmapLayerEffect;
import org.papervision3d.core.effects.BitmapColorEffect;
import org.papervision3d.core.effects.utils.BitmapClearMode;
import org.papervision3d.core.geom.Pixels;
import org.papervision3d.core.geom.renderables.Pixel3D;
import org.papervision3d.objects.DisplayObject3D;
import net.hires.debug.Stats;
import frocessing.color.ColorHSV;
[SWF(width="465", height="465", backgroundColor="0x000000", frameRate="60")]
public class FireText3D extends BasicView {
private var _container:DisplayObject3D;
private var _pixels:Pixels;
private var _particles:Array/*Particle*/ = [];
private var _startTime:int;
private var _textW:Number;
private var _textH:Number;
private var _bmd:BitmapData;
private var _currentNum:int = 0;
private var _count:int = 0;
//========================================================================
// constructor
//========================================================================
public function FireText3D() {
super(0, 0, true, false);
init();
}
//========================================================================
// init
//========================================================================
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
stage.quality = StageQuality.LOW;
camera.z = -80;
var _layer:BitmapEffectLayer = new BitmapEffectLayer(viewport, stage.stageWidth * 0.8, stage.stageHeight, true, 0, BitmapClearMode.CLEAR_PRE, false);
viewport.containerSprite.addLayer(_layer);
//_layer.addEffect(new BitmapColorEffect(1, 1, 1, .7));
_layer.addEffect(new BitmapLayerEffect(new BlurFilter(10, 10, BitmapFilterQuality.LOW), true));
_layer.addEffect(new BitmapLayerEffect(new ColorMatrixFilter([1.1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0])));
_pixels = new Pixels(_layer);
_layer.addDisplayObject3D(_pixels);
_container = scene.addChild(new DisplayObject3D());
_container.addChild(_pixels);
createText();
createBody(0, .2, 0xFF000000);
//perlinNoise は 重い為縦を3倍の長さでBitmapDataを作成する
_bmd = new BitmapData(465, 465 * 3.5, false, 0x00000000);
stage.addEventListener(MouseEvent.CLICK, onClickHandler);
upDate();
startRendering();
stage.addChild(new Stats());
}
//========================================================================
// createText
//========================================================================
private function createText():void {
var tf:TextField = new TextField();
tf.defaultTextFormat = new TextFormat("小塚ゴシック Pro H", 18, 0x000000, true);
tf.autoSize = TextFieldAutoSize.LEFT;
tf.text = "FIRE";
_textW = tf.textWidth;
_textH = tf.textHeight;
_bmd = new BitmapData(_textW + 5, _textH + 5, false, 0xFFFFFF);
_bmd.draw(tf);
}
//========================================================================
// onClickHandler
//========================================================================
private function onClickHandler(e:MouseEvent = null):void {
_startTime = getTimer();
(_currentNum < 3) ? _currentNum++ : _currentNum = 0;
}
//========================================================================
// onEnterFrameHandler
//========================================================================
private var _rotateX:Number = 0;
private var _rotateY:Number = 0;
override protected function onRenderTick(event:Event = null):void {
super.onRenderTick();
drawEffect();
switch (_currentNum) {
case 1:
collapsesAnimation();
upDate();
break;
case 3:
revivalAnimation();
upDate();
break;
}
_count++;
_rotateX += (stage.mouseX - stage.stageWidth * 0.5 - _rotateX) * 0.1;
_rotateY += (stage.mouseY - stage.stageHeight * 0.5 - _rotateY) * 0.1;
_pixels.rotationY = _rotateX * 0.5;
_pixels.rotationX = _rotateY * 0.5;
}
//========================================================================
// drawEffect
//========================================================================
private var _offset:Array = [new Point(), new Point()];
private const DRAW_MATRIX:Matrix = new Matrix(1, 0, 0, 1, 0, 0);
private function drawEffect():void {
_bmd.lock();
//_countが100の倍数の時だけperlinNoise!
if (_count % 240 == 0)_bmd.perlinNoise(30, 50, 1, 0, false, false, 0, true, _offset);
_bmd.scroll(0, -5);
_pixels.layer.canvas.lock();
_pixels.layer.canvas.draw(_bmd, DRAW_MATRIX, null, BlendMode.SUBTRACT);
_pixels.layer.canvas.scroll(0, -5);
_pixels.layer.canvas.unlock();
_bmd.unlock();
}
//========================================================================
// 再生アニメーション
//========================================================================
private function revivalAnimation():void {
var now:int = getTimer();
var len:int = _particles.length;
for (var i:int = 0; i < len; i++) {
var p:Particle = _particles[i];
var x_delay:Number = (1 - ((p.tx + _textW * .5) / _textW )) * 5000;
var y_delay:Number = (1 - ((p.ty + _textH * .5) / _textH )) * 500;
var z_delay:Number = (1 - ((p.tz + 6) / 12 )) * 1000;
var delay:Number = x_delay + y_delay + z_delay;
if (_startTime + delay > now) continue ;
//Math.absの高速化?
var xx:Number = p.tx - p.x;
var yy:Number = p.ty - p.y;
var zz:Number = p.tz - p.z;
var x:Number = (xx < 0)?xx * -1:xx;
var y:Number = (yy < 0)?yy * -1:yy;
var z:Number = (zz < 0)?zz * -1:zz;
if (x < .5 && y < .5 && z < .5) {
p.x = p.tx;
p.y = p.ty;
p.z = p.tz;
p.r = 20;
p.degree = 10;
p.c += (p.tc - p.c) * .2;
}else {
p.x += (p.tx - p.x) * .08;
p.y += (p.ty - p.y) * .08;
p.z += (p.tz - p.z) * .08;
color.h = (getTimer() / 20000) * 360;
p.c = rgb2argb(color.value, 1);
if (p.r > 3) {
p.x += ((p.x + p.r * Math.sin(Math.PI / 180 * p.degree)) - p.x) * .1;
p.y += ((p.y + p.r * Math.cos(Math.PI / 180 * p.degree)) - p.y) * .1;
p.z += ((p.z + p.r * Math.sin(Math.PI / 180 * p.degree)) - p.z) * .1;
}
if (p.r > 0) p.r -= .3;
p.degree += 10;
}
}
}
//========================================================================
// collapsesAnimation
//========================================================================
private var color:ColorHSV = new ColorHSV(0, 0.5);
private function collapsesAnimation():void {
var now:int = getTimer();
var len:int = _particles.length;
for (var i:int = 0; i < len; i++) {
var p:Particle = _particles[i];
var x_delay:Number = (1 - ((p.tx + _textW * .6) / _textW )) * 5000;
var y_delay:Number = (1 - ((p.ty + _textH * .8) / _textH )) * 500;
var z_delay:Number = (1 - ((p.tz + 8 * .5) / 8 )) * 1000;
var delay:Number = x_delay + y_delay + z_delay;
if (_startTime + delay > now) continue ;
//Math.absの高速化?
var xx:Number = p.ex - p.x;
var yy:Number = p.ey - p.y;
var zz:Number = p.ez - p.z;
var x:Number = (xx < 0)?xx * -1:xx;
var y:Number = (yy < 0)?yy * -1:yy;
var z:Number = (zz < 0)?zz * -1:zz;
if (x < .5 && y < .5 && z < .5) {
p.x = p.ex;
p.y = p.ey;
p.z = p.ez;
p.r = 20;
p.degree = 10;
}else {
p.x += (p.ex - p.x) * .08;
p.y += (p.ey - p.y) * .08;
p.z += (p.ez - p.z) * .08;
if (p.r > 3) {
p.x += ((p.ex + p.r * Math.cos(Math.PI / 180 * p.degree)) - p.x) * .1;
p.y += ((p.ey + p.r * Math.cos(Math.PI / 180 * p.degree)) - p.y) * .1;
p.z += ((p.ez + p.r * Math.sin(Math.PI / 180 * p.degree)) - p.z) * .1;
}
if (p.r) p.r -= .3;
p.degree += 10;
}
}
}
//========================================================================
// Particleが保持している情報を元にPixelsにaddPixel3D()
//========================================================================
private var _pixel3Ds:Array/*Pixel3D*/ = [];
private function upDate():void {
_pixels.removeAllpixels();
var len:int = _particles.length;
for (var i:int = 0; i < len; i++) {
var p:Particle = _particles[i];
var px:Pixel3D;
color.h = (getTimer() / 5000) * 360;
var c:int = rgb2argb(color.value, 1);
if (_pixel3Ds[i]) {
px = _pixel3Ds[i];
px.color = c;
px.x = p.x;
px.y = p.y;
px.z = p.z;
}else {
_pixel3Ds[i] = new Pixel3D(rgb2argb(0xEFDD6D, 1), p.x, p.y, p.z);
};
px = _pixel3Ds[i];
_pixels.addPixel3D(px);
}
}
//========================================================================
// createBody
//========================================================================
private var _c:uint;
private function createBody(depth:Number = 0, distance:Number = 2, color:Number = NaN):void {
var p:Particle;
var w:Number = _textW * .5;
var h:Number = _textH * .4;
for (var i:int = 0, _y:Number = 0; _y < _textH; _y += distance ) {
for (var _x:Number = 0; _x < _textW; _x += distance ) {
_c = _bmd.getPixel( _x, _y );
if (_c != 0xFFFFFF) {
_c = (color)?color:rgb2argb(_c, 1);
p = _particles[i] || new Particle();
p.c = _c;
p.x = _x - w;
p.y = - _y + h;
p.z = depth;
p.tx = p.x;
p.ty = p.y;
p.tz = p.z;
p.tc = p.c;
_particles[i] = p;
i++;
}
}
}
}
//========================================================================
// RGBをARGBに変換する
//========================================================================
private function rgb2argb(rgb:uint, alpha:Number):uint {
return ((alpha * 0xff) << 24) + rgb;
}
}
}
//========================================================================
// 座標、色情報を保持するクラス
//========================================================================
class Particle {
public var x:Number;
public var y:Number;
public var z:Number;
public var c:int;
public var tx:Number;
public var ty:Number;
public var tz:Number;
public var tc:int;
public var ex:Number = (Math.random() - .5) * 2;
public var ey:Number = (Math.random() - .5) * 2 - 30;
public var ez:Number = (Math.random() - .5) * 2;
public var ec:int;
public var r:Number = 2;
public var degree:Number = 5;
}