Seite 1 von 1
[ASSIMP] Skelett verdreht
Verfasst: 12.06.2013, 14:05
von Andre
Hallo liebe ZFX-Gemeinde! :D
Ich bin in den letzten Tagen (oder Wochen?) in den Genuss gekommen das erste mal Skeletal-Animations irgendwo einzubauen, was auch bis fast zum Schluss recht gut voran ging.
Jetzt stimmt so gut wie alles, nur will mein Skelett nicht so wirklich ins Mesh passen. Zum einen ist es klar verdreht, und zum anderen passt es auch nicht wenn man selbst versucht es richtig hinzudrehen.
Im Assimp-Viewer sieht das ganze so aus:
In meinem Programm allerdings so:
Hier ist eben alles zur Seite gekippt.
Versuche ich selbst die Bones richtig hinzudrehen (was ich ja eigentlich nicht tun müsste) kommt das hier bei raus:
Während die Füße und der Schwanz hier korrekt sind, sind die Bones für Augen und Mund viel zu weit hinten.
Stelle ich die Bind-Pose überhaupt richtig da? Ich habe für die Positionen der einzelnen Bones einfach die Position aus der Transformation-Matrix der Node des Bones genommen.
Weder das Mesh selbst, noch die Root-Node sind übrigens gedreht worden. Mesh und Animation werden aus einer COLLADA-Datei geladen und in ein eigenes Format konvertiert.
Ist es möglich, dass auf diesem Weg sich so ein Fehler einschleichen könnte? Ich lade die Transformationen für Levelgeometrie eigentlich auf dem selben weg wie die der Bones...
Hat vielleicht jemand eine Idee was ich mir anschauen sollte?
Re: [ASSIMP] Skelett verdreht
Verfasst: 12.06.2013, 17:08
von Ingrater
Es könnte sein das sich aus irgendeinem grund eine Rechtshändig auf Linkshändig konvertierung eingeschlichen hat. Um das zu beheben reicht es nicht das Skelett zu drehen. Du musst die Z und Y achse vertauschen und dann und dann noch die z achse invertieren. Also
y_neu = z_alt
z_neu = y_alt * -1
Mit was hast du denn exportiert? Bei 3ds max kann man beim export von Collada die Up-Axis einstellen, vielleicht liegts daran.
Re: [ASSIMP] Skelett verdreht
Verfasst: 12.06.2013, 20:57
von Andre
Eigentlich wird da nichts umkonvertiert, hab eben nochmal geschaut. Wie gesagt, die Transformationsmatrizen der Levelgeometrie werden auf dem selben weg geladen. Ich werde mal die Positionen der Bones direkt nach dem Import durch Assimp und nach dem Konvertieren in mein eigenes Format vergleichen.
Edit: Kurz an die frische Luft gehen hilft Wunder. Ich bin für die BindPose die Matrizen nicht vom Root durchgegangen sondern hab einfach nur die der Node genommen. Jetzt sieht alles gut aus :)
Re: [ASSIMP] Skelett verdreht
Verfasst: 20.06.2013, 18:52
von Andre
Es ist doch noch nicht alles gut. Ich habe zwar die Positionen der einzelnen Bones richtig darstellen können, aber die Vertices wollen sich daran einfach nicht richtig anhängen lassen.
Wenn ich es genau so wie in diesem Tutorial mache, in dem Skeletal-Animation mit Assimp beschrieben wird, so bekomme ich einfach kein richtiges Ergebnis:
Hier ist der Code, welcher die Matrizen der einzelnen Bones ausrechnet:
Code: Alles auswählen
/** Recalculates the bones transform matrix */
void Bone::RecalcMatrix(float animationTime)
{
XMFLOAT3 pos = InterpolatePosition(animationTime);
XMFLOAT4 rot = InterpolateRotation(animationTime);
XMFLOAT3 scale = InterpolateScale(animationTime);
XMVECTOR vPos = XMLoadFloat3(&pos);
XMVECTOR vRot = XMLoadFloat4(&rot);
XMVECTOR vScale = XMLoadFloat3(&scale);
XMMATRIX mat;
mat = XMMatrixScalingFromVector(vScale);
mat *= XMMatrixRotationQuaternion(vRot);
mat *= XMMatrixTranslationFromVector(vPos);
// Get parents transform
XMMATRIX parentMat;
if(Parent)
parentMat = XMLoadFloat4x4(&Parent->NodeTransform);
else
parentMat = XMMatrixIdentity();
//XMMATRIX invBindPosMat = XMMatrixInverse(nullptr, XMLoadFloat4x4(&BindPoseMatrix));
//XMMATRIX bindPoseMatrix = XMLoadFloat4x4(&BindPoseMatrix);
XMMATRIX offsetMat = XMLoadFloat4x4(&OffsetMatrix);
// Compute this bones transform
XMMATRIX nodeTrans = parentMat * mat;
XMMATRIX globalInverseTransform = XMLoadFloat4x4(&GlobalInverseTransform);
// Store final transformation matrix
XMStoreFloat4x4(&Matrix, globalInverseTransform * nodeTrans * offsetMat);
// Store this bones transform for the children
XMStoreFloat4x4(&NodeTransform, nodeTrans);
// Compute the other transforms
for(int i=0; i<ChildBones.size();i++)
{
ChildBones[i]->RecalcMatrix(animationTime);
}
}
Und hier mein VertexShader (Muss noch etwas aufgeräumt werden, fürchte ich :roll:) :
Code: Alles auswählen
static const int MAX_BONES = 32;
cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
matrix model;
matrix view;
matrix projection;
float Time;
};
cbuffer ExplosionBuffer : register(b1)
{
float State;
};
cbuffer BoneBuffer : register(b2)
{
matrix Bones[MAX_BONES];
};
struct VertexShaderInput
{
float3 Position : POSITION;
float3 Normal : NORMAL;
float2 TexCoord : TEXCOORD0;
int4 BoneIDs : BONEIDS;
float4 Weights : WEIGHTS;
};
struct VertexShaderOutput
{
float2 TexCoord : TEXCOORD0;
float3 Normal : NORMAL;
float4 Pos : SV_POSITION;
};
SamplerState DefSampler;
VertexShaderOutput main(VertexShaderInput input)
{
VertexShaderOutput output;
float4 pos = float4(input.Position, 1.0f);
/*float nTime = Time;
float rand = sin(3*(pos.x+Time+pos.y+pos.z));
// Pressure
float p = min(State,1);
pos.xyz *= 1 + 0.125 * rand * p;
// Explosion
float e = max(1,min(State,2))-1;
pos.xyz *= 1 + (e*(rand + 1.5f));*/
matrix boneTransform = Bones[input.BoneIDs[0]] * input.Weights[0];
boneTransform += Bones[input.BoneIDs[1]] * input.Weights[1];
boneTransform += Bones[input.BoneIDs[2]] * input.Weights[2];
boneTransform += Bones[input.BoneIDs[3]] * input.Weights[3];
// Transform the vertex position into projected space.
pos = mul(pos, boneTransform);
pos = mul(pos, model);
pos = mul(pos, view);
pos = mul(pos, projection);
output.Pos = pos;
// Pass through the color without modification.
output.Normal = mul(input.Normal, (float3x3)model);
//output.Normal = mul(output.Normal, (float3x3)boneTransform);
output.TexCoord = float2(input.TexCoord.x, input.TexCoord.y * -1);
output.Normal = input.Weights.rgb;
return output;
}
Nun bin ich mir was einige Matrizen angeht nicht gerade sicher was sie sind. Was genau ist z.B. die OffsetMatrix? Ist es einfach die InverseBindPose-Matrix vom Bone? Muss ich die Offset-Matrizen vorher noch vom Root aus durchmultiplizieren, für jeden Bone?
Hat jemand eine Ahnung was ich falsch mache? :(
Re: [ASSIMP] Skelett verdreht
Verfasst: 20.06.2013, 21:21
von Schrompf
Bin grad kurz angebunden, aber normalerweise geht das so:
ErgebnisMatrix = InverseBindPose (ja, das ist die Offsetmatrix) * BoneNode * ParentNode * ParentNode usw.
Vorausgesetzt, Dein Matrix-Layout ist so rum, dass a*b zuerst A und dann B ausführt. Ansonsten umdrehen.
Die Matrizen lädst Du dann in den Shader hoch und transformierst damit die Vertizes, bevor Du WorldMatrix, ViewMatrix usw. anwendest. Und achte auf das Matrix-Layout im Shader, dass Du bei HLSL mit "column_major" und "row_major" (Standard) einstellen kannst. Bei Bone-Matrizen, die ja in großer Stückzahl auftreten, bietet sich column_major 4x3 an, weil das pro Matrix ein Konstantenregister weniger braucht. Das Matrix-Layout im Shader hat aber *wieder* Einfluss auf die Multiplikationsreihenfolge. Rechne also Dein mul() besser auf Papier durch oder probier beide Richtungen aus.
Re: [ASSIMP] Skelett verdreht
Verfasst: 21.06.2013, 02:10
von Andre
Ich wollte fast schon wieder für heute aufgeben, aber ich habs endlich nun doch noch hinbekommen!
Die Reihenfolge wie du sie mir gesagt hast stimmt auf jeden Fall so. Was später noch meine Probleme waren:
Es steckte noch das bisschen von Ingraters Tipp in meinen Position-Keys (also unnötige RH zu LH-Konvertierung) und die BindPoseMatrix war nicht vom Root durch die Bones zusammenmultipliziert. Dachte das passiert schon dadurch, dass man seine Matrizen noch mit der Parentmatrix bei der Animation multipliziert.
Diesesmal stimmt nun aber wirklich alles:
Danke für die Hilfe :)
Re: [ASSIMP] Skelett verdreht
Verfasst: 29.12.2013, 05:32
von Slin
Öhm, das Thema ist zwar alt, aber da ich gerade mit ähnlichen Problemen kämpfe: Die mOffsetMatrix ist doch schon die fertige inverse BindPose Matrix oder nicht? Also da muss ich nichts mehr von der Wurzel aufmultiplitzieren?
Also eigentlich bin ich der Meinung, dass ich inzwischen eigentlich alles korrekt mache und bei manchen Modellen ist auch alles super, bei anderen aber eher weniger...
Wenn ich zum Beispiel dwarf.x von psionic (ist für einige Formate auch mit in den Assimp Testmodellen) lade, dann steckt die obere Hälfte in der Unteren, es sind aber beide einzeln korrekt animiert (
http://cld.slindev.com/T7g0). Bei einem anderen Modell habe ich das Problem dass ein Teil perfekt funktioniert und andere Teile sich nicht bewegen, das Modell selbst ist aber korrekt. Außerdem gehen einige der funktionierenden auch kaputt sobald ich die Skalierung wieder mit in die Animation nehme, da dort irgendwie komische Werte drinn stehen (auch bei dem Zwerg...). Also insgesamt ist mein Ergebnis sehr durchwachsen bisher und ich würde es gern schaffen, dass es mit den meisten Modellen die ich darauf werfe ohne es vorher anpassen zu müssen korrekt funktioniert...
Für irgendwelche generellen Ideen und Tipps wäre ich da echt dankbar :)
Den Assimp Viewer gibt es nicht für OSX, oder? Denn sonst könnte ich testweise damit auch mal einige Modelle überprüfen ohne jedes mal neuzustarten...
Re: [ASSIMP] Skelett verdreht
Verfasst: 31.12.2013, 06:47
von Slin
Wie sich herausgestellt hat, habe ich Bones vergessen in mein Skelett aufzunehmen, die nicht direkt Geometrie zugeordnet waren. Außerdem habe ich einen Fehler in meinem Code um die Skalierung zu importieren gefunden und zur Sicherheit nutze ich jetzt auch alle Nodes bis zur Wurzel, die irgendwie entfernt Parent Nodes von Bones sind.
Nach verdammt viel Arbeit und Herumprobiere und hässlichem Code bin ich jetzt tatsächlich an einem Punkt an dem bisher jedes getestete Modell korrekt funktioniert :).