Beautifl - Flash Gallery

Preview

布いじり3D
novogrammer 2010年3月28日 All rights reserved
?
布シミュをいじってみる by NOVO  
動作が変わってしまうのでfork  
ToDo 3Dにしてみたい(見た目)  
Done 3Dにしてみたい(計算)  
ToDo 単位系をそろえる  
Done Fの計算が終わる前にXを動かしているのが偏りの原因っぽい  
Done せん断抵抗、角度抵抗用のJointを設定したい  
ToDo 微小時間でシミュレート  
ToDo 積分法を変えてみる?  
Done 初期化変更、必要ない変数も消す。描画方法もJointの描画だけでいいのでは?  
Done 片方向のJointを両方向に変更(力の計算場所も変更)  
Done ダンパ力を設定  
Done 簡易ベクトルクラスに置き換え  
Done ばねの自然長計算を変更  
以下オリジナルコメント  
  
GraphicsPathCommandでラインを描画するバージョン。  
drawLine関数の中が違います。  
 
本格的な布のシミュレーションではありません。  
  
ドラッグでマウスに一番近いポイントを移動させる。  
ctrlキー押しながらドラッグで固定。  
ダブルクリックで固定を解除。
      /**
 * 布シミュをいじってみる by NOVO
 * 動作が変わってしまうのでfork
 * ToDo 3Dにしてみたい(見た目)
 * Done 3Dにしてみたい(計算)
 * ToDo 単位系をそろえる
 * Done Fの計算が終わる前にXを動かしているのが偏りの原因っぽい
 * Done せん断抵抗、角度抵抗用のJointを設定したい
 * ToDo 微小時間でシミュレート
 * ToDo 積分法を変えてみる?
 * Done 初期化変更、必要ない変数も消す。描画方法もJointの描画だけでいいのでは?
 * Done 片方向のJointを両方向に変更(力の計算場所も変更)
 * Done ダンパ力を設定
 * Done 簡易ベクトルクラスに置き換え
 * Done ばねの自然長計算を変更
 * 以下オリジナルコメント
 */
// forked from miniapp's GraphicsPathCommand使ったバージョン  forked from: 布
/**
 * GraphicsPathCommandでラインを描画するバージョン。
 * drawLine関数の中が違います。
 *
 * 本格的な布のシミュレーションではありません。
 * 
 * ドラッグでマウスに一番近いポイントを移動させる。
 * ctrlキー押しながらドラッグで固定。
 * ダブルクリックで固定を解除。
 */
package {
    import flash.display.GraphicsPathCommand;
    import flash.display.Sprite;
    import flash.display.StageQuality;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import net.hires.debug.Stats;

    [SWF(backgroundColor="0xFFFFFF", width="465", height="465", frameRate="60")]
    public class Cloth_DrawPath extends Sprite {
        
        public static const STAGE_WIDTH:uint = 465;
        public static const STAGE_HEIGHT:uint = 465;
        
        public function Cloth_DrawPath() {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private var _lineColor:uint = 0x000000;
        private var _cols:uint = 16;//横の数
        private var _rows:uint = 16;//縦の数
        private var _diffX:uint = 10;
        private var _diffY:uint = 10;
        private var _isCtrlPress:Boolean = false;
        private var _isMouseDown:Boolean = false;
        private var _draggedPoint:Point;
        private var _isFirst:Boolean = false;
        //private var _numJoints:uint;
        private var _joints:Vector.<Joint> = new Vector.<Joint>();
        private var _points:Vector.<Point> = new Vector.<Point>();
        //private var _pointsXs:Vector.<Vector.<Point>> = new Vector.<Vector.<Point>>(_rows, true);
        //private var _pointsYs:Vector.<Vector.<Point>> = new Vector.<Vector.<Point>>(_cols, true);
        
        private var _vertices:Vector.<Number> = new Vector.<Number>();
        private var _commands:Vector.<int> = new Vector.<int>();
        
        private function init(e:Event = null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            stage.scaleMode = StageScaleMode.NO_SCALE;
            //stage.quality = StageQuality.MEDIUM;
            
            stage.doubleClickEnabled = true;
            stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDwonHandler);
            stage.addEventListener(MouseEvent.DOUBLE_CLICK, doubleClickHandler);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDonwHandler);
            stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
            
            //putPoint();
            //joint();
            putPointAndJoint();
            
            //上端2つを固定します。
            //左端
            var point1:Point = _points[0];
            point1._position=new MyVector3D(100,10,0);
            point1.isPinned = true;
            
            //右端
            var point2:Point = _points[_rows - 1];
            point2._position=new MyVector3D(STAGE_WIDTH - 100,10,100);//ちょっと奥行きをつけてみる
            point2.isPinned = true;
            
            addEventListener(Event.ENTER_FRAME, enterFrameHandler);
            addChild(new Stats());
        }
        /**
         *
         *
         */
        private function putPointAndJoint():void
        {
            var clothWidth:Number = (_cols - 1) * _diffX;
            var clothHeight:Number = (_rows - 1) * _diffY;
            var startX:Number = (STAGE_WIDTH - clothWidth) / 2;
            var startY:Number = (STAGE_HEIGHT - clothHeight) / 2;
            
            //ポイントとジョイントを一気に配置したほうが楽なので
            for(var y:uint=0;y<_rows;++y)
            {
                for(var x:uint=0;x<_cols;++x)
                {
                    var point:Point=new Point();
                    _points.push(point);
                    point.name = String(y) + "-" + String(x);//デバッグ用
                    var noize:Number = Math.random()*10;//0から1
                    point._position=new MyVector3D(startX + _diffX * x,startY + _diffY * y,noize);
                    
                    if(y>0)
                    {
                        var pointUp:Point=_points[(y-1)*_cols+x];
                        _joints.push(new Joint(point, pointUp));//たて
                        if (x > 0)
                        {
                            var pointNaname1:Point=_points[(y-1)*_cols+(x-1)];
                            _joints.push(new Joint(point, pointNaname1));//ななめ1
                        }
                        if (x < _cols -1)
                        {
                            var pointNaname2:Point=_points[(y-1)*_cols+(x+1)];
                            _joints.push(new Joint(point, pointNaname2));//ななめ2
                        }
                    }
                    if(x>0)
                    {
                        var pointLeft:Point=_points[y*_cols+(x-1)];
                        _joints.push(new Joint(point,pointLeft));//よこ
                    }
                    if(y>1)
                    {
                        var pointUp2:Point=_points[(y-2)*_cols+x];
                        _joints.push(new Joint(point, pointUp2));//たて ひとつ飛ばし
                    }
                    if(x>1)
                    {
                        var pointLeft2:Point=_points[y*_cols+(x-2)];
                        _joints.push(new Joint(point,pointLeft2));//よこ
                    }
                    
                }
            }
            trace("_poinits.length"+_points.length);
            trace("_joints.length"+_joints.length);
            _points.fixed=true;
            _joints.fixed=true;
        }
            
        
        /**
         * 一番カーソルに近いポイントを捜す。
         */
        private function searchPoint():Point {
            var lastMinDist:Number = Infinity;
            var target:Point;
            for each(var point:Point in _points) {
                var pos:MyVector3D = point._position;
                var m:MyVector3D=new MyVector3D(mouseX,mouseY,0.0);
                var dist:Number = pos.subtract(m).length();
                if (dist < lastMinDist) {
                    lastMinDist = dist;
                    target = point;
                }
            }
            return target;
        }
        
        /**
         * バネの線を書く
         */
        private function drawLine():void {
            graphics.clear();
            graphics.lineStyle(1, _lineColor);
            
            var dataIndex:uint = 0;
            var commandIndex:uint = 0;
            for each(var joint:Joint in _joints)
            {
                var pointA:Point=joint._point;
                var pointB:Point=joint._target;
                _vertices[dataIndex++] = pointA._position.x;
                _vertices[dataIndex++] = pointA._position.y;
                _commands[commandIndex++] = GraphicsPathCommand.MOVE_TO;
                _vertices[dataIndex++] = pointB._position.x;
                _vertices[dataIndex++] = pointB._position.y;
                _commands[commandIndex++] = GraphicsPathCommand.LINE_TO;
            }
            
            if(_isFirst){
                _commands.fixed = _vertices.fixed = true;
                _isFirst = false;
            }
            graphics.drawPath(_commands, _vertices);
        }
        
        private function enterFrameHandler(e:Event):void {
            if (_isMouseDown) {
                _draggedPoint._position.x = mouseX;
                _draggedPoint._position.y = mouseY;
            }
            //フェーズを二つに分ける。力更新と位置更新
            // update force
            for each(var joint1:Joint in _joints) {
                joint1.updateForce();
            }
            for each(var point1:Point in _points) {
                point1.updateForce();//多分下のループに入れても影響はないけど、明示的に分ける。
            }
            // update position
            for each(var point2:Point in _points) {
                point2.updatePosition();
            }
            
            drawLine();
        }
        
        private function keyDonwHandler(e:KeyboardEvent = null):void{
            if(e.ctrlKey) _isCtrlPress = true;
        }
        
        private function keyUpHandler(e:KeyboardEvent = null):void{
            _isCtrlPress = false;
        }
        
        private function doubleClickHandler(e:MouseEvent = null):void{
            searchPoint().isPinned = false;
        }
        
        private function mouseDwonHandler(e:MouseEvent):void {
            _isMouseDown = true;
            _draggedPoint = searchPoint();
            _draggedPoint.isDragging = true;
        }
        
        private function mouseUpHandler(e:MouseEvent):void    {
            _isMouseDown = false;
            if (_isCtrlPress)
                _draggedPoint.isPinned = true;
            _draggedPoint.isDragging = false;
            _draggedPoint = undefined;
        }
    }
}

//簡易ベクトルクラス
class MyVector3D
{
    public var x:Number = 0.0;
    public var y:Number = 0.0;
    public var z:Number = 0.0;
    public function MyVector3D(inX:Number=0.0, inY:Number=0.0,inZ:Number=0.0)
    {
        x = inX;
        y = inY;
        z = inZ;
    }
    //+=
    public function addTo(rhs:MyVector3D):MyVector3D
    {
        this.x += rhs.x;
        this.y += rhs.y;
        this.z += rhs.z;
        return this;
    }
    //+
    public function add(rhs:MyVector3D):MyVector3D
    {
        return new MyVector3D(this.x + rhs.x, this.y + rhs.y, this.z + rhs.z);
    }
    //-=
    public function subtractTo(rhs:MyVector3D):MyVector3D
    {
        this.x -= rhs.x;
        this.y -= rhs.y;
        this.z -= rhs.z;
        return this;
    }
    //-
    public function subtract(rhs:MyVector3D):MyVector3D
    {
        return new MyVector3D(this.x - rhs.x, this.y - rhs.y, this.z - rhs.z);
    }
    //*=
    public function multiplyTo(rhs:Number):MyVector3D
    {
        this.x *= rhs;
        this.y *= rhs;
        this.z *= rhs;
        return this;
    }
    //*
    public function multiply(rhs:Number):MyVector3D
    {
        return new MyVector3D(this.x*rhs,this.y*rhs,this.z*rhs);
    }
    ///=
    public function divideTo(rhs:Number):MyVector3D
    {
        this.x /= rhs;
        this.y /= rhs;
        this.z /= rhs;
        return this;
    }
    ///
    public function divide(rhs:Number):MyVector3D
    {
        return new MyVector3D(this.x/rhs,this.y/rhs,this.z/rhs);
    }

    public function length2():Number
    {
        return this.x * this.x + this.y * this.y+ this.z * this.z;
    }
    public function length():Number
    {
        return Math.sqrt(length2());
    }
    //単位ベクトル
    public function normalize():MyVector3D
    {
        return this.divide(this.length());
    }
}

class Joint {
    
    public static var SPRING:Number = 0.03;
    public static var DAMPER:Number = 0.005;
    
    public var _naturalLength:Number = 0.0;
    
    public var _point:Point=null;
    public var _target:Point=null;
    
    public function Joint(point:Point, target:Point) { 
        _point=point;
        _target = target;
        _naturalLength = _point._position.subtract(_target._position).length();
        //trace(_naturalLength);
    }
    public function updateForce():void
    {
        //バネの力
        var dx:MyVector3D = _target._position.subtract(_point._position);
        var nx:MyVector3D = dx.normalize();//単位ベクトル
        var springForce:MyVector3D = nx.multiply((dx.length() - _naturalLength) * Joint.SPRING);
        
        //ダンパの力
        var dv:MyVector3D = _target._velocity.subtract(_point._velocity);
        var damperForce:MyVector3D = dv.multiply(DAMPER);
        
        //合力
        var totalForce:MyVector3D = springForce.add(damperForce);
        _point._force.addTo(totalForce);
        //逆の力をかける
        _target._force.addTo(totalForce.multiply(-1));
        
    }
}

class Point {
    public var name:String;
    public var _position:MyVector3D = new MyVector3D();
    public var _velocity:MyVector3D = new MyVector3D();
    public var _force:MyVector3D = new MyVector3D();
    public var mass:Number=0.3;
    public var isPinned:Boolean = false;
    public var isDragging:Boolean = false;
    public static var GRAVITY:Number = 0.005;
    public static var AIR_FRICTION:Number = 0.0005;
    public function updateForce():void
    {
        _force.y += GRAVITY;
        _force.addTo(_velocity.multiply(AIR_FRICTION*-1));
    }
    public function updatePosition():void
    {
        if (isDragging || isPinned)
        {
            _velocity = new MyVector3D();
            _force = new MyVector3D();
        }
        else
        {
            _velocity.addTo(_force.divide(mass));
            _force = new MyVector3D();
            _position.addTo(_velocity);
        }
    }
}