10 флеш синусы и косинусы в прошлом.


Проект состоит из 3 классов, а именно: Car3Doc.as - документ класс; ThreeD.as - класс ответственный за 3D работу; Cube.as - кубический объект. Скомпилированно на flex, но можно его скомпилить и на Flash CS4. Версия плеера 10.

Документ класс Car3Doc.as.

Уже и не спрашивайте: "Ну причем тут машина Car???" Ладно - это должна была быть 3Д гоночка, ну все понемногу...
package 
	{
	import flash.display.*;
	import flash.events.*;
	import flash.text.*;
	import __AS3__.vec.*;
	import flash.geom.*;
	
[SWF(width='400', height='400', backgroundColor='#123456', frameRate='24')]
	dynamic public class Car3Doc extends MovieClip{ ;
		public var i:int,j:int,a:int,c:int,
			threeD:ThreeD,
			cubeArr:Array,
			spArr:Array,
			cube:Cube,
			sp:Sprite,
			distS:Array;
		public function Car3Doc() {
			x = y = 200;

			threeD = new ThreeD();
			threeD.calcAngle();
			cubeArr = [];
			spArr = [];
			distS = [];
			for (i=0;i<4;i++) {
				cubeArr[i] = new Cube(threeD,40);
				addChild(spArr[i] = new Sprite());
			}
			j=c=a=0;
			addEventListener(Event.ENTER_FRAME, enterFrameFunc);
		}
		private function enterFrameFunc(evt:Event):void {
			threeD.angleA+=1;
			threeD.angleB+=2;
			threeD.angleB-=3;
			threeD.calcAngle();
			a++;
			for (i = 0; i < 4; i++) {
				sp = spArr[i];
				cube = cubeArr[i];
				cube.purelyDirt();
				if (i == 0 || i == 2) threeD.moveV(cube.dirtS,new Vector3D(70,0,0));
				if (i == 1 || i == 3) threeD.moveV(cube.dirtS,new Vector3D(-70,0,0));
				if (i == 0 || i == 1) threeD.moveV(cube.dirtS,new Vector3D(0,70,0));
				if (i == 2 || i == 3) threeD.moveV(cube.dirtS,new Vector3D(0,-70,0));
				if (a<180) if (i == 0 || i == 3) 
					threeD.rot(cube.dirtS, cube.dirtS[cube.dirtS.length-1],new Vector3D(0, 0, 1), j++);
				else threeD.rot(cube.dirtS, cube.dirtS[cube.dirtS.length-1],new Vector3D(0, 0, 1), c--);
				if (a>180) if (i == 0 || i == 3) 
					threeD.rot(cube.dirtS, cube.dirtS[cube.dirtS.length-1],new Vector3D(0, 1, 0), j++);
				else threeD.rot(cube.dirtS, cube.dirtS[cube.dirtS.length-1],new Vector3D(0, 1, 0), c--);

				if (a>360) a=0;

				distS[i] = [cube.render(sp),i]
			}
			//trace(distS);
			threeD.sortFac(this, spArr, distS);
		}
	}
}
Как видно по коду действия создаются четыре куба. Больше ничего добавить не хочу ибо считаю что все и так понятно. Кому не понятно - боюсь не смогу помочь, тк. я начинаю сильно волноваться, скажу даже больше нервничать.

Класс для 3Д проекций и преобразований ThreeD.as

//ThreeD
package {
	import flash.geom.*;
	import __AS3__.vec.*;
	import flash.display.*;
	
	public class ThreeD {
		public var angleA:Number, angleB:Number, angleC:Number, j:Number;
		public var focus:Number;//focus
		public var i:Number,len:Number;
		private var mat3D:Matrix3D, matR:Matrix3D;

		public var distS:Array;

		public function ThreeD(_focus:Number = 300) {
			angleA = -60;
			angleB = 360;
			angleC = -30;
			focus = _focus;
			matR = new Matrix3D();
			calcAngle();
		}

		public function calcAngle():void {
			mat3D = new Matrix3D();
			mat3D.appendRotation(angleA, Vector3D.X_AXIS);//сначала Y потом X
			mat3D.appendRotation(angleB, Vector3D.Y_AXIS);
			mat3D.appendRotation(angleC, Vector3D.Z_AXIS);
		}
		//посчитать проекцию одной точки (не используется)
		public function calcProjection(_pVec:Vector3D):Vector3D {
			_pVec = mat3D.transformVector(_pVec);
			
			_pVec.w = (focus + _pVec.z) / focus;

			_pVec.project();
			return _pVec;

		}

		//посчитать проекцию всех точек
		public function calcBigProjection(_pVec:Vector.<Vector3D>):void {
			len = _pVec.length;
			for (i=0;i<len;i++) {
				_pVec[i] = mat3D.transformVector(_pVec[i]);
			
				_pVec[i].w = (focus + _pVec[i].z) / focus;
	
				_pVec[i].project();;
			}
		}

		//используется для сортироки граней
		public function sorT(v:Array,w:Array):Number {
			if (v[0]>w[0]) {
				return -1;
			} else if (v[0]<w[0]) {
				return 1;
			} else {
				return 0;
			}
		}

		//функция для перемещения пространства по вектору
		public function moveV(_pVec:Vector.<Vector3D>, _vCorre:Vector3D):void {
			len = _pVec.length;//переместить координаты
			for (i=0;i<len;i++){
				_pVec[i].decrementBy(_vCorre);
			}
		}
		
		//средняя точка
		public function calcMid(_pVec:Vector.<Vector3D>):Vector3D {
			var cMidV:Vector3D = new Vector3D();
			len = _pVec.length;//переместить координаты
			for (i=0;i<len;i++){
				cMidV.x = cMidV.x + _pVec[i].x;
				cMidV.y = cMidV.y + _pVec[i].y;
				cMidV.z = cMidV.z + _pVec[i].z;
			}
			cMidV.x = cMidV.x/len;
			cMidV.y = cMidV.y/len;
			cMidV.z = cMidV.z/len;
			return cMidV;
		}

		

		//функция для вращения объекта ПРИМЕР ВЫЗОВА
		//threeD.rot(cube.dirtS, new Vector3D(20,50,20),new Vector3D(1, 0, 0), 5);
		public function rot(_pVec:Vector.<Vector3D>, _rotCorre:Vector3D, _zRotVec:Vector3D, _r:Number):void {
			//zRotVec - (ВЕКТОР РОТАЦИИ)
			//zRotVec - если ставить больше 1 то куб увеличивается в размерах //
			matR = new Matrix3D();
			//_rotCorre = центр ротации
			matR.appendRotation(_r, _zRotVec);//матрици модифицируется прибавляя углов

			
			len = _pVec.length;//переместить координаты
			for (i = 0; i < len; i ++) {
				_pVec[i].decrementBy(_rotCorre);//вычитание векторов
				_pVec[i] = matR.transformVector(_pVec[i]);
				_pVec[i].incrementBy(_rotCorre);//сложение векторов
			}
		}
		//поставить грани по порядку
		public function sortFac(_sp:Sprite, _spArr:Array, _distS:Array):void {
			_distS.sort(sorT);
			len = _distS.length;
			for (i=0; i < 4; i++) {//выстроить грани по порядку
				//trace(_distS[i][1]);
				_sp.setChildIndex(_spArr[_distS[i][1]], i);
			}
			
			
		}
		
		//расчитать цвет грани (работает только красный - пока)
		public function calcColor(_color:uint,_dist:Array,_index:int):uint{
			var color:uint;
			len = _dist.length;
			var dMin:Number = _dist[0][0];
			var dMax:Number = _dist[len-1][0];
			var dStep:Number = Math.abs((dMax - dMin)/len);

			var rMin:uint = 0x00;
			var rMax:uint = 0xee;
			var cStep:Number = Math.abs((rMin-rMax)/len);

			var r:uint;
			var g:uint = 0x00;
			var b:uint = 0x00;



			var ind:Number = (_dist[_index][0]-dMin)/dStep;
			r = uint(rMax-cStep*ind);
			color = ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF);
			
			return color;
			
		}

	}
}
Тут тоже должно быть все понятно (подробные комментарии), единственное я не доделал расчет цвета грани, но ничего потом доделаю (если захочу).
Послений жизнено необходимый (не очень) класс собственно Куб (от него можно наследоваться в виде пирамиды, цилиндра, плоскости - рассматриваться не будет, потому как в лом).

Cube.as - класс куба

package {
	import flash.display.*;
	import flash.geom.*;

	public class Cube {

		public var i:int, j:int,len:int,
			pointS:Array,
			cS:Number,
			threeD:ThreeD,
			facetLength:Number,
			purelyS:Vector.<Vector3D>,//чистые точки объекта
			dirtS:Vector.<Vector3D>,//грязные точки полученные при трансформациях
			facetS:Array,
			zAverage:Number,
			curFaceLen:int,
			numFaces:int,
			dist:int,
			distArray:Array,
			curFace:int;
		public function Cube(_treeD:ThreeD, _size:Number = 70) {
			cS = _size;
			threeD = _treeD;
			
			distArray = [];

			
			purelyS = new Vector.<Vector3D>,//чистые точки объекта
			dirtS = new Vector.<Vector3D>,//грязные точки полученные при трансформациях
			facetS = [];
			init();
			purelyS.push(threeD.calcMid(purelyS));//добавить в конец среднюю точку этого объекта
			facetLength = facetS.length;

		}
		public function init():void {
			pointS = [
			 cS,-cS, cS,//0
			 cS, cS, cS,//1
			-cS, cS, cS,//2
			-cS,-cS, cS,//3
			 cS,-cS,-cS,//4
			 cS, cS,-cS,//5
			-cS, cS,-cS,//6
			-cS,-cS,-cS //7
			];
			for (i=0;i<pointS.length;i+=3) 
				purelyS.push(new Vector3D(pointS[i],pointS[i+1],pointS[i+2]));
			purelyDirt();
			
			facetS[0] = [0,4,5,1];
			facetS[1] = [1,5,6,2];
			facetS[2] = [2,6,7,3];
			facetS[3] = [3,7,4,0];
			facetS[4] = [4,5,6,7];
			facetS[5] = [0,1,2,3];
			numFaces = facetS.length;
		}
		//из чистого в грязное
		public function purelyDirt():void{
			len = purelyS.length;
			for (i=0;i<len;i++) dirtS[i] = purelyS[i].clone();
		}
		public function render(_sp:Sprite):Number{
			threeD.calcBigProjection(dirtS);
			//trace(dirtS);
			for(i=0;i<numFaces;i++){
				curFaceLen=facetS[i].length;
				zAverage=0;
					for(j=0;j<curFaceLen;j++){
						zAverage+=dirtS[facetS[i][j]].z;
					}
				zAverage/=curFaceLen;
				dist=zAverage;
				distArray[i]=[dist,i];
			}

			distArray.sort(threeD.sorT);
			_sp.graphics.clear();
			for(i=0;i<numFaces;i++){
				//_sp.graphics.lineStyle(0);
				curFace=distArray[i][1]; 
				curFaceLen=facetS[curFace].length;
				
				_sp.graphics.beginFill(threeD.calcColor(0xff00cc,distArray,i));
				_sp.graphics.moveTo(dirtS[facetS[curFace][0]].x,
				dirtS[facetS[curFace][0]].y);
					for(j=1;j<curFaceLen;j++){
						_sp.graphics.lineTo(dirtS[facetS[curFace][j]].x,
						dirtS[facetS[curFace][j]].y);
					}
				_sp.graphics.lineTo(dirtS[facetS[curFace][0]].x,
				dirtS[facetS[curFace][0]].y);
				_sp.graphics.endFill();
			}
			zAverage=0;
					for(j=0;j<curFaceLen;j++){
						zAverage += distArray[j][0];
					}
			zAverage = zAverage/curFaceLen;
			return zAverage;
		}
	}
}
Ну что тут можно прокомментировать??? Посетите если уж ничего не понятно сайт http://www.flashandmath.com/ Там подробно описаны все трехмерные преобразования (если не знаете английского смотрите по рисункам, но формулы и код естественно все равно на английском - как ни крути)
архив, содержащий все классы проекта с четырьма вращающимися флеш кубами.