Страницы

3.7.14

3D динамический Аттрактор Лоренца во Flash AS3 без матриц преобразований / 3D Lorenz attractor dynamic

Всем привет. Хочу поделиться с Вами своими навыками работы с 3D во Flash ActionScript3.
Естественно простому человеку сложно освоить принципы работы с 3D и его отображения на экране в силу таких понятий как перспектива, проецирование, точка исчезновения, отбор, матрица преобразования, вектор., то что в реальной жизни предопределено для всех объектов природой и над этим никогда не приходилось ломать голову. И ломать мы её не будем, а перейдем сразу к результату.
Целью и первой успешной попыткой 3D построения с помощью средств ActionScript3 явилась красивая и завораживающая система Лоренца, называемая аттрактором Лоренца, которую я разместил на deviantart.com (нажмите на ссылку чтобы это увидеть). У этой системы очень интересное поведение при изменении параметров и я задался вопросом, как это сделать интерактивным и простым в использовании... и вуаля.

Используя за основу код из Вики, приведенный в качестве примера для JavaScript и HTML5 с небольшой коррекцией появился вот такой код для AS3 (вы можете просто запустить Adobe Flash, создать файл AS3, вставить код в пустой кадр и скомпилировать ролик):



import flash.events.MouseEvent;
import flash.display.Sprite;
import flash.events.KeyboardEvent;

var spriteNames:Array = new Array();

activateAttractor(0.01, 5, 500, spriteNames);
//activateAttractor(dt- время, a - коэффициент, количество объектов, массив имён)

function activateAttractor(dt:Number, a:Number, n:Number, spriteNames:Array){
    var container:Sprite = new Sprite();//создаем контейнер для будующих точек
    var centerProection:Sprite = new Sprite();/*создаем спрайт для последующего построения проэкций точек и рисования линии*/
    container.name = "container";
    stage.addChild(container);
    container.addChild(centerProection);
    container.x = stage.stageWidth/2;//размещаем по центру
    container.y = stage.stageHeight/2;
    //исходное значение коэффициентов
    var b:Number = -57.8;
    var c:Number = -818;
    //координаты начала построения
    var X:Number = 3.051522;
    var Y:Number = 1.582542;
    var Z:Number = 15.62388;
  
    for (var i=0; i<=n; i++) {
        var spr:Sprite = new Sprite();
        spr.name = "spr"+i;
        spriteNames.push("spr"+i);
        var clr = 0xfedcba;
        spr.graphics.beginFill(clr*i,1);
        spr.graphics.drawCircle(0,0,2);
        spr.graphics.endFill();
        container.addChild(spr);
//здесь для пущей красоты вы можете добавить фильтры для точек (размытие, свечение)
        spr.x = X;
        spr.y = Y;
        spr.z = Z;               
        attractorCoord(spr, a, b, c, dt)
        X = spr.x;
        Y = spr.y;
        Z = spr.z;
    }
    dotReplacer(spriteNames, container, a, b, c, dt);
    //прослушиватели событий мыши и клавиатуры
    stage.addEventListener(MouseEvent.MOUSE_MOVE, rotator);
    stage.addEventListener(MouseEvent.MOUSE_WHEEL, scaler);
    stage.addEventListener(KeyboardEvent.KEY_DOWN, presskeyDown);
   
    function presskeyDown(e:KeyboardEvent){
        trace (e.keyCode);       
        if (e.keyCode == 87){// клавиша W - для увеличения коэфф. с
            c +=0.1;
            trace ("> +c ");
            dotReplacer(spriteNames, container, a, b, c, dt);
        }else if (e.keyCode == 83){// клавиша S - для уменьшения коэфф. с
            c-=0.1;
            trace ("> -c ");
            dotReplacer(spriteNames, container, a, b, c, dt);
        }else if (e.keyCode == 68){// клавиша D - для увеличения коэфф. b
            b+=0.1;
            trace ("> +b ");
            dotReplacer(spriteNames, container, a, b, c, dt);
        }else if (e.keyCode == 65){// клавиша A - для уменьшения коэфф.b
            b-=0.1;
            trace ("> -b ");
            dotReplacer(spriteNames, container, a, b, c, dt);
    }}
    function scaler(e:MouseEvent){//функция масштабирования
        container.scaleX +=e.delta/100;
        container.scaleY +=e.delta/100;
        container.scaleZ +=e.delta/100;
    }
    function rotator(e:MouseEvent){//функция поворота объекта
        container.rotationY = (mouseX - stage.stageWidth/2)/5;
        container.rotationX = (mouseY - stage.stageHeight/2)/2;
}}
function dotReplacer(spriteNames:Array, container:Object, a:Number, b:Number, c:Number, dt:Number){
            for (var f = 1; f<spriteNames.length; f++){
            var tar = container.getChildByName(spriteNames[f]);       
            var prevTar = container.getChildByName(spriteNames[f-1]);
            coordTransfer(tar, prevTar);
            attractorCoord(tar, a, b, c, dt)
}}
function attractorCoord(spr:Object, a:Number, b:Number, c:Number, dt:Number){
//собственно система Аттрактора Лоренца
    var X:Number = spr.x+a*(spr.x+spr.y)*dt;
    var Y:Number = spr.y+(b*spr.x-spr.y-spr.z*spr.x)*dt;
    var Z:Number = spr.z+(-c*spr.z+spr.x*spr.y)*dt;
   
    if (spr.x < 2000 && spr.x >-2000 && spr.y < 2000 && spr.y >-2000 && spr.z < 2000 && spr.z >-2000){//ограничение на размер построения
        spr.x = X;
        spr.y = Y;
        spr.z = Z/10;/*Аттрактор очень уж расползается по оси Z, пришлось немного подрезать*/
}}
function coordTransfer(fromObj:Object, toObj:Object){/* тут у вас может возникнуть небольшая путаница, я перепутал местами название передающего и принимающего координаты объекта, можете поменять*/
    fromObj.x = toObj.x;
    fromObj.y = toObj.y;
    fromObj.z = toObj.z;
}

Естественно, что здесь я привел код только для построения точек, изменения коэффициентов b и с в системе, её вращения относительно осей X, Y и масштабирование. Вы можете запустить процесс изменения системы нажатием (удерживанием) клавиш W и S для увеличения или уменьшения коэффициента c, а клавиши A  и D для изменения коэффициента b.
А вот кадр страницы помощи из полного 3D Lorenz attractor dynamic ролика:


Кроме запуска интерации коэффициентов b и с  в сторону увеличения или уменьшения, в полной версии ролика есть возможность построения "скелета" поверхности вращения по трем осям (для ограниченного набора точек, где-то с 100 по 300 точку), возможность изменения начальных координат X, Y, Z построения, возможность прекратить интерацию коэффициентов нажатием клавиши пробел.


Поверхность вращения относительно оси X.

Поверхность вращения относительно оси Z.

Поверхность вращения относительно оси Y.