Combining multiple .x files into a single .x file

Started by
28 comments, last by Steve_Segreto 10 years, 9 months ago

Here is what I tried to do to set D3DXPLAY_ONCE flag (not working though):


ID3DXKeyframedAnimationSet* set = 0;
animController->GetAnimationSet(animationIndex, (ID3DXAnimationSet**)&set);
D3DXCreateKeyframedAnimationSet(set->GetName(), set->GetSourceTicksPerSecond(), D3DXPLAY_ONCE, set->GetNumAnimations(), set->GetNumCallbackKeys(), NULL, &set);

// Code here to set the track and play the animation...
Advertisement

From what i can tell D3DXCreateKeyframedAnimationSet only outputs ID3DXKeyframedAnimationSet it does not copy SRT keys from existing animation set, you need to that yourself.
Note that i have not done this before so i am going to guess with help from MSDN documentation:


ID3DXAnimationSet* dieAnimationSet;
ID3DXKeyframedAnimationSet* dieKeyFramedAnimationSet;
 
animController->GetAnimationSet(animationIndex, &dieAnimationSet);
 
// creates "empty" keyframed-animation-set
D3DXCreateKeyframedAnimationSet(
    dieAnimationSet->GetName(), 
    dieAnimationSet->GetSourceTicksPerSecond(), 
    D3DXPLAY_ONCE,
    dieAnimationSet->GetNumAnimations(), 
    dieAnimationSet->GetNumCallbackKeys(), 
    NULL, 
    &dieKeyFramedAnimationSet);
 
// now you need to copy SRT keys data from dieAnimationSet to dieKeyFramedAnimationSet
// some thing here i am not sure how to obtain as documentation is not clear enough
LPD3DXKEY_VECTOR3 scaleKeys[ numKeys ];
LPD3DXKEY_QUATERNION rotKeys[ numKeys ];
LPD3DXKEY_VECTOR3 translKeys[ numKeys ];

for each numKeys and "periodic/local/whatever_time_they_mean_by_this"
{
    D3DXVECTOR3 scale, transl;
    D3DXQUATERNION rot;
    dieAnimationSet->GetSRT( timePos, 0, &scale, &rot, &transl );
    scaleKeys[ i ].Time = timePos;
    scaleKeys[ i ].Value = scale;
    rotKeys[ i ].Time = timePos;
    rotKeys[ i ].Value = rot;
    translKeys[ i ].Time = timePos;
    translKeys[ i ].Value = transl;
}

DWORD newAnimIndex;
dieKeyFramedAnimationSet->RegisterAnimationSRTKeys(
    "animation_name",
    numKeys, numKeys, numKeys,
    scaleKeys, rotKeys, translKeys, &newAnimIndex);

// then here unregister old dieAnimationSet and register new dieKeyFramedAnimationSet to animation controler

Now look how stupid this is for setting such a small and trivial thing.

@belfegor: I'm new to D3DX animation, so I will need a little more help

and "periodic/local/whatever_time_they_mean_by_this"

I don't understand this part

How do I get numKeys?

The following functions doesn't exists:


dieAnimationSet->GetSourceTicksPerSecond()
dieAnimationSet->GetNumCallbackKeys()

I am sorry, i just copied your code from above for that function and didn't look if it is correct.

I commented in code that i don't know for some things how to obtain them.

You could put it like this for test:


D3DXCreateKeyframedAnimationSet(
    dieAnimationSet->GetName(),
    30.0, // for this check in 3ds max and/or exporter options on which value it was set
    D3DXPLAY_ONCE, 
    1, // assume 1 animation in set
    0, // assume no callback keys, otherwise i don't know how to obtain them
    NULL,
    &dieKeyFramedAnimationSet);

Then for numKeys you could try (my guess is that GetPeriod() is in seconds?):


double timeStep = dieAnimationSet->GetPeriod() / 30.0;
DWORD numKeys = std::floor(dieAnimationSet->GetPeriod() * 30);

double timePos = 0.0;
for(DWORD i =0; i < numKeys; ++i, timePos += timeStep)
{
    D3DXVECTOR3 scale, transl;
    D3DXQUATERNION rot;
    dieAnimationSet->GetSRT( timePos, 0, &scale, &rot, &transl );
    ...
}

Maybie there is an easier way but i don't see one.

Now, the animation is not playing anymore :/

Here is the code:


LPD3DXANIMATIONSET tempSet = 0;
LPD3DXKEYFRAMEDANIMATIONSET set;
m_animController->GetAnimationSet(index, &tempSet);


D3DXCreateKeyframedAnimationSet(
    tempSet->GetName(),
    30.0, // for this check in 3ds max and/or exporter options on which value it was set
    D3DXPLAY_ONCE, 
    1, // assume 1 animation in set
    0, // assume no callback keys, otherwise i don't know how to obtain them
    NULL,
    &set);


double timeStep = tempSet->GetPeriod() / 30.0;
DWORD numKeys = std::floor(tempSet->GetPeriod() * 30);


// now you need to copy SRT keys data from dieAnimationSet to dieKeyFramedAnimationSet
// some thing here i am not sure how to obtain as documentation is not clear enough
LPD3DXKEY_VECTOR3 scaleKeys = new D3DXKEY_VECTOR3[numKeys]();
LPD3DXKEY_QUATERNION rotKeys = new D3DXKEY_QUATERNION[numKeys]();
LPD3DXKEY_VECTOR3 translKeys = new D3DXKEY_VECTOR3[numKeys]();


double timePos = 0.0;
for(DWORD i =0; i < numKeys; ++i, timePos += timeStep)
{
    D3DXVECTOR3 scale, transl;
    D3DXQUATERNION rot;
tempSet->GetSRT( timePos, 0, &scale, &rot, &transl );


scaleKeys[ i ].Time = timePos;
    scaleKeys[ i ].Value = scale;
    rotKeys[ i ].Time = timePos;
    rotKeys[ i ].Value = rot;
    translKeys[ i ].Time = timePos;
    translKeys[ i ].Value = transl;
}


DWORD newAnimIndex;
set->RegisterAnimationSRTKeys(
    tempSet->GetName(),
    numKeys, numKeys, numKeys,
    scaleKeys, rotKeys, translKeys, &newAnimIndex);


animController->UnregisterAnimationSet(tempSet);
tempSet->Release();
animController->RegisterAnimationSet(set);

This little hurdle is just one of many reasons why most people have abandoned X files :)

I suppose if you could generate the compressed animation data, you could output it to your text X file under this template (CompressedAnimationSet):

http://msdn.microsoft.com/en-us/library/windows/desktop/bb204841(v=vs.85).aspx

and specify '1' for playback type manually and then re-load it and get the desired play once behavior. You can also kind of jury-rig the play once behavior by just setting an animation callback near the end of a play once animation and using that callback to return to idle, rather than loop (or whatever).

Note that using compressed keyframe data will block your D3DXSaveMeshHierarchy() call and you would have to do D3DXSaveMeshToX() instead (http://msdn.microsoft.com/en-us/library/windows/desktop/bb205428(v=vs.85).aspx)

RESOLVED!

I had to simply add 2 lines to play the animation once:


animController->SetTrackPosition(track, 0.0);
animController->KeyTrackEnable(track, FALSE, currentTime + set->GetPeriod());
No need to compress or clone the animation or do anything else happy.png
Now to do animation callbacks, is there is any way as simple as this. biggrin.png
I'm thinking about calculating the passed time and comparing it to set->GetPeriod() then do callbacks accordingly.

Have a look here:

http://gearengine.googlecode.com/svn/!svn/bc/2/trunk/GearEngine/AnimatedObject.h

and here:

http://gearengine.googlecode.com/svn/!svn/bc/2/trunk/GearEngine

@Steve_Segreto: I tried adding this method to my class:


HRESULT CALLBACK Character::HandleCallback(THIS_ UINT track, LPVOID pCallbackData)
{
    MessageBox(NULL, "Callback", NULL, NULL);
    return S_OK;
}

And when updating the animation:


animController->AdvanceTime(elapsedTime, this)

The callback method Character::HandleCallback never fire.

Yeah sorry, right after I posted those links I looked a bit more at the code and realized that "engine" never installs any callbacks to the animation controller.

This topic is closed to new replies.

Advertisement