Hi,
ich hab es jetzt nach einigen Nächten hingekriegt. Es hat wirklich geholfen sich die Mathematik einmal genau klar zu machen ...
Danke nochmal für den Link FredK das hat wirklich geholfen.
Ich hab es zwar geschafft das Skelett aus einer Milkshapedatei auszulesen. Aber die Animationen krieg ich immer noch nicht raus.
Stattdessen hab ich jetzt die Animationen einfach hart gecoded (das Milkshape Dateiformat ist wirklich nicht das Wahre).
Für all diejenigen, die mal auf das Problem stoßen sollten hier mein Berechnung der Animationsmatrizen:
Code: Alles auswählen
void BBEJOINT::CalculateAnimationMatrix(const float Time,
const float StartTime,
const float EndTime,
const BOOL MultiAnimations)
{
if (MultiAnimations && m_Touched)//Multianimationsmodus und der Joint wurde schon einmal berechnet
return;
int LeftRot=-1;
int RightRot=-1;
for (int i=0;i < m_NumberOfRotations;i++)
{
if (m_pRotations[i].m_Time > EndTime)//Hier muss immer ein echt größer stehen
break;
if (m_pRotations[i].m_Time >= Time)//Hier muss immer ein größer gleich stehen
{
RightRot=i;
break;
}
if (m_pRotations[i].m_Time >= StartTime)//Hier muss immer ein größer gleich stehen
LeftRot=i;
}
int LeftPos=-1;
int RightPos=-1;
for (int i=0;i < m_NumberOfTranslations;i++)
{
if (m_pTranslations[i].m_Time > EndTime)//Hier muss immer ein echt größer stehen
break;
if (m_pTranslations[i].m_Time >= Time)//Hier muss immer ein größer gleich stehen
{
RightPos=i;
break;
}
if (m_pTranslations[i].m_Time >= StartTime)//Hier muss immer ein größer gleich stehen
LeftPos=i;
}
//Rotation
BBEMATRIX Transformation;
if (LeftRot != -1 && RightRot == -1)//Wir sind rechts am Ende
{
D3DXMatrixRotationYawPitchRoll(&Transformation, m_pRotations[LeftRot].m_Data.y, m_pRotations[LeftRot].m_Data.x, m_pRotations[LeftRot].m_Data.z);
m_IsIdentity=false;
}
else if (LeftRot == -1 && RightRot == -1)//Keine Rotation vorhanden
{
D3DXMatrixIdentity(&Transformation);
m_IsIdentity=true;
}
else//Alles normal
{
float LeftTime;
if (LeftRot == -1)//Haben wir links noch eine Keyframe?
LeftTime=StartTime;
else
LeftTime=m_pRotations[LeftRot].m_Time;
//Berechne Skalierung
float Scale=(Time - LeftTime) / (m_pRotations[RightRot].m_Time - LeftTime);
BBEVECTOR Rotation;
if (LeftRot != -1)//Haben wir links noch eine Keyframe?
Rotation=(1.0f-Scale)*m_pRotations[LeftRot].m_Data + Scale*m_pRotations[RightRot].m_Data;//Interpolieren
else//Ansonsten Nullvektor für Links nehmen
Rotation=Scale*m_pRotations[RightRot].m_Data;//Interpolieren
if (m_pParent)
{
if (!m_pParent->m_IsIdentity)
{
BBEVECTOR NewRotation;
NewRotation.x=m_pParent->m_Final._11*Rotation.x + m_pParent->m_Final._21*Rotation.y + m_pParent->m_Final._31*Rotation.z;
NewRotation.y=m_pParent->m_Final._12*Rotation.x + m_pParent->m_Final._22*Rotation.y + m_pParent->m_Final._32*Rotation.z;
NewRotation.z=m_pParent->m_Final._13*Rotation.x + m_pParent->m_Final._23*Rotation.y + m_pParent->m_Final._33*Rotation.z;
D3DXMatrixRotationYawPitchRoll(&Transformation, NewRotation.y, NewRotation.x, NewRotation.z);
}
else
D3DXMatrixRotationYawPitchRoll(&Transformation, Rotation.y, Rotation.x, Rotation.z);
}
else
D3DXMatrixRotationYawPitchRoll(&Transformation, Rotation.y, Rotation.x, Rotation.z);
m_IsIdentity=false;
}
//Translation
if (LeftPos != -1 && RightPos == -1)//Wir sind rechts am Ende
{
Transformation._41=m_pTranslations[LeftPos].m_Data.x;
Transformation._42=m_pTranslations[LeftPos].m_Data.y;
Transformation._43=m_pTranslations[LeftPos].m_Data.z;
m_IsIdentity=false;
}
else if (LeftPos != -1 || RightPos != -1)//Alles normal
{
float LeftTime;
if (LeftPos == -1)//Haben wir links noch eine Keyframe?
LeftTime=StartTime;
else
LeftTime=m_pTranslations[LeftPos].m_Time;
//Berechne Skalierung
const float Scale=(Time - LeftTime) / (m_pTranslations[RightPos].m_Time - LeftTime);
//Interpolieren
const float rScale=1.0f-Scale;
Transformation._41=rScale*m_pTranslations[LeftPos].m_Data.x + Scale*m_pTranslations[RightPos].m_Data.x;
Transformation._42=rScale*m_pTranslations[LeftPos].m_Data.y + Scale*m_pTranslations[RightPos].m_Data.y;
Transformation._43=rScale*m_pTranslations[LeftPos].m_Data.z + Scale*m_pTranslations[RightPos].m_Data.z;
m_IsIdentity=false;
}
//Den Joint in seine neue Position transformieren
if (!m_IsIdentity)//Optimierung, falls nichts anliegt können wir uns das sparen
{
BBEVECTOR NewPosition=m_Position;
if (m_pParent)
{
if (!m_pParent->m_IsIdentity)//Falls Einheitsmatrix ist das hier überflüssig
{
NewPosition.x=m_pParent->m_Final._11*m_Position.x + m_pParent->m_Final._21*m_Position.y + m_pParent->m_Final._31*m_Position.z + m_pParent->m_Final._41;
NewPosition.y=m_pParent->m_Final._12*m_Position.x + m_pParent->m_Final._22*m_Position.y + m_pParent->m_Final._32*m_Position.z + m_pParent->m_Final._42;
NewPosition.z=m_pParent->m_Final._13*m_Position.x + m_pParent->m_Final._23*m_Position.y + m_pParent->m_Final._33*m_Position.z + m_pParent->m_Final._43;
}
}
//Um den Joint rotieren und nicht um den Ursprung
Transformation._41 += - Transformation._11*NewPosition.x - Transformation._21*NewPosition.y - Transformation._31*NewPosition.z + NewPosition.x;
Transformation._42 += - Transformation._12*NewPosition.x - Transformation._22*NewPosition.y - Transformation._32*NewPosition.z + NewPosition.y;
Transformation._43 += - Transformation._13*NewPosition.x - Transformation._23*NewPosition.y - Transformation._33*NewPosition.z + NewPosition.z;
}
if (!m_IsIdentity)//Der Joint wurde signifikant berührt
m_Touched=true;//Für Mehrfachanimationen keine weitere Animationen zulassen
if (m_pParent)
{
if (!m_pParent->m_IsIdentity)//Falls Einheitsmatrix ist das hier überflüssig
{
m_Final=m_pParent->m_Final*Transformation;
m_IsIdentity=false;//Dann sind wir wahrscheinlich auch nicht mehr eine Einheitsmatrix
}
else
m_Final=Transformation;
}
else//Kein Parent Joint
m_Final=Transformation;
}
Und hier mein Code zum Einlesen einer Milkshapedatei:
Code: Alles auswählen
//Joints lesen
WORD Joints;
fread(&Joints, sizeof(WORD), 1, File);
if (Joints > 0)
CreateJoints(Joints);
BBEMATRIX Fix;
Fix._11=1.0f;
Fix._12=0.0f;
Fix._13=0.0f;
Fix._14=0.0f;
Fix._21=0.0f;
Fix._22=0.0f;
Fix._23=1.0f;
Fix._24=0.0f;
Fix._31=0.0f;
Fix._32=1.0f;
Fix._33=0.0f;
Fix._34=0.0f;
Fix._41=0.0f;
Fix._42=0.0f;
Fix._43=0.0f;
Fix._44=1.0f;
char *pJointNames=new char[32*Joints];
BBEMATRIX *pAbsoluts=new BBEMATRIX[Joints];
float **ppTranslations=new float*[Joints];
float **ppRotations=new float*[Joints];
for (int i=0;i < Joints;i++)
{
BYTE Flag;
fread(&Flag, sizeof(BYTE), 1, File);
fread(&pJointNames[32*i], sizeof(char), 32, File);
char Parent[32];
fread(&Parent, sizeof(char), 32, File);
//Suche den Vater
int ParentID=-1;
for (int j=0;j < i;j++)
{
if (strcmp(Parent, &pJointNames[32*j]) == 0)
{
ParentID=j;
break;
}
}
BBEVECTOR Rotation;
fread(Rotation, sizeof(BBEVECTOR), 1, File);
BBEVECTOR Position;
fread(Position, sizeof(BBEVECTOR), 1, File);
WORD NumRotations;
fread(&NumRotations, sizeof(WORD), 1, File);
WORD NumTranslations;
fread(&NumTranslations, sizeof(WORD), 1, File);
ppTranslations[i]=new float[NumTranslations*4];
ppRotations[i]=new float[NumRotations*4];
const float Epsilon=0.0001f;
int k=0;
for (int j=0;j < NumRotations;j++)
{
float Time;
BBEVECTOR Data;
fread(&Time, sizeof(float), 1, File);
fread(&Data, sizeof(BBEVECTOR), 1, File);
if (Data.x*Data.x < Epsilon*Epsilon &&
Data.y*Data.y < Epsilon*Epsilon &&
Data.z*Data.z < Epsilon*Epsilon)
continue;
ppRotations[i][k*4+0]=Time;
ppRotations[i][k*4+1]=Data.x;
ppRotations[i][k*4+2]=Data.y;
ppRotations[i][k*4+3]=Data.z;
k++;
}
int l=0;
for (int j=0;j < NumTranslations;j++)
{
float Time;
BBEVECTOR Data;
fread(&Time, sizeof(float), 1, File);
fread(&Data, sizeof(BBEVECTOR), 1, File);
if (Data.x*Data.x < Epsilon*Epsilon &&
Data.y*Data.y < Epsilon*Epsilon &&
Data.z*Data.z < Epsilon*Epsilon)
continue;
ppTranslations[i][l*4+0]=Time;
ppTranslations[i][l*4+1]=Data.x;
ppTranslations[i][l*4+2]=Data.y;
ppTranslations[i][l*4+3]=Data.z;
l++;
}
//Berechne die Position des Joints aus den Milkshapedaten
BBEMATRIX Relative;
float Angle;
float sr, sp, sy, cr, cp, cy;
Angle = Rotation.z;
sy = sinf(Angle);
cy = cosf(Angle);
Angle = Rotation.y;
sp = sinf(Angle);
cp = cosf(Angle);
Angle = Rotation.x;
sr = sinf(Angle);
cr = cosf(Angle);
//Matrix = (Z * Y) * X
Relative._11 = cp*cy;
Relative._21 = cp*sy;
Relative._31 = -sp;
Relative._12 = sr*sp*cy+cr*-sy;
Relative._22 = sr*sp*sy+cr*cy;
Relative._32 = sr*cp;
Relative._13 = (cr*sp*cy+-sr*-sy);
Relative._23 = (cr*sp*sy+-sr*cy);
Relative._33 = cr*cp;
Relative._41 = 0.0f;
Relative._42 = 0.0f;
Relative._43 = 0.0f;
Relative._44 = 1.0f;
Relative._14=Position.x;
Relative._24=Position.y;
Relative._34=Position.z;
if (ParentID != -1)
pAbsoluts[i]=pAbsoluts[ParentID]*Relative;
else
pAbsoluts[i]=Relative;
BBEMATRIX Final=pAbsoluts[i]*Fix;
D3DXMatrixTranspose(&Final, &Final);
Final._41=-Final._41;
Position.x=Final._41;
Position.y=Final._42;
Position.z=Final._43;
if (!AddJoint(i, ParentID, Position, 0, 0))
return false;
for (int j=0;j < k;j++)
{
BBEVECTOR Data;
Data.x=ppRotations[i][j*4+1];
Data.y=ppRotations[i][j*4+2];
Data.z=ppRotations[i][j*4+3];
SetRotationKeyFrame(i, j, ppRotations[i][j*4], Data.x, Data.y, Data.z);
}
for (int j=0;j < l;j++)
{
BBEVECTOR Data;
Data.x=ppTranslations[i][j*4+1];
Data.y=ppTranslations[i][j*4+2];
Data.z=ppTranslations[i][j*4+3];
SetTranslationKeyFrame(i, j, ppTranslations[i][j*4], Data.x, Data.y, Data.z);
}
}
Die Animationen werden zwar falsch eingelesen, aber immerhin stimmt das Skelett.
Übrigens muss man beim Einlesen die X Koordiante der Vertice negieren und dann natürlich auch die Indize anpassen, damit das richtige gecullt wird.
Danke nochmal an alle, die mir geholfen haben :-)