Подключение меша к костной анимации.

Итак теперь, я начал тупить, тк. пишу счас он лайн, те. практически не готов как, пока подключить меш к арматуре, благо, что хоть арматура вроде работает хорошо и не плющится.
Хотел девочку нарисовать для анимации, но передумал, и нарисовал спичечного человечка.
текстура для спичечного коробка
нарисовал текстуру для спичек со своим лого, ну типа рекламы на спичечных коробках...

По идее тут все просто, меш состоит из вершин, вершины запакованы в группы, назание группы дублирует название соответствующей кости, теперь можно взять head кости крутануть относительно него кватернионом вершины меша, и переместить в точку где находится теперь head этой кости. Пипец как просто. Персоонаж нарисовался как бы сам собой, как-то легко и быстро, я даже подумал: нельзя с такой скоростью работать.
Прикольный 3Д персоонаж во флеше
человечек из спичечных коробков

Вставка 3D персоонажа во флеш 3D движком.

Сами положения костей в кадрах, арматуру и меш я экспортирую из блендера нехитрыми, самодельными py скриптами, за основу был взят универсальный экспортер меша от rozengain. Гуи я не делал, так-что надо в сами скрипты впечатать пути к файлам экспорта.

Выбор трехмерного движка для 3Д костной анимации.

Будет использоваться самый перспективный и рульный 3Д флеш движек, на сегодняшний момент, это конечно мой нативный d3, оптимизированный для отображения low poly (низкополигональных) текстуированных моделек. Это фрии опенсорс 3Д флеш двиг, который был сегодня доработан для отображения анимированного 3Д перца.
Немного теории...
10 флеш содержит в себе все необходимое для отображения 3Д, это ничего, что сортировка не работает, это мелочи, а как только флеш начнет поддерживать аппаратно видеокарту, флеш игрухи начнут выглядеть богато.

Экспорт анимации 3D персоонажа.

Анимация экспортируется питон скриптом get-animation.py (в архив). Особенность, тк. экспортируются кватернионы, надо отдельно экспортировать перемещения главной кости (надо впечатать ее имя), тк. иначе перец будет топтаться на месте.
import Blender
from Blender import *
from Blender.Mathutils import *

from multiprocessing import Process, Lock
from multiprocessing.sharedctypes import Value, Array
from ctypes import Structure, c_double
import math

#вытягиваемая арматура
myArmatureName = 'Armature'

#Экранное имя арматуры
myScrArmatureName = 'Armature'

#путь к экспорту
exportPathStr = 'D:\\FLEX\\3D\\proj-3d-engine\\pose-port\\animation.txt';

#координаты главной кости
centralBoneName = 'Bone';

#число кадров
frameBeginIndex = 1;
frameEndIndex = 22;

#и тд и тп...

Еще видите тут #вытягиваемая арматура и #Экранное имя арматуры, тут я немного не допонял, тк. у меня арматура называлась Armature, в то-же время на экране она отображалась в пописи как Armature.001 и я сделал две переменные, так скрипт заработал, и я оставил их две. Так-же задается и сколько кадров экспортировать, тк. кадры не содержащие анимации все равно экспортируются.

Экспорт арматуры персоонажа.

Арматура экспортируется через питон скриптом get-armature.py. Особенность скрипта, опять-же надо задать имя арматуры и поставить булеан триггер
#вытягиваемая арматура
myArmatureName = 'Armature'


#путь к экспорту
exportPathStr = 'D:\\FLEX\\3D\\proj-3d-engine\\pose-port\\armature.txt';


#не показывать голову и хвост
noHeadNoTail = False

#не показывать первоначальные матрицы
noSpaceMat = False

Тк. в ходе разработки, до меня дошло, что координаты head и tail костей в принципе не нужны для работы арматуры, они получаются сами собой при расчете кватернионов, то эти триггеры лучше поставить в False, что-бы эта лишняя инфа не увеличивала размер swf.

Экспорт меша для флеш анимации.

Mesh для flash экспортируется скриптом get-mesh.py
#вытягиваемый объект
myObfName = 'Cube'

#и группы вытягивать тоже
groupON = True

#путь к экспорту
exportPathStr = 'D:\\FLEX\\3D\\proj-3d-engine\\pose-port\\bone-mesh.txt';

Надо задать имя экспортируемого меша (это имя высвечивается на экране) и поставить триггер groupON в True, тк. надо тянуть индексы вершин, которые нужны для расчета анимации в кадрах. Еще у меша должны быть расщитаны uv координаты, тк. скрипт их экспортирует. Грани должны быть треугольные, для их отрисовки методом drawTriangless
Полный листинг питон скриптов будет в архиве.
Подумал и решил не портить этот чудесный, тутор для экспорта меша. Я имею ввиду, что кости так красиво шуршат, у меня рука не поднимается их убирать, допишу чуток, но косточки оставлю. Для визуального отображиния кости сделаю отдельный класс
package  
{
	import lex.d3.*;
	/**
	 * ...
	 * @author Alex Lexcuk http://www.murmadillo.tut.su
	 */
	public class VisioBone extends Obj3d
	{
		[Embed(source = 'color-bone.jpg')]
		private var Pic:Class;
		
		public function VisioBone() 
		{
			include "bone-mesh.txt"
			bmd = new Pic().bitmapData;
			//инвертировать текстурный битмап объекта
			mirrorBmdY();
		}
		
	}

}

Использовал оператор include, что-бы не копировать и потом всталять данные экспортированные из блендера в виде текстовых файлов. Ну что??? чувствуете мощь моего 3Д двига, нигде, так просто не вставляется триД модель. Пишем документ класс (с комментариями, что-бы народ смог чего-то понять).
package  
{
	import adobe.utils.XMLUI;
	import flash.display.*;
	import flash.events.Event;
	import flash.geom.*;
	import lex.d3.*;
	/**
	 * ...
	 * @author Alex Lexcuk http://www.murmadillo.tut.su
	 */
	public class Doc extends Sprite
	{
		[Embed(source = 'match.jpg')]
		private var Pic:Class;

		private var armature:Armature = new Armature();
		private var obj3d:Obj3d = new Obj3d();
		private var renderObj:ObjRender = new ObjRender();
		private var anim:AnimationObj = new AnimationObj();
		
		private var cam:Matrix3D = new Matrix3D();
		private var scaleObj:Number = 30;
		
		private var renderSp:Sprite;
		private var chapeArr:Vector.<Shape> = new Vector.<Shape>()
		private var frCount:int;
		private var frMax:int = 20;
		private var frRevers:Boolean = false;
		private var visioBone:VisioBone = new VisioBone();
		public function Doc() 
		{
			graphics.beginFill(0xFFFFFF);
			graphics.drawRect(0, 0, 550, 400);
			
			var i:int;
			with (obj3d) { include "match-mesh.txt"; }
			with (armature) { include 'armature.txt' }
			with (anim) { include 'animation.txt' }
			
			//задается текстура для объекта
			obj3d.bmd = new Pic().bitmapData;
			
			//инвертировать текстурный битмап объекта
			obj3d.mirrorBmdY();
			
			//подготовка углов камеры
			cam.appendScale(scaleObj, scaleObj, scaleObj);
			cam.appendRotation( 90, Vector3D.X_AXIS);
			
			//спрайт для рендера перца
			addChild(renderSp = new Sprite());
			
			renderSp.x = 250;
			renderSp.y = 300;
			
			armature.init();
			
			obj3d.usePose = true;
			
			obj3d.initGroup();
			
			obj3d.armature = armature;
			
			//добавление на спрайт для рендера кучи шейпов для отображения костей
			for (i = 0; i < armature.bones.length; i++) {
				renderSp.addChild(chapeArr[i] = new Shape());
				chapeArr[chapeArr.length - 1].alpha = 0.5;
			}
			
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}

		private function enterFrameHandler(e:Event):void {
			if (frRevers) frCount--; else frCount++;
			if (frCount < 0) { frRevers = false; frCount = 0 }
			if (frCount >= frMax) { frRevers = true; frCount = frMax }
			

			//координаты главной кости в фреймах
			var cx:Number = anim.centralBoneLoc[frCount][0];
			var cy:Number = anim.centralBoneLoc[frCount][1];
			var cz:Number = anim.centralBoneLoc[frCount][2];
			
			//подстановка кватернионов фрейма для перерасщета скелета
			armature.reCalcQuat(anim.animObjAr[frCount]);
			
			//сборка арматуры для текущих кватернионов костей
			armature.compilate(armature.boneObj[armature.masterBoneName], cx, cy, cz);
			
			//рендер костей
			renderBone();
			
			//рендер арматуры
			renderBear();
		}

		//рендер перца
		private function renderBear():void {
			var preCam:Matrix3D = new Matrix3D();
			preCam.identity();
			
			preCam.append(cam);
			
			var graphics:Graphics = renderSp.graphics;// chapeArr[i].graphics;
			
			graphics.clear();
			
			//для рендера объекта надо задать графику, какой объект рендерить и матрицу камеры
			renderObj.render(obj3d, preCam, graphics);
		}

		//рендер костей перца
		private function renderBone( ):void {
			
			var i:int;
			var preCam:Matrix3D = new Matrix3D();
			var pTrMat:Matrix3D = new Matrix3D();
			var bScaleXY:Number = 0.20;
			
			var obj3d:Obj3d = visioBone;
			
			var graphics:Graphics;
			var zArr:Vector.<Number> = new Vector.<Number>();
			
			for (i = 0; i < armature.bones.length; i++) {
				pTrMat.identity()
				pTrMat.appendScale(0.1*armature.bones[i].length, bScaleXY*armature.bones[i].length, bScaleXY*armature.bones[i].length);
				pTrMat.appendRotation( 90, Vector3D.Z_AXIS);
			
				preCam.identity();
				preCam.append(pTrMat);
				
				//при отображении кости в объекте надо брать localMat текущей кости в арматуре
				preCam.append(armature.bones[i].localMat);
				
				preCam.append(cam);
				
				renderSp.setChildIndex(chapeArr[i],0)
				
				graphics = chapeArr[i].graphics;
				
				graphics.clear();
				graphics = chapeArr[i].graphics;
				
				zArr[i] = renderObj.render(obj3d, preCam, graphics);
			}
			
			//z сортировка объектов
			var zind:Vector.<int> = renderObj.vecSortNum(zArr);
			
			//отображение костей по их z индексу
			for (i = 0; i < zind.length; i++) {
				renderSp.setChildIndex(chapeArr[zind[i]], 0);
			}
		}

	}

}

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

управляйте кнопками, слайдером и не забудте нажать правую кнопку мыши и выбрать там увеличить, что-бы рассмотреть заднюю часть спичечного коробка

Легко-же, на всякий случай архив с проектом, там есть бленд файлы, много весят по 250 кБ, классы двига, документ класс, питон экспортеры и все... остальное, текстуры для спичмена.