Трехмерная моделька во флеш со сложной формой.

В качестве 3Д редактора будет использоваться Blender. Мне понравилась эта програмуля, она весит около 10 мегабайт, с мобильным пипел нетом, я ее скачал без проблем, стартует довольно быстро на моем престарелом железяке. Так как я практически не шарю в 3Д редакторах, то сравнить не с чем не могу, кроме как визуально, блендер шуршит намного быстрее, чем остальные платные его аналоги. Сделал по уроку текст со сложной формой в blender.
скрин блендера с трехмерным текстом

Потом этот 3d текст был переведен в as3 по где то там нашел, технологии экспорта из блендера в as3 или вот еще как устанавливать плугин блендера для экспорта в as flash код. Особенностью этих экспортеров является множество форматов для экспорта, там и sandy, papervision, а так-же гордость отечественного флеш-три-д-прогропрома alternativa3d, но мы их не будем юзать, а будем использовать наиболее приглянувшийся экспорт из линейки away3d lite version 1.0
экспорт в as

Мне надо чтобы модель состояла из треугольных граней поэтому надо нажать в режиме edit mode клавиатурную махинацию ctrl+t (convert quads to triangles) потом нажать u сделать unwrap и выбрать там же cube proection (прим. печатывающего последовательность действий может быть любая как и тип проекции цилиндрическая или сферическая, все равно будет работать). Получется файл в результате экспорта примерно такой
package  {
	import away3dlite.arcane;
	import away3dlite.core.base.*;
	import away3dlite.materials.*;
	import away3dlite.primitives.*;
	use namespace arcane;

	public class Font extends AbstractPrimitive {
		protected var vtmp:Vector.<Number> = new Vector.<Number>();
		protected var indicesCounter:int=0;

		public function Font(mat:Material= null) {
			super( mat );
		}
		protected override function buildPrimitive():void {
			super.buildPrimitive();

			v(-6.518186,-6.101490,20.899748);
			v(15.542115,-6.101490,16.368355);
			v(10.806922,-6.101490,16.881636);
			/*
			штук 50 ну очень похожих строк
			*/
			v(1.104486,13.042084,22.111891);
			v(4.314753,13.042084,21.817190);
			v(4.314753,-6.101490,21.817190);

			f(128,12,11,0.624654,0.662113,0.611937,0.707049,0.588711,0.721273);
			f(128,13,12,0.624654,0.662113,0.625150,0.732212,0.611937,0.707049);
			f(16,13,128,0.643879,0.700547,0.625150,0.732212,0.624654,0.662113);
			/*
			штук 30 ну очень похожих строк
			*/
			f(30,31,75,0.044679,0.216735,0.044679,0.187052,0.099835,0.188990);
			f(30,75,78,0.044679,0.216735,0.099835,0.188990,0.096889,0.207066);


			x = 0.000000; y = 0.000000; z = 0.000000;

			rotationX = 0.000000; rotationY = 0.000000; rotationZ = 0.000000;

			scaleX = 3.167547; scaleY = 3.167547; scaleZ = 3.167547;

		}
		public function v(x:Number, y:Number, z:Number):void {
			vtmp.push(x, y, z);
		}

		public function v2(x:Number, y:Number, z:Number):void {
			_vertices.push(x, y, z);
		}

		public function uv(u:Number, v:Number):void {
			_uvtData.push(u,v,1);
		}

		public function f(vertexIndex1:int, vertexIndex2:int, vertexIndex3:int, uv00:Number, uv01:Number, uv10:Number, uv11:Number, uv20:Number, uv21:Number ):void {
			var vi1:int=vertexIndex1*3;
			var vi2:int=vertexIndex2*3;
			var vi3:int=vertexIndex3*3;
			_vertices.push(vtmp[vi1],vtmp[vi1+1],vtmp[vi1+2]);
			_vertices.push(vtmp[vi2],vtmp[vi2+1],vtmp[vi2+2]);
			_vertices.push(vtmp[vi3],vtmp[vi3+1],vtmp[vi3+2]);
			_uvtData.push(uv00,uv01,1,uv10,uv11,1,uv20,uv21,1);
			_indices.push(indicesCounter++,indicesCounter++,indicesCounter++);
		}

		public function f2(vertexIndex1:int, vertexIndex2:int, vertexIndex3:int):void {
			_indices.push(vertexIndex1,vertexIndex2,vertexIndex3);
		}

	}
}

Мне в принципе эти похожие строки как-бы и не нужны, мне надо координаты векторов, координаты сетки и грани с индексами векторов и индексами сетки. Для этого я сделал на флеше переэкспорт этого всего в свой формат, я тупо копирую строки начинающиеся на v и f и вставляю их в спец as файл (возможно я чето перемудрил, тк. красота кода под вопросом, мож чего и лишнее, однако работоспособно вполне)
package  
{
	import flash.geom.*;
	import flash.display.*;
	/**
	 * ...
	 * @author Alex Lexcuk http://www.murmadillo.tut.su
	 */
	public class DocBlendToNormalize extends Sprite
	{
		public var uv:Vector.<Ep> = new Vector.<Ep>();
		public var uvUnique:Vector.<Ep> = new Vector.<Ep>();
		public var uCount:uint;
		public var fac:Vector.<Fac> = new Vector.<Fac>();

		public var v3ds:Vector.<Number> = new Vector.<Number>();
		public var uvs:Vector.<Number> = new Vector.<Number>();
		public var facs:Vector.<int> = new Vector.<int>();
		public var facUvs:Vector.<int> = new Vector.<int>();

		public function DocBlendToNormalize() 
		{
			//вставляю сюда все v строки из блендер экспорта
			//пример
			v(12.058761,-6.101490,18.962967);
			v(14.438794,6.501834,17.309065);
			v(8.406545,0.326485,20.724327);
			//ну и так дальше их около 40 штук

			//вставляю сюда все f строки из блендер экспорта
			//пример
			f(3,160,159,0.494402,0.089217,0.614703,0.042390,0.614703,0.089217);
			f(3,161,160,0.494402,0.089217,0.494402,0.042390,0.614703,0.042390);
			f(155,1,156,0.650278,0.264687,0.778463,0.357854,0.727543,0.339881);
			//ну и так дальше их около 30 штук




			
			//поиск одинаковых uv
			var i:int;
			var j:int;
			var accuracy:Number = 0.001;//точность текстуры
			var len:int = uv.length;
			var lenUnique:int; 
			for (i = 0; i < len; i++)
			for (j = 0; j < len; j++) {
				if (i == j) continue;
				if (!uv[i].delMeB && Point.distance(uv[i].toPoint(), uv[j].toPoint()) < accuracy) {
					//trace('совпадение',i,j,' ');
					uv[j].delMeB = true;
					uv[i].brotherI.push(j);
				} 
			}
			
			var uniCount:int;
			
			for (i = 0; i < len; i++) if (!uv[i].delMeB) {
				uv[i].uniId = uniCount;
				uvUnique.push(uv[i]);
				uniCount++;
			}
			
			len = uv.length;
			
			var ep:Ep;
			var uniIndX:Vector.<uint> = new Vector.<uint>();
			for (i = 0; i < len; i++) {
				ep = getFromUvUnique(i, 'i');
				if (ep == null) ep = getFromBr(i);
				//trace(ep);
				uniIndX[i] = ep.uniId;
			}
			len = uvUnique.length;
			for (i = 0; i < len; i++) uvFunc(uvUnique[i].x , uvUnique[i].y);
			
			len = fac.length;
			for (i = 0; i < len; i++) {
				fFunc( fac[i].p0,fac[i].p1,  fac[i].p2, uniIndX[fac[i].ep0.i],
				uniIndX[fac[i].ep1.i],
				uniIndX[fac[i].ep2.i]);
			}
			
			
			trace('v3ds = Vector.<Number>([' + v3ds + ']);');
			trace();
			trace('uvs = Vector.<Number>([' + uvs+']);');
			trace('facs = Vector.<int>([' + facs+']);');
			trace('facUvs = Vector.<int>([' + facUvs+']);');
		}

		private function v(x:Number,y:Number,z:Number):void
		{
		v3ds.push(x,y,z);
		}

		private function uvFunc(u:Number,v:Number):void
		{
		uvs.push(u,v);
		}

		private function fFunc(vn0:int, vn1:int, vn2:int, uvn0:int, uvn1:int, uvn2:int):void
		{
			facs.push(vn0, vn1, vn2);
			facUvs.push(uvn0, uvn1, uvn2);
		}

		public function getFromUvUnique(_i:uint,param:String):Ep {
			var i:int;
			var len:int = uvUnique.length;
			for (i = 0; i < len; i++) {
				if (uvUnique[i][param] == _i) return uvUnique[i];
			}
			return null;
		}

		public function getFromBr(_i:int):Ep {
			var i:int;
			var len:int = uvUnique.length;
			var tb:Object;
			for (i = 0; i < len; i++) {
				tb = uvUnique[i].brother(_i);
				if (tb != null) return uvUnique[i];
			}
			return null;
		}

		public function f(p0:Number, p1:Number, p2:Number, u0x:Number, u0y:Number, u1x:Number, u1y:Number, u2x:Number, u2y:Number):void {
			var e0:Ep;
			var e1:Ep;
			var e2:Ep;
			uv.push(e0 = new Ep(u0x, u0y, uCount++), 
			e1 = new Ep(u1x, u1y, uCount++), 
			e2 = new Ep(u2x, u2y, uCount++));
			
			fac.push(new Fac(p0, p1, p2, e0, e1, e2));
			
		}

	}

}

Запускаю этот файл на компиляцию и получаю в trace панельки нужные мне массивы примерно такого вида
v3ds = Vector.([12.058761,...,-6.10149,21.81719]);

uvs = Vector.([0.494402,0.089217,0.614703,0.04239,...]);
facs = Vector.([3,160,...75,30,31,75,30,75,78]);
facUvs = Vector.([0,1,2,0,3,1,4,5,6,4,7,5,8,7...312,321,322,312,322,314]);


троеточия это похожие повторы, для экономии html места. Теперь по идее можно вставить эти вассивы в отдельный класс (или как хотите) примерно так (вставлять на html кодом как-то многовато), сделаю скрин как это выглядит во FlashDevelop
скрин данных 3д модели в fd
Вот такая 3д моделька

Те. вполне себе юзабельно (с виду).
Теперь выведем модельку на экран, для z-sort граней будем пользоваться ранее продуманной сортировкой vector в флеш 10
package lex.m
{
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	
	
	
	import lex.LMath;
	
	import flash.events.*;
	/**
	 * ...
	 * @author Alex Lexcuk http://www.murmadillo.tut.su
	 */
	public class RTree extends MovieClip
	{
		[Embed(source = 'thumb_1850.png')]
		private var Pic:Class,
			baseBmd:BitmapData,
			baseBm:Bitmap;

		private var frCount:int;
		
		private var my3Obj:CubeObject = new CubeObject();


		
		private var cubeSh:Shape;
		private var world:Sprite;
		private var fdat:Vector.<Number> = new Vector.<Number>();
		private var m3d:Matrix3D = new Matrix3D();
		private var dats:Vector.<Number> = new Vector.<Number> ();
		private var isPlay:Boolean;
		public function RTree() 
		{
			//stage.scaleMode = StageScaleMode.NO_SCALE;
			
			addChild(cubeSh = new Shape());
			
			cubeSh.x = 400;
			cubeSh.y = 300;
			
			
			
			
			baseBmd = new Pic().bitmapData;
			baseBm = new Bitmap(baseBmd);
			//addChild(baseBm);
			m3d.appendScale(5, 5, 5);
			m3d.appendRotation(90, Vector3D.X_AXIS);
			//m3d.appendRotation(90, Vector3D.Y_AXIS);
			m3d.appendTranslation(0, 150, 0);
			//m3d.appendTranslation(0, -300, 0);
			drawCube();
		}

		public function startPlay():void {
			if (isPlay == false) {
				isPlay = true;
				addEventListener(Event.ENTER_FRAME, announceChange);
			}
		}

		private function drawCube():void {
			cubeSh.graphics.clear();
			//cubeSh.graphics.lineStyle(0, 0);
			var i:int;
			var j:int;
			var len:int = my3Obj.facs.length;
			var facs:Vector.<int> = my3Obj.facs;
			var x0:Number;
			var x:Number;
			var y0:Number;
			var y:Number;
			var w:Number;
			var focus:Number = 300;
			var n:Vector3D;
			var poly:Vector.<Vector3D> = new Vector.<Vector3D>();
			var z:Number;
			var x1:Number;
			var x2:Number;
			var y1:Number;
			var y2:Number;
			var z0:Number, z1:Number, z2:Number;
			var c:int = 0;
			var uv:Vector.<Number> = new Vector.<Number>();
			var uvRes:Vector.<Number> = new Vector.<Number>();
			var verticesRes:Vector.<Number> = new Vector.<Number>();
			
			var vertSorts:Vector.<Number> = new Vector.<Number>();
			var uvSorts:Vector.<Number> = new Vector.<Number>();
			
			var zs:Vector.<Number> = new Vector.<Number>();
			var zInds:Vector.<uint>;
			
			m3d.transformVectors(my3Obj.v3ds, dats);
			
			
			n = new Vector3D();
			
			w = 1 / ((focus + z) / focus);


			for (i = 0; i < len; i += 3) {
				j = 0;
				c = 0;
				//i =i;
				z = dats[facs[i] * 3 + 2 ];//z
				
				w = 1 / ((focus + z) / focus);
				
				
				x0 = fdat[j++] = dats[facs[i] * 3 ]*w;//x
				y0 = fdat[j++] = dats[facs[i] * 3 + 1 ]*w;//y
				z0 = dats[facs[i] * 3 + 2 ] * w;//z
				
				
				uv[c++]= my3Obj.uvs[my3Obj.facUvs[i] * 2 ] ;//x
				uv[c++] =( my3Obj.uvs[my3Obj.facUvs[i] * 2 +1] );//y
				
				
				z = dats[facs[i+1] * 3 +2];//z
				w = 1 / ((focus + z) / focus);
				
				x1 = fdat[j++] = dats[facs[i+1] * 3 ] * w;//x
				y1 = fdat[j++] = dats[facs[i+1] * 3 + 1 ] * w;//y
				z1 = dats[facs[i+1] * 3 + 2 ] * w;//z
				
				uv[c++] = (my3Obj.uvs[my3Obj.facUvs[i+1] * 2 ] );//x
				uv[c++] =( my3Obj.uvs[my3Obj.facUvs[i+1] * 2 +1] );//y
				
				
				z = dats[facs[i+2] * 3 + 2 ];//z
				w = 1 / ((focus + z) / focus);
				
				x2 = fdat[j++] = dats[facs[i+2] * 3 ] * w;//x
				y2 = fdat[j++] = dats[facs[i+2] * 3 + 1 ] * w;//y
				z2 =  dats[facs[i+2] * 3 + 2 ] * w;//z
				
				uv[c++] =( my3Obj.uvs[my3Obj.facUvs[i+2] * 2 ] );//x
				uv[c++] =( my3Obj.uvs[my3Obj.facUvs[i+2] * 2 +1] );//y
				
				
				
				poly[0] = new Vector3D( x0, y0, z0);
				poly[1] = new Vector3D( x1, y1, z1);
				poly[2] = new Vector3D( x2, y2, z2);
				
				
				
				LMath.calcNormal(poly[0], poly[1], poly[2], n);
				
				if (n.dotProduct(Vector3D.Z_AXIS) < 0) {//test invisible facet
					zs.push((poly[0].z + poly[1].z + poly[2].z)/3);//вставим z координаты
					verticesRes.push(fdat[0], fdat[1], fdat[2], fdat[3], fdat[4], fdat[5]);
					uvRes.push(uv[0], uv[1], uv[2], uv[3], uv[4], uv[5]);
				//trace('draw facet');
				}else ;//trace('not draw facet');
			}
			//sort on z coordinate
			zInds = LMath.vecSortNum(zs);

			
			len = zs.length;
			var vr:Vector.<Number> = verticesRes;
			var ur:Vector.<Number> = uvRes;
			for (j = 0; j < len; j++) {
				i = zInds[len - j -1];
				vertSorts.push(vr[i * 6], vr[i * 6 + 1], vr[i * 6 + 2], vr[i * 6 + 3], vr[i * 6 + 4], vr[i * 6 + 5]);
				uvSorts.push(ur[i * 6], ur[i * 6 + 1], ur[i * 6 + 2], ur[i * 6 + 3], ur[i * 6 + 4], ur[i * 6 + 5]);
			}
			cubeSh.graphics.beginBitmapFill(baseBmd);
			cubeSh.graphics.drawTriangles(vertSorts, null, uvSorts);
		}


		private function announceChange(e:Event):void {
			m3d.identity();
			
			m3d.appendScale(5, 5, 5);
			
			//m3d.appendRotation(90, Vector3D.Y_AXIS);
			
			//m3d.appendRotation(slider.value, Vector3D.X_AXIS);
			
			m3d.appendRotation(frCount--, Vector3D.Y_AXIS);
			
			m3d.appendRotation(-180, Vector3D.X_AXIS);
			//m3d.appendRotation(zSlider.value, Vector3D.Z_AXIS);
			
			m3d.appendTranslation(0, 150, 0);
			//m3d.appendRotation(180, Vector3D.Z_AXIS);
			
			
			drawCube();
			if (frCount > 180) frCount = -180;
			if (frCount < -180) frCount = 180;
		}

	}

}

Документ класс такой
package  
{
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	import lex.m.RTree;
	
	
	
	import lex.asComponent.LSlider;
	import lex.asComponent.style.LSliderStyle;
	import lex.LMath;
	
	/**
	 * ...
	 * @author Alex Lexcuk http://www.murmadillo.tut.su
	 */
	public class DocCube extends Sprite
	{

		
		private var rtr:RTree;
		public function DocCube() 
		{
			addChild(rtr = new RTree());
			rtr.startPlay();
			rtr.x = -150;
			rtr.y = -300;
		}


	}

}





Ctrl+enter

Вот она трехмерная Lexcuk надпись, а чё 8-24% проца (amd semptron 1800 мгц) кушает при 30 fps
Нормально, по моему.., чем меньше текстура у меня 150x150 тем меньше проц кушает...Если кому надо, можете позырить на архив с файлами FD проекта по отображению трехмерной модели методом drawTriangles с сортировкой граней. Единственное в нем нет blend файла с трехмерной надписью, тк. не увидел даже целесообразности его сохранять, его же можно за 30 секунд нарисовать.