Привет.
Блин, прогаю C# + SlimDX
Сделал загрузчик моделей и анимации SMD. Модель рисуется отлично (ну кроме багов с нормалями но то не суть важно).
Первый кадр как и в редакторе но вот с анимацией траблы : ( Я быстро накидал AnimationController и попробовал проиграть анимацию.. о жесть! Модель всю корячит так шо ппц. Уже 3 день не могу понять в чём причина. Сейчас наглядно покажу:
это первый кадр (3D Max):
вот кадр анимации #30 (3DMAX)
а это кадр анимации #30 в моём "движке"
Как видите, анимация в моём движке не особо похожа на ту, что нужна.
В чём может быть причина?
вся анимация рисуется через шейдер (не кидайтесь помидорами, я его на скорую руку написал, лишь бы работал)
#define MAX_MATRICES 50 #define MAX_BONES 4 float4x4 matWVP : WORLDVIEWPROJECTION; float4x4 matVP : VIEWPROJECTION; float4x4 matWV : WORLDVIEW; float3 sunPosition : SUN; float4x4 matW : WORLD; float4 ambient : AMBIENT, diffuse : DIFFUSE, specular : SPECULAR, emissive : EMISSIVE; Texture baseTexture : TEXTURE_BASE; float4x4 wmArray[MAX_MATRICES]; sampler baseSampler = sampler_state { texture = <baseTexture>; minfilter = anisotropic; magfilter = anisotropic; }; struct VS_INPUT { float4 Position : POSITION0; float2 Texcoord : TEXCOORD0; float3 Normal : NORMAL; float4 BlendWeights : BLENDWEIGHT; float4 BlendIndices : BLENDINDICES; }; struct VS_OUTPUT { float4 Position : POSITION0; float2 Texcoord : TEXCOORD0; float3 Normal : TEXCOORD1; float3 Light: TEXCOORD2; }; VS_OUTPUT vs_main( VS_INPUT Input ) { VS_OUTPUT Output; Output.Texcoord = Input.Texcoord; int IndexArray[MAX_BONES] = (int[MAX_BONES])(Input.BlendIndices); float WeightArray[MAX_BONES] = (float[MAX_BONES])(Input.BlendWeights); float LastWeight = 0; float4 pos = 0; float4 norm = 0; for(int i = 0; i<MAX_BONES;i++) { LastWeight = LastWeight + WeightArray[i]; pos = pos + mul(Input.Position, wmArray[IndexArray[i]]*WeightArray[i]); norm = norm + mul(Input.Position, wmArray[IndexArray[i]]*WeightArray[i]); } pos = pos + mul(Input.Position, wmArray[IndexArray[0]]* (1.0f - LastWeight)); norm = norm + mul(Input.Position, wmArray[IndexArray[0]]* (1.0f - LastWeight)); Output.Position = mul(pos,matVP); Output.Normal = norm.xyz; Output.Light = sunPosition.xyz - Output.Position.xyz; return( Output ); } struct PS_INPUT { float2 Texcoord : TEXCOORD0; float3 Normal : TEXCOORD1; float3 Light: TEXCOORD2; }; float4 ps_main( PS_INPUT Input ) : COLOR0 { return float4(float3(1,1,1) * dot(normalize(Input.Normal), normalize(Input.Light)),1); } technique Default_Skin { pass Pass_0 { // cullmode = none; VertexShader = compile vs_3_0 vs_main(); PixelShader = compile ps_3_0 ps_main(); } }
Позиции вершин и анимация (положение, поворот кости) грузятся так: XZY (Y и Z меняем местами)
Иерархия костей 100% верная - проверял каждую кость вручную.
Как считаюабсолютную трансформацию кости:
для каждой кости выполняется её функция: (псевдокод)
AbsoluteMatrix = ParentMatrix * (BaseMatrix * FrameMatrix);
где ParentMatrix - абсолютная матрица родительской кости, BaseMatrix - инвертированная матрица первого кадра,
FrameMatrix - матрица нынешнего кадра.
Нужна ваша помощь ибо у самого скоро мосх разорвёт на куски : ( заранее спасибо!
На всякий случай:
сама модель (SMD):
Model SMD
её анимация:
Анимация SMD
Чтото гдето не так с матрицами костей делаешь... Сложно сказать конкретно, может гдето на бинд позу не помножил, может наоборот помножил, да зря... :) Смотря как там всё хранится...
ок, довайте разбираться...
как всё хранится:
(немного у меня не оптимизированно но мне главное сейчас результат а потом оптимизирую ^^)
Есть класс Skeleton
в нём массив костей. У каждой кости есть Имя, ID, ссылки на родительскую кость и на дочерние кости. У Root кости ссылка на родителя = null
итак:
1. RootBone - кость с ID = -1. на неё ни что в меше не забиндено. Она просто root-ом является и всё. Все её матрицы = Identity.
У RootBone 2 дочерних кости: кость с ID = 0 - сам меш. У меня от неё ни чего не наследуется. И вторая кость с ID = 1 - первая "реальная" кость в скелете. И далее у этой кости есть дети, у детей другие дети и т.д. - обычное дерево.
Как происходит у меня анимация:
1. Блендю матрицы анимации, полученные матрицы выставляю костям! (у кости она называется LocalMatrix)
у RootBone вызываем функцию
public void UpdateMatrices() { if(Parent !=null) WorldMatrix = Parent.WorldMatrix *(g_baseMat * LocalMatrix); if (Childs != null && Childs.Length > 0) for (int i = 0; i < Childs.Length; i++) Childs[i].UpdateMatrices(); }
тут g_baseMat это инвертированная матрица первого кадра.
Вот так у меня хранится
Если для геометрии нужно Y и Z координаты вершин поменять местами, нужно ли их менять местами для поворотов?
и ещё, вот как я строю (читаю) матрицу кости..это верно?
Matrix boneMatrix = Matrix.RotationX(Convert.ToSingle(frameData[4])) * Matrix.RotationY(Convert.ToSingle(frameData[6])) * Matrix.RotationZ(Convert.ToSingle(frameData[5])) * Matrix.Translation(new Vector3( Convert.ToSingle(frameData[1]), Convert.ToSingle(frameData[3]), Convert.ToSingle(frameData[2])));
up ^
^
Если уж ни кто помочь не может, может поделитесь загрузчиком/отрисовщиком SMD? Желательно только это без лишнего кода - чтоб только загружалась и отображалась модель. C++ или C# - не важно. Ессно на DirectX. Спасибо.
блин... типа ни у кого SMD не грузится??? > : (
Не понятно что происходит с поворотами костей о_О
вот сначала как я всё гружу и рисую (псевдокодом)
1. ЗАГРУЗКА МОДЕЛИ
а. грузим скелет - строим иерархию согласно nodes блоку. (Класс Skeleton - в нём хранится rootBone (класс Bone) в котором ссылки надочерние кости, у каждой кости также есть ссылка на родительскую кость)
б. каждой ноде загружаем трансформации первого кадра из блока skeleton
как именно:
>6 1.909899 -0.000000 0.000000 0.000000 0.000000 -0.007202
7 сегментов - сегмент #1 = ID кости, беру эту кость
читаю позиции в float px,py,pz; МЕНЯЯ местами Y и Z координаты (переводим в координатную систему DirectX)
читаю повороты в float rx,ry,rz; МЕНЯЯ местами Y и Z координаты (переводим в координатную систему DirectX)
теперь создаю из полученных данных матрицу: BaseMatrix = MatrixRotationX(rx) * MatrixRotationY(ry) *
MatrixRotationZ(rz) * MatrixTranslation(tx,ty,tz);
итого получил скелет со связанными в правильную иерархию костями и их матрицами из первого кадра
в. читаю треугольники - у каждой вершины меняю также местами Y и Z координаты.
2. ЧИТАЮ ФАЙЛ С АНИМАЦИЕЙ
там всё просто есть класс AnimationTrack в него загружаются все кадры.. в каждом кадре для каждой кости загружается матрица трансформации. (матрица грузится также как и при загрузке модели в п.1)
3. ОТРИСОВКА
интерполирую кадры (тут всё чётко) получаю матрицы трансформаций для каждой кости.
WorldMatrix = ParentMatrix * (Matrix.Invert(BaseMatrix) * LocalMatrix);
где:
WorldMatrix = абсолютная матрица кости,
ParentMatrix = абсолютная матрица родительской кости,
(Matrix.Invert(BaseMatrix)) - инверсия базовой матрицы - матрицы нулевого кадра.
LocalMatrix кости = текущая интерполированная матрица.
полученные абсолютные матрицы передаю в шейдер (см. выше)
позиция норме но повороты ужасны - по совсем другим осям крутятся кости)
Такое ощущение, что для каждой точки трансформаций, система координат установлена по разному и движутся они поэтому не туда, куда надо. Проверь в максе точки трансформаций, попробуй какой нибудь ResetXForm применить к модели.
Может дело не в бобине?
JR-44
> Такое ощущение, что для каждой точки трансформаций, система координат
> установлена по разному и движутся они поэтому не туда, куда над
вот вот так и есть! те кости, что лежат вдоль оси Х, они НОРМАЛЬНО движутся! Остальные кости также и с такой скоростью поворачиваются как в максе но по другим осям! Не понятно почему : (
ResetXForm я попробую но AFAIK это устраняет только проблемму с инвертированными нормалями!
Просьба затестить прикреплённые к посту #1 модель и анимацию! Может действительно в НИХ проблема а не в моём коде?
ОЧЕНЬ нужно! Риальне! Мегареспект за любую помощь!
У меня тока х файлы грузит. Попробуй ее куда нибудь импортни - какую нибудь прогу, которая анимацию показывает и увидишь. Или попробовать импортнуть последний кадр анимации в DeepEploration например, тока надо в максе экспортнуть последний кадр.
В максе посмотри куда направлены оси координат этих центров. Они должны совпадать.
Тема в архиве.