In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

forked from: forked from: forked from: Lorenz Attractor - forked from: nengafl

こうですか!

Lorenz Attractor
@author Hiiragi

ビギナーの人が楽しめるのがルールということなので、考えてみたんですが、
Flashを始めて最初に衝撃を受けたのが、このきれいな模様を描いていく作品でした。
あまりの綺麗さに、ずっと見とれていた記憶があります。今でもそうですけど。
50 - 52行目の定数の値を弄ると動きが変わりますので
よかったら、ForkするなりDownloadするなりで試してみてください。

最近いろいろ凹み気味なので、初心を忘れないためにも、挑戦してみました。
なお、参考サイトをかなり参考にしました。(高校数学サボってた人なので数式判らん)
計算式は弄りようがないので、ほぼそのままです。

本当はcopyPixelsの第4引数以降のアルファを適用して、
奥に行くほどにアルファ値を下げるとかしたかったのですが、うまくいきませんでした・・・。

参考
http://www.procreo.jp/labo/labo08.html
http://ton-up.net/blog/archives/92
/**
 * Copyright zaltech ( http://wonderfl.net/user/zaltech )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/8EPa
 */

// forked from uwi's forked from: forked from: Lorenz Attractor - forked from: nengafl
// forked from uwi's forked from: Lorenz Attractor - forked from: nengafl
// forked from Hiiragi's Lorenz Attractor - forked from: nengafl
// forked from nengafl's nengafl
package 
{
    import net.hires.debug.Stats;

        import org.papervision3d.view.BasicView;
        import flash.events.MouseEvent;
        import flash.events.Event;
        import org.papervision3d.core.geom.*;
        import org.papervision3d.core.geom.renderables.*;
        import org.papervision3d.materials.special.*;
        import org.papervision3d.core.math.*;
        import org.papervision3d.view.layer.*;
        import frocessing.color.*;
    
        // こうですか!
    /**
     * Lorenz Attractor
     * @author Hiiragi
     * 
     * ビギナーの人が楽しめるのがルールということなので、考えてみたんですが、
     * Flashを始めて最初に衝撃を受けたのが、このきれいな模様を描いていく作品でした。
     * あまりの綺麗さに、ずっと見とれていた記憶があります。今でもそうですけど。
     * 50 - 52行目の定数の値を弄ると動きが変わりますので
     * よかったら、ForkするなりDownloadするなりで試してみてください。
     * 
     * 最近いろいろ凹み気味なので、初心を忘れないためにも、挑戦してみました。
     * なお、参考サイトをかなり参考にしました。(高校数学サボってた人なので数式判らん)
     * 計算式は弄りようがないので、ほぼそのままです。
     *
     * 本当はcopyPixelsの第4引数以降のアルファを適用して、
     * 奥に行くほどにアルファ値を下げるとかしたかったのですが、うまくいきませんでした・・・。
     * 
     * 参考
     * http://www.procreo.jp/labo/labo08.html
     * http://ton-up.net/blog/archives/92
     * 
     */
    
    [SWF(width = 465, height = 465, frameRate = 120, backgroundColor = 0x000000)]
    public class Main extends BasicView
    {
        //公式に使われる定数
        private var _p:Number = 10;
        private var _r:Number = 28;
        private var _b:Number = 8 / 3;
        
        //時間単位
        private var _d:Number = 0.003;
        
        //現在の座標を保持する変数
        private var _nowX:Number = Math.random();
        private var _nowY:Number = Math.random();
        private var _nowZ:Number = Math.random();

                private var _pixels : Pixels;
        
        public function Main():void 
        {
                        Wonderfl.capture_delay(20);
                        super(0, 0, true, false);
                        
                        graphics.beginFill(0x000000);
                        graphics.drawRect(0, 0, 465, 465);
                        graphics.endFill();
            
                        var bel : BitmapEffectLayer = new BitmapEffectLayer(viewport, 465, 465, false, 0, "clear_pre", false, true);
                        viewport.containerSprite.addLayer(bel);
                        
                   _pixels = new Pixels(bel, "dots");

                        scene.addChild(_pixels);
            
                        _camera = new SphereCamera(new Number3D(0, 0, 30), 60, new Number3D(0, 0, 1), new Number3D(0, 1, 0));
                        startRendering();

            //debug
            this.addChild(new Stats());
            
                        stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            
        }

        override protected function onRenderTick(e : Event = null) : void
        {
            for(var i : uint = 0;i < 10;i++){
                process();
            }
                        
            super.onRenderTick(e);
        }
        
        private function process() : void
        {
            //LorenzAttractorの公式
            //http://ja.wikipedia.org/wiki/%E3%83%AD%E3%83%BC%E3%83%AC%E3%83%B3%E3%83%84%E6%96%B9%E7%A8%8B%E5%BC%8F
            var dx : Number = _p * (_nowY - _nowX);
                var dy : Number = _nowX * (_r - _nowZ) - _nowY;
            var dz : Number = _nowX * _nowY - _b * _nowZ;
            
            //現在の座標に適用(3Dを作り方を知らないので、Z軸は結局使ってない)
            _nowX += _d * dx;
            _nowY += _d * dy;
            _nowZ += _d * dz;
            
                        _hsv.hsv(_nowX * 12, 1, 1);
                        _pixels.addPixel3D(new Pixel3D(_hsv.value, _nowX, _nowY, _nowZ));
                        
                        if(_pixels.pixels.length > 20000){
                            var rp : Pixel3D = _pixels.pixels[0];
                            _pixels.removePixel3D(rp);
                        }
    }

        private var _hsv : ColorHSV = new ColorHSV();

        private var _prevX : Number = 0;
        private var _prevY : Number = 0; 
        
        private function onMouseMove(e : MouseEvent) : void
        {
            if(!(_camera is SphereCamera))return;
            if(e.buttonDown){
                // ボタンをおしている状態のときのみカメラを移動
                if(_prevX != 0 && _prevY != 0){
                    var sc : SphereCamera = SphereCamera(_camera);
                    // 直前との差分だけ移動
                    sc.move((stage.mouseX - _prevX) * 0.005, (stage.mouseY - _prevY) * 0.005);
                }
                _prevX = stage.mouseX;
                _prevY = stage.mouseY;
            }else{
                _prevX = 0;
                _prevY = 0;
            }
        }
    }
    
}

import org.papervision3d.core.math.*;
import org.papervision3d.objects.*;
import org.papervision3d.cameras.*;
// ジンバルロックを解消した以外はCamera3Dと同じ
class QCamera3D extends Camera3D
{
    public var _up : Number3D; // カメラの上の向きの単位ベクトル
    protected var _front : Number3D;
    private var _prevDir : Number3D;
    private var _ltarg : DisplayObject3D;
    
    public function QCamera3D(up : Number3D, front : Number3D = null)
    {
        super();
        _up = null;
        _ltarg = new DisplayObject3D();
        init(up, front);
    }
    
    // prevDirからcurDirへ向ける回転を_upにかけるだけ。カメラ自体に操作はしない
    public function rotate(curDir : Number3D) : void
    {
        if(_prevDir != null){
            var n : Number3D = Number3D.cross(_prevDir, curDir);
//            if(n.moduloSquared > 0.00000001){
            if(n.moduloSquared != 0){
                n.normalize();
                var angle : Number = Math.acos(Number3D.dot(_prevDir, curDir));
                if(_front != null){
                    var a : Array = applyQuaternion([_front, _up], n, angle);
                    _front = a[0];
                    _up = a[1];
                }else{
                    _up = applyQuaternion([_up], n, angle)[0];
                }
            }
            _prevDir.copyFrom(curDir);
        }else{
            _prevDir = curDir.clone();
        }
    }
    
    // カメラの右方向へx[rad], 上方向へy[rad]回転させる
    public function rotateXY(x : Number, y : Number) : void
    {
        if(_front == null)return;
        
        // X方向の移動
        _front = applyQuaternion([_front], _up, -x)[0];
        
        // Y方向の移動
        var right : Number3D = Number3D.cross(_up, _front);
        right.normalize();
        var ret : Array = applyQuaternion([_front, _up], right, y);
        _front = ret[0];
        _up = ret[1];
    }
    
    public function head() : void
    {
        if(_front != null){
            // まわりくどい
            var ltpos : Number3D = this.position.clone();
            ltpos.plusEq(_front);
            _ltarg.position = ltpos;
            this.lookAt(_ltarg, _up);
        }
    }
    
    public function init(up : Number3D = null, front : Number3D = null) : void
    {
        if(up != null){
            _up = up.clone();
            _up.normalize();
        }
        if(front != null){
            _front = front.clone();
            _front.normalize();
        }else{
            _front = null;
        }
        _prevDir = null;
    }
    
    // axisを軸にangle回転させる変換を、srcsの要素それぞれに適用する
    public static function applyQuaternion(srcs : Array, axis : Number3D, angle : Number) : Array
    {
        var q : Quaternion = Quaternion.createFromAxisAngle(
            axis.x / axis.modulo, 
            axis.y / axis.modulo, 
            axis.z / axis.modulo,
            angle
            );
        var qc : Quaternion = Quaternion.conjugate(q);
        
        var ret : Array = [];
        for each(var src : Number3D in srcs){
            var qSrc : Quaternion = new Quaternion(src.x, src.y, src.z, 0);
            var qDst : Quaternion = Quaternion.multiply(qc, qSrc);
            qDst.mult(q);
            ret.push(new Number3D(qDst.x, qDst.y, qDst.z));
        }
        return ret;
    }
    
}
// 球面上を動き、球の中心を見るカメラ
class SphereCamera extends QCamera3D
{
    private var _O : DisplayObject3D; // 球の中心
    private var _R : Number; // 球の半径
    
    public function SphereCamera(O : Number3D, R : Number, front : Number3D, up : Number3D) : void
    {
        super(up, front);
        _O = new DisplayObject3D();
        _O.x = O.x;
        _O.y = O.y;
        _O.z = O.z;
        _R = R;
        move();
    }
    
    public function move(x : Number = 0, y : Number = 0) : void
    {
        rotateXY(x, y);
        this.x = _front.x * -_R + _O.x;
        this.y = _front.y * -_R + _O.y;
        this.z = _front.z * -_R + _O.z;
        this.lookAt(_O, _up);
    }
}