[ASSIMP] Skelett verdreht

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Andre
Establishment
Beiträge: 186
Registriert: 21.12.2011, 20:33

[ASSIMP] Skelett verdreht

Beitrag 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:
bones_assimpviewer.jpg
In meinem Programm allerdings so:
bones_original.jpg
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:
bones_rotated.jpg
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?
Benutzeravatar
Ingrater
Establishment
Beiträge: 103
Registriert: 18.04.2007, 21:52

Re: [ASSIMP] Skelett verdreht

Beitrag 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.
Andre
Establishment
Beiträge: 186
Registriert: 21.12.2011, 20:33

Re: [ASSIMP] Skelett verdreht

Beitrag 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 :)
Andre
Establishment
Beiträge: 186
Registriert: 21.12.2011, 20:33

Re: [ASSIMP] Skelett verdreht

Beitrag 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:
animationkaputt.jpg
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? :(
Benutzeravatar
Schrompf
Moderator
Beiträge: 5047
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: [ASSIMP] Skelett verdreht

Beitrag 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.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Andre
Establishment
Beiträge: 186
Registriert: 21.12.2011, 20:33

Re: [ASSIMP] Skelett verdreht

Beitrag 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:
animationrichtig.jpg
Danke für die Hilfe :)
Slin
Beiträge: 44
Registriert: 15.05.2010, 01:21
Echter Name: Nils Daumann
Wohnort: Lübeck
Kontaktdaten:

Re: [ASSIMP] Skelett verdreht

Beitrag 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...
Slin
Beiträge: 44
Registriert: 15.05.2010, 01:21
Echter Name: Nils Daumann
Wohnort: Lübeck
Kontaktdaten:

Re: [ASSIMP] Skelett verdreht

Beitrag 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 :).
Antworten