Alternativa3D 7.6 Визуализатор


Full Browser Size Music 1

800×600 Music 1

Full Browser Size Music 2

800×600 Music 2

Исходник

Решил реализовать в качестве примера визуализатор на Alternativa3D 7.6. На сцене два шлейфа(TwoPointsTrail.as) один рисует низкую частоту, другой высокую. Сам шлейф строится каждый кадр по двум точкам. Т.е. каждый кадр в вектор заносятся по две точки, если точек больше трех, то соответственно можно строить треугольные фейсы. Причем точки это Object3D, который имеет свойство x,y,z. В каждом шлейфе, каждый фейс рисуется в один Mesh, который в свою очередь кладется в заданный при инициализации шлейфа контейнер. После того, как onEnterFrame отработал 45 раз, т.е. прошел 45-ый кадр, запускаю другой onEnterFrame, который каждый кадр будет удалять по две точки находящиеся в векторе вертексов, и по два фейса, находящихся в векторе фейсов. В главном классе вся логика визуализации находится в onEnterFrame методе _loop(e:Event). В зависимости от считанного числа из ByteArray я всячески всё кручу-верчу =)

Построение Mesh:

private function _addVertices(e:Event):void 
       {
           currentFrame++;
         //как только мы проскочили 45-ый кадр, 
          //начинаем удалять по два фейса каждый кадр
          if (currentFrame == 45)
         {
               _startRemoveVertices(null);
         }
           if (!trailMesh) return;
         //преобразовываем локальные координаты в глабольные, пространства
          var vec1:Vector3D = info.points[0].localToGlobal(new Vector3D(0, 0, 0));
            var vec2:Vector3D = info.points[1].localToGlobal(new Vector3D(0, 0, 0));
            //кладем в вектор
          _vertices.push(trailMesh.addVertex(vec1.x, vec1.y, vec1.z));
            _vertices.push(trailMesh.addVertex(vec2.x, vec2.y, vec2.z));
            //если в векторе уже присутствует 4 вертекса, то можно строить два фэйса
           if (_vertices.length > 3)
           {
               //рисуем треугольные фейсы с двух сторон
               //два фейса с одной стороны
                _faces.push(trailMesh.addTriFace(_vertices[_vertices.length - 4], _vertices[_vertices.length - 3], _vertices[_vertices.length - 2]));
               _faces.push(trailMesh.addTriFace(_vertices[_vertices.length - 3], _vertices[_vertices.length - 4], _vertices[_vertices.length - 2]));
               //два фейса с другой стороны
              _faces.push(trailMesh.addTriFace(_vertices[_vertices.length - 3], _vertices[_vertices.length - 1], _vertices[_vertices.length - 2]));
               _faces.push(trailMesh.addTriFace(_vertices[_vertices.length - 1], _vertices[_vertices.length - 3], _vertices[_vertices.length - 2]));
           }
           //сеттим материал
         trailMesh.setMaterialToAllFaces(new FillMaterial(_color, 0.7));
 
            //рассчитываем нормали
           trailMesh.calculateNormals(true);
           //рассчитываем границы
           trailMesh.calculateBounds();
        }

Main.as:

package 
{
 import alternativa.engine3d.containers.ConflictContainer;
   import alternativa.engine3d.core.Camera3D;
  import alternativa.engine3d.core.Object3D;
  import alternativa.engine3d.core.Object3DContainer;
 import alternativa.engine3d.core.View;
  import caurina.transitions.Tweener;
 import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
  import flash.media.Sound;
   import flash.media.SoundMixer;
  import flash.utils.ByteArray;
 
   /**
  * ...
   * @author Sergey [Flastar] Gonchar
  */
 [Frame(factoryClass="Preloader")]
   public class Main extends Sprite 
   {
       [Embed(source='../bin/011.mp3')]
      private var _embSoundClass:Class;
       private var _snd:Sound;
 
        private var _rootContainer:Object3DContainer = new Object3DContainer();
     private var _cameraContainer:Object3DContainer;
     private var _cContainer:ConflictContainer;
      private var _cContainer2:ConflictContainer;
     private var _cContainer3:ConflictContainer;
 
        private var _camera:Camera3D;
       private var _point1:Object3D;
       private var _point2:Object3D;
       private var _point3:Object3D;
       private var _point4:Object3D;
 
        private var _angle:Number = 1;
      private var _vibroFlag:Number = 1;
 
        public var speed:Number = 30;
 
 
        public function Main():void 
        {
           if (stage) init();
          else addEventListener(Event.ADDED_TO_STAGE, init);
      }
 
       private function init(e:Event = null):void 
     {
           removeEventListener(Event.ADDED_TO_STAGE, init);
 
            stage.align = StageAlign.TOP_LEFT;
          stage.scaleMode = StageScaleMode.NO_SCALE;
 
            _camera = new Camera3D();
           _camera.view = new View(stage.stageWidth, stage.stageHeight);
           addChild(_camera.view);
         _camera.rotationX = -130*Math.PI/180;
           _camera.rotationZ = 90*Math.PI/180;
         _camera.y = 0;
          _camera.z = 1000;
 
            //контейнер в котором будет эффект
          _cContainer = new ConflictContainer();
          _rootContainer.addChild(_cContainer);
           //контейнер с камерой отдельно
         _cameraContainer = new Object3DContainer();
         _rootContainer.addChild(_cameraContainer);
          _cameraContainer.addChild(_camera);
         //контейнер для первых двух поинтов
            _cContainer2 = new ConflictContainer();
         _rootContainer.addChild(_cContainer2);
 
            _point1 = new Object3D();
           _cContainer2.addChild(_point1);
         _point1.x = -400;
           _point1.z = 100;
 
            _point2 = new Object3D();
           _cContainer2.addChild(_point2);
         _point2.x = -400;
           _point2.z = -100;
 
            var effect:TwoPointsTrail = new TwoPointsTrail();
           effect.create(new TrailInfo(_cContainer, 0xff136c, [_point1, _point2]));
            effect.start();
         //контейнер для следующих двух поинтов
          _cContainer3 = new ConflictContainer();
         _rootContainer.addChild(_cContainer3);
 
            _point3 = new Object3D();
           _cContainer3.addChild(_point3);
         _point3.x = -400;
           _point3.z = 100;
 
            _point4 = new Object3D();
           _cContainer3.addChild(_point4);
         _point4.x = -400;
           _point4.z = -100;
 
            var effect2:TwoPointsTrail = new TwoPointsTrail();
          effect2.create(new TrailInfo(_cContainer, 0x18c1ff, [_point3, _point4]));
           effect2.start();
            //звук
          _snd = new _embSoundClass();
            _snd.play(0, 99);
 
            //чтобы камера наклонялась вправо и влево
         _beginRotateCamera();
 
            stage.addEventListener(Event.ENTER_FRAME, _loop);
           stage.addEventListener(Event.RESIZE, _stageUpdate);
     }
 
        private function _beginRotateCamera():void 
     {
           Tweener.addTween(_cameraContainer, { rotationX: 40*Math.PI/180,time:3, transition:"easeInOutSine", onComplete:_endRotateCamera} );
      }
 
        private function _endRotateCamera():void 
       {
           Tweener.addTween(_cameraContainer, { rotationX: -40*Math.PI/180, transition:"easeInOutSine",time:3, onComplete:_beginRotateCamera} );
       }
 
        private function _stageUpdate(e:Event):void 
        {
           _camera.view.width = stage.stageWidth;
          _camera.view.height = stage.stageHeight;
        }
 
        private function _loop(e:Event):void 
       {
           _cContainer2.x -= speed;
            _cContainer3.x -= speed;
            _cameraContainer.x = _cContainer2.x + 1000;
 
            //считываем звук
           var bytes:ByteArray = new ByteArray();
          SoundMixer.computeSpectrum(bytes);
 
            //ставим новое расстояние между первой парой точек
            var newDepth1:Number = Math.abs(bytes.readFloat() * 2000)+2;
            Tweener.addTween(_point1, { z:newDepth1, time:1 } );
            Tweener.addTween(_point2, { z: -newDepth1, time:1 } );
 
            //наш вибратор:)
         _cContainer.rotationX = 90 * Math.PI / 180 +_vibroFlag*Math.abs(bytes.readFloat())/8;
           _vibroFlag *= -1;
 
            //крутим по спирали синий шлейф
            _angle += Math.abs(bytes.readFloat() * 100);
            Tweener.addTween(_cContainer3, { z: Math.sin((_angle + 180) * Math.PI / 180) * 800, transition:"linear", time:0.2 } );
          Tweener.addTween(_cContainer3, { y: Math.cos((_angle + 180) * Math.PI / 180) * 600, transition:"linear", time:0.2 } );
          _cContainer3.rotationX = _angle * Math.PI / 180;
 
            //переходим к высоким
          for (var i:int = 0; i < 240; i++ ) bytes.readFloat();
           //ставим новое расстояние между второй парой точек
            var newDepth2:Number = Math.abs(bytes.readFloat() * 2000)+2;
            Tweener.addTween(_point3, { z:newDepth2, transition:"linear",time:0.15 } );
         Tweener.addTween(_point4, { z: -newDepth2, transition:"linear", time:0.15 } );
          //рендерим
          _camera.render();
       }
   }
}

TwoPointsTrail.as:

package  
{
 import alternativa.engine3d.core.Face;
  import alternativa.engine3d.core.Sorting;
   import alternativa.engine3d.core.Vertex;
    import alternativa.engine3d.materials.FillMaterial;
 import alternativa.engine3d.materials.TextureMaterial;
  import alternativa.engine3d.objects.Mesh;
   import flash.display.Shape;
 import flash.events.Event;
  import flash.events.EventDispatcher;
    import flash.events.TimerEvent;
 import flash.geom.Vector3D;
 import flash.utils.Timer;
   /**
  * ...
   * @author Sergey [Flastar] Gonchar
  */
 public class TwoPointsTrail extends EventDispatcher
 {
       public var info:TrailInfo;
      public var trailMesh:Mesh;
      public var material:TextureMaterial;
 
        private var _timerRemoveVertices:Timer;
     private var _vertices:Vector.<Vertex>;
      private var _faces:Vector.<Face>;
       private var _currentRemove:Number = 0;
      private var _shapeRemoveListener:Shape;
     private var _shapeAddListener:Shape;
        private var _beginStopBool:Boolean;
     private var _isDestroyed:Boolean;
 
        private var _color:uint;
        private var currentFrame:Number = 1;
 
        public function create(config:Object):void
      {
           this.info = config as TrailInfo;
        }
 
        public function start () : void
     {
           this._color = info.color;
 
            _shapeAddListener = new Shape();
            _shapeAddListener.addEventListener(Event.ENTER_FRAME, _addVertices);
 
            trailMesh = new Mesh();
         trailMesh.sorting = Sorting.AVERAGE_Z;
          info.targetContainer.addChild(trailMesh);
 
            _vertices = new Vector.<Vertex>();
          _faces = new Vector.<Face>();
       }
 
        private function _addVertices(e:Event):void 
        {
           currentFrame++;
         //как только мы проскочили 45-ый кадр, 
          //начинаем удалять по два файса каждый кадр
          if (currentFrame == 45)
         {
               _startRemoveVertices(null);
         }
           if (!trailMesh) return;
         //преобразовываем локальные координаты в глабольное пространство
           var vec1:Vector3D = info.points[0].localToGlobal(new Vector3D(0, 0, 0));
            var vec2:Vector3D = info.points[1].localToGlobal(new Vector3D(0, 0, 0));
            //кладем в вектор
          _vertices.push(trailMesh.addVertex(vec1.x, vec1.y, vec1.z));
            _vertices.push(trailMesh.addVertex(vec2.x, vec2.y, vec2.z));
            //если в векторе уже присутствует 4 вертекса, то можно строить два фэйса
           if (_vertices.length > 3)
           {
               //рисуем треугольные фэйсы с двух сторон
               //два фэйса с одной стороны
                _faces.push(trailMesh.addTriFace(_vertices[_vertices.length - 4], _vertices[_vertices.length - 3], _vertices[_vertices.length - 2]));
               _faces.push(trailMesh.addTriFace(_vertices[_vertices.length - 3], _vertices[_vertices.length - 4], _vertices[_vertices.length - 2]));
               //два фэйса с другой стороны
              _faces.push(trailMesh.addTriFace(_vertices[_vertices.length - 3], _vertices[_vertices.length - 1], _vertices[_vertices.length - 2]));
               _faces.push(trailMesh.addTriFace(_vertices[_vertices.length - 1], _vertices[_vertices.length - 3], _vertices[_vertices.length - 2]));
           }
           //сеттим материал
         trailMesh.setMaterialToAllFaces(new FillMaterial(_color, 0.7));
 
            //рассчитываем нормали
           trailMesh.calculateNormals(true);
           //рассчитываем границы
           trailMesh.calculateBounds();
        }
 
        private function _startRemoveVertices(e:TimerEvent):void 
       {
           _shapeRemoveListener = new Shape();
         _shapeRemoveListener.addEventListener(Event.ENTER_FRAME, _removeLast2Vertices);
     }
 
        private function _removeLast2Vertices(e:Event):void 
        {
           if (!trailMesh) return;
 
            if (trailMesh.faces.length > 2)
         {
               trailMesh.removeFace(_faces[_currentRemove]);
               _currentRemove++;
               trailMesh.removeFace(_faces[_currentRemove]);
               _currentRemove++;
               trailMesh.removeFace(_faces[_currentRemove]);
               _currentRemove++;
               trailMesh.removeFace(_faces[_currentRemove]);
               _currentRemove++;
 
                trailMesh.removeVertex(_vertices.shift());
              trailMesh.removeVertex(_vertices.shift());
          }
       }
   }
}

TrailInfo.as:

package  
{
  import alternativa.engine3d.core.Object3D;
  import alternativa.engine3d.core.Object3DContainer;
 import flash.display.BitmapData;
    /**
  * ...
   * @author Sergey [Flastar] Gonchar
  */
 public class TrailInfo 
 {
       public var targetContainer:Object3DContainer; 
      public var points:Array/*Object3D*/ = [];
       public var color:uint;
 
        public function TrailInfo(targetContainer:Object3DContainer, color:uint, points:Array) 
     {
           this.targetContainer = targetContainer;
         this.color = color;
         this.points = points;
       }
   }
}

За полезные советы отдельное спасибо: Владимиру Бабушкину, Белой, Дмитрию [focus] Юханову.
Любые вопросы задавайте на форуме альтернативы или присылайте мне на почту. Надеюсь вам понравилось!

SergeyGonchar
flash-developer
Visit Gonchar Website.

12 Responses to “Alternativa3D 7.6 Визуализатор”

  1. bimawa says:

    Ни че так прикольная задумка.

  2. […] Alternativa3D 7.6 Visualization by Flastar This entry was posted in Experiment. Bookmark the permalink. ← Snow […]

  3. fmaxx says:

    моя не понимать, зачем это?

  4. foreground says:

    SoundMixer.computeSpectrum лучше не юзать. Потомучта если в другом окне браузера открыта другая флэшка с видео или аудио содержимым может выпасть ошибка секьюрности. Юзать надо Sound.extract.

  5. Ivan Taranov says:

    а что надо сделать, чтобы видеть не только черный экран и музыку слушать?)

  6. Рост says:

    Замечательно, но не хватает музыки, слишком внезапно обрывается, нужен кач, чувак!

  7. Flastar says:

    to Rost: сейчас исправим)))
    to Ivan Taranov: обновить флеш-плеер до 10-ой версии
    to foreground: спасибо за совет, этого я не знал
    to fmaxx: просто экзампл

  8. Ivan Taranov says:

    До какой именно ?
    У меня:
    http://www.adobe.com/software/flash/about/
    You have version 10,1,103,20 installed

  9. Ivan Taranov says:

    Посмотрел в Firefox. По какой то странной особенности Chrome показать не захотел мне визуализацию. А так и правда побольше бы колбасы!))) Спасибо за пример!)

  10. 0xFFFFFF says:

    to foreground: с extract замучаешься делать FFT. а визуализация без FFT скучна

  11. foreground says:

    to 0xFFFFFF: зато ошибки не валятся.

  12. 0xFFFFFF says:

    to Foreground: ошибки можно отлавливать, просто обычно лень и рассчитываешь на сознательных понимающих граждан-флешеров

Leave a Reply

×
%d bloggers like this: