heihachi
> pos = pos + mul(Input.Position, wmArray[IndexArray[0]]* (1.0f - LastWeight));
> norm = norm + mul(Input.Position, wmArray[IndexArray[0]]* (1.0f - LastWeight));
Привет, попробуй вместо wmArray[IndexArray[0]] последний индекс wmArray[IndexArray] - твоя ошибка в этом
Чувак
> твоя ошибка в этом
нет.. ошибка уж точно не в этом! У меня передаётся остаточный вес на первую кость из ТЕХ которые действуют на эту вершину.. даже еслиб весь вес передавался то всеравно,хоть криво но выполнялась бы примерно таже анимация! а тут по каждой оси в разные стороны кидает! + эта "фишка" в шейдере используется безтолку! т.к. веса полностью распределяются в программе! и рапределяются правильно! (ну да, я убирал программно - одна фигня!) дело НЕ в этом!
heihachi
А ты пробовал сменить последний вес? Просто у меня в свое время как раз дико глючило из за последнего веса.. А без анимации файл не глючит?
elephantman
> просто у меня в свое время как раз дико глючило из за последнего веса..
пробовал. Ни чего не выходит путёвого. Изза того веса модель должна тянуться или некоторые вершины оставаться в начальной позиции.. не это происходит
без анимации всё кулЪ, модель проверил во вьювере с анимацией - нормальна! дайте ктонить свой загрузчег / отрисовщик
что было с чем сравнить а то вроде ну всё понятно! но не работает.. это больше всего и напрягает : (
и да - есть ли гденить гид типа загрузка SMD моделей и отрисовка анимации на DirectX ??
По DirectX - в DirectX SDK для C# есть примеры со скелетной анимацией (SimpleAnimation) По smd - где то было, если найду - скину
Да и кстати, AnimationController ты двигаешь (AdvanceTime(elapsed))?
elephantman
> По smd - где то было, если найду - скину
Буду очень признателен.
elephantman
> По DirectX - в DirectX SDK для C# есть примеры со скелетной анимацией
> (SimpleAnimation)
тофигня! У меня она работала изначально как часы... и я то ведь вроде как и знаю как работает анимация, более того, как написать её лоадер/рендер. Что очень странно что не работает это всё! Нету случайно экспортёра который сразу в LH координатную систему экспортирует? : )
п.с. чувак, обнови СДК! Давно уже для C# ни чего не пихают в СДК к сожалению
А с какого формата экспортер надо, с smd? - тогда нету
Посмотри тут может что то найдешь
elephantman
> А с какого формата экспортер надо, с smd?
не, чтоб сразу правильно для DirectX из 3D Max экспортировал
Panda DirectX Exporter
elephantman
> Panda DirectX Exporter
аррр нет : ) я проклял и изгнал Х формат! он ЗЛО! реквестирую экспортёр SMD из 3DMax который экспортирует правильную LeftHanded меш с анимацией ^__^
хмм странно это всё! я остановил принудительно рендеринг на 30 кадре (ессно не то, что должно быть отображается)
и попробовал вручную покрутить кости - нефиг делать! все кости чётко привязаны, веса правильно поставлены! все работает отлично! любой костью кручу как хочу . значит в матрицах всё дело. опишите точный полный процесс загрзки и создания матриц (со всеми шаманствами с обменом Y & Z координат и т.д. пожалуйсто
А сколько всего костей?
Ты MAX_BONES используешь вообще не в том контексте. Она здесь не нужна.
> int IndexArray[MAX_BONES] = (int[MAX_BONES])(Input.BlendIndices);
> float WeightArray[MAX_BONES] = (float[MAX_BONES])(Input.BlendWeights);
В корне неверно, правильно будет:
int IndexArray[4] = (int[4])(Input.BlendIndices);
float WeightArray[4] = (float[4])(Input.BlendWeights);
А вообще попробуй вот это (если нормалсмэпинг не нужен, бинормали и тангенты можешь убрать) и сверь со своей вертекдекларацией:
struct SkinnedInfoNBT
{
float4 Position;
float3 Normal;
float3 Tangent;
float3 Binormal;
};
SkinnedInfoNBT SkinVertexNBT( float4 Position, float3 Normal, float3 Tangent, uint4 BlendIndices, float4 BlendWeight )
{
SkinnedInfoNBT Output = (SkinnedInfoNBT)0;
//Bone0
uint iBone = BlendIndices.x;
float fWeight = BlendWeight.x;
matrix m = g_mBones[iBone];
Output.Position += fWeight * mul( Position, m );
Output.Normal += fWeight * mul( Normal, (float3x3)m );
Output.Tangent += fWeight * mul( Tangent, (float3x3)m );
//Bone1
if(BlendWeight.y > 0.0f)
{
iBone = BlendIndices.y;
fWeight = BlendWeight.y;
m = g_mBones[iBone];
Output.Position += fWeight * mul( Position, m );
Output.Normal += fWeight * mul( Normal, (float3x3)m );
Output.Tangent += fWeight * mul( Tangent, (float3x3)m );
}
//Bone2
if(BlendWeight.z > 0.0f)
{
iBone = BlendIndices.z;
fWeight = BlendWeight.z;
m = g_mBones[iBone];
Output.Position += fWeight * mul( Position, m );
Output.Normal += fWeight * mul( Normal, (float3x3)m );
Output.Tangent += fWeight * mul( Tangent, (float3x3)m );
}
//Bone3
if(BlendWeight.w > 0.0f)
{
iBone = BlendIndices.w;
fWeight = BlendWeight.w;
m = g_mBones[iBone];
Output.Position += fWeight * mul( Position, m );
Output.Normal += fWeight * mul( Normal, (float3x3)m );
Output.Tangent += fWeight * mul( Tangent, (float3x3)m );
}
Output.Binormal = cross(Normal, Tangent);
return Output;
}
struct VS_INPUT
{
float3 Position : POSITION;
float4 Weights : BLENDWEIGHT;
uint4 Indices : BLENDINDICES;
float2 TexCoord : TEXCOORD;
float3 Normal : NORMAL;
float3 Tangent : TANGENT;
};
struct XCPSInput
{
float4 Position : SV_Position;
float2 TexCoord : TEXTURE0;
float3 PositionWS : TEXTURE1;
float3 NormalWS : TEXTURE2;
float3 BinormalWS : TEXTURE3;
float3 TangentWS : TEXTURE4;
};
XCPSInput VSSceneNBT( VS_INPUT input )
{
SkinnedInfoNBT skinInfo = SkinVertexNBT( float4(input.Position, 1), input.Normal, input.Tangent, input.Indices, input.Weights );
XCPSInput output = (XCPSInput)0;
output.Position = mul(skinInfo.Position, g_mViewProjection);
output.TexCoord = input.TexCoord;
output.PositionWS = skinInfo.Position.xyz;
output.NormalWS = skinInfo.Normal;
output.TangentWS = skinInfo.Tangent;
output.BinormalWS = skinInfo.Binormal;
return output;
}
и еще, посмотри порядок умножения матриц анимации и костей. Порядок такой:
Child1*=Papent;
Child11*=Child1;
Child11*=Child12;
Bone1*=Child11;
Bone1*=Child12;
А вообше .SMD не самый лучшый выбор. Потеряй недельку и напиши собственный формат. Так глюки легче вылавливаются и модификация проще.
destrator
> Потеряй недельку и напиши собственный формат
у меня он есть только без анимации покачто.
destrator
> и еще, посмотри порядок умножения матриц анимации и костей. Порядок такой:
в любом порядке получается бред
шейдер у тебя немножко не универсален ты забыл про остаточный вес - если модель будет замоделена так что все кости в сумме не будут давать
1.0 вес то вершины будут "тянуться" к начальной позиции.
шейдер у меня 100% рабочий и декларация тоже! вот она:
VertexElement[] elements = new VertexElement[] { new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0), new VertexElement(0, 12, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Normal,0), new VertexElement(0, 24, DeclarationType.Float2, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate,0), new VertexElement(0, 32, DeclarationType.Float4, DeclarationMethod.Default, DeclarationUsage.BlendIndices,0), new VertexElement(0, 48, DeclarationType.Float4, DeclarationMethod.Default, DeclarationUsage.BlendWeight,0), VertexElement.VertexDeclarationEnd }; VertexDeclaration decl = new VertexDeclaration(CG.GraphicsDevice, elements);
Уфф тока громко не смеяться и не плеваться. писал код на скорую руку лишьбы одна анимация заработала а тогда уже в планах привести его в божеский вид и оптимизировать ибо он меганеоптимизирован
-- ФУНКЦИЯ ЗАГРУЗКИ АНИМАЦИИ
public static LifeAnimationTrack LoadSMDAnimation(string fileName, Skeleton skelet) { LifeAnimationTrack animationTrack = new LifeAnimationTrack(); float sampleRate = 30.0f; //get full animation path string filePath = LifeFileSystem.AnimationsPath + fileName; //++++++++++++++++++++++++++++LOAD SMD ANIMATION+++++++++++++++++++++++++++++ FileStream stream = new FileStream(filePath, FileMode.Open); StreamReader reader = new StreamReader(stream, true); string tmp = reader.ReadLine(); //Read header and check file version Debug.Assert(tmp.Split(' ')[1] == "1", "Wrong file version!"); SortedList<int, LifeFrame> frames = new SortedList<int, LifeFrame>(); //Skip everything up to "skeleton" token do tmp = reader.ReadLine(); while (tmp != "skeleton"); //move to the first bone string[] frameData; string[] tmpData; int frameKey = 0; int maxFrameNumber = 0; do { tmp = reader.ReadLine(); tmpData = tmp.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); //if new frame, add it to the buffer if (tmpData[0] == "time") { LifeFrame frame = new LifeFrame((float)Convert.ToInt32(tmpData[1])/sampleRate); frame.FrameName = Convert.ToInt32(tmpData[1]); frames.Add(Convert.ToInt32(tmpData[1]), frame); frameKey = Convert.ToInt32(tmpData[1]); maxFrameNumber = Convert.ToInt32(tmpData[1]); } else if(tmp!="end") //if not new frame, read transformation matrix for bone { tmp = tmp.Replace('.', ','); frameData = tmp.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); 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]))); int bn = Convert.ToInt32(frameData[0]); frames[frameKey].g_bonesTransformations.Add(bn, boneMatrix); } } while (tmp != "end"); //EOF, close any streams stream.Close(); reader.Dispose(); stream.Dispose(); animationTrack.FramesCount = maxFrameNumber + 1; animationTrack.TrackTime = maxFrameNumber / sampleRate; animationTrack.Frames = new LifeFrame[maxFrameNumber + 1]; frames.Values.CopyTo(animationTrack.Frames, 0); return animationTrack; }
--ФУНКЦИЯ ЗАГРУЗКИ МОДЕЛИ (в ней внутри используется предыдущая функция)
public static Geometric LoadModelSMD(string fileName) { //get full model path string filePath = LifeFileSystem.ObjectsPath + fileName; //++++++++++++++++++++++++++++LOAD SMD+++++++++++++++++++++++++++++ SkinInforamtion skinInfo = new SkinInforamtion(); List<TRIANGLE> triCache = new List<TRIANGLE>(); Skeleton ObjSkeleton = new Skeleton(); FileStream stream = new FileStream(filePath, FileMode.Open); StreamReader reader = new StreamReader(stream, true); string tmp = reader.ReadLine(); //Read header and check file version Debug.Assert(tmp.Split(' ')[1] == "1", "Wrong file version!"); //skip everything to move to "nodes" block do tmp = reader.ReadLine(); while (tmp != "nodes"); tmp = reader.ReadLine();//advance position to the first node string[] nodeData; //Read nodes int boneCnt = 0; do { boneCnt++; nodeData = tmp.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); //Add a bone to the skeleton BONE b = ObjSkeleton.AddBone( new BONE(Convert.ToInt32(nodeData[0]), nodeData[1], ObjSkeleton.GetBone(Convert.ToInt32(nodeData[2])))); //If current bone is not root, we'll add current node as a child to the parent bone ObjSkeleton.GetBone(Convert.ToInt32(nodeData[2])).AddChild(b); ObjSkeleton.maxBoneID = b.ID; tmp = reader.ReadLine(); } while (tmp != "end"); skinInfo.BonesCount = boneCnt; //Skip everything up to "skeleton" token do tmp = reader.ReadLine(); while (tmp != "skeleton"); //move to the first bone string[] frameData; tmp = reader.ReadLine(); tmp = reader.ReadLine(); do { tmp = tmp.Replace('.', ','); frameData = tmp.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); 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]))); ObjSkeleton.GetBone(Convert.ToInt32(frameData[0])).BaseMatrix = boneMatrix; ObjSkeleton.GetBone(Convert.ToInt32(frameData[0])).LocalMatrix = Matrix.Identity; tmp = reader.ReadLine(); } while (tmp != "end"); LifeAnimationController cntrl = new LifeAnimationController(); cntrl.g_skeleton = ObjSkeleton; LifeAnimationTrack track = LoadSMDAnimation(fileName, ObjSkeleton); cntrl.AddTrack(track); skinInfo.Controller = cntrl; skinInfo.Skeleton = ObjSkeleton; //check, if we need to load this geometry. maybe we have it in our cache already. if (g_geometryCache.Count > 0) for (int i = 0; i < g_geometryCache.Count; i++) if (g_geometryCache.Values[i].ResourceDataName == filePath) { return g_geometryCache[i]; } //Skip everything up to "triangles" token do tmp = reader.ReadLine(); while (tmp != "triangles"); //move to the first triangle tmp = reader.ReadLine(); //reading triangles string[] triData; CustomVertex.Skinned v1, v2, v3; int parentBone; do { TRIANGLE tri = new TRIANGLE(); //read texture name triData = tmp.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); tri.TextureName = triData[0]; //------------------1'st vertex--------------------- tmp = reader.ReadLine(); tmp = tmp.Replace('.', ','); //read first vertex triData = tmp.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); parentBone = Convert.ToInt32(triData[0]); v1 = new CustomVertex.Skinned(); v1.Position = new Vector3( Convert.ToSingle(triData[1]), Convert.ToSingle(triData[3]), Convert.ToSingle(triData[2])); v1.Normal = new Vector3( Convert.ToSingle(triData[4]), Convert.ToSingle(triData[6]), Convert.ToSingle(triData[5])); v1.Texture = new Vector2( Convert.ToSingle(triData[7]), Convert.ToSingle(triData[8])); //reading bones count, which affecting on current vertex v1.Bones = new Vector4(0, 0, 0, 0); v1.Weights = new Vector4(0, 0, 0, 0); float totalWeight = 0; int offset = 9; int numBones = 0; if (triData.Length > 9) { numBones = Convert.ToInt32(triData[9]); if (numBones > 4) Debug.Fail("Bones limit overflow!", "Maximum allowed count of bones per vertex: 4\nbut current bones count per vertex is: " + numBones.ToString()); for (int i = 0; i < numBones; i++) { if (i == 0) { v1.Bones.X = (float)Convert.ToInt32(triData[++offset]); v1.Weights.X = Convert.ToSingle(triData[++offset]); totalWeight += v1.Weights.X; } else if (i == 1) { v1.Bones.Y = (float)Convert.ToInt32(triData[++offset]); v1.Weights.Y = Convert.ToSingle(triData[++offset]); totalWeight += v1.Weights.Y; } else if (i == 2) { v1.Bones.Z = (float)Convert.ToInt32(triData[++offset]); v1.Weights.Z = Convert.ToSingle(triData[++offset]); totalWeight += v1.Weights.Z; } else if (i == 3) { v1.Bones.W = (float)Convert.ToInt32(triData[++offset]); v1.Weights.W = Convert.ToSingle(triData[++offset]); totalWeight += v1.Weights.W; } } } float addWeight = 1.0f - totalWeight; if (addWeight > 0) if ((int)v1.Bones.X == parentBone) v1.Weights.X += addWeight; else if ((int)v1.Bones.Y == parentBone) v1.Weights.Y += addWeight; else if ((int)v1.Bones.Z == parentBone) v1.Weights.Z += addWeight; else if ((int)v1.Bones.W == parentBone) v1.Weights.W += addWeight;
----------продолжение далее
Тема в архиве.