青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

天行健 君子當自強而不息

Blending Skeletal Animations(2)

Enhancing Skeletal Animation Objects

Now that you've seen how simple it is to blend multiple skeletal animations, why not take this new knowledge and add on to the skeletal animation objects? Sounds like a great idea; by adding a single function to the cAnimationCollection class, you can be on your way to blending animations like the pros.

In fact, rather than messing with the code from cAnimationCollection, just derive a new class that handles blended animations. This new derived class, cBlendedAnimationCollection, is defined as follows:

class cBlendedAnimationCollection : public cAnimationCollection
{
public:
void Blend(char *AnimationSetName,
DWORD Time, BOOL Loop,
float Blend = 1.0f);
};

Wow, that's a small class! The one and only function declared in cBlendedAnimationCollection is Blend, which is meant to take over the cAnimationCollection::Update function. Why not just derive a new Update function, you ask? Well, with cBlendedAnimationCollection, you can use the regular animation sets you used, as well as your (soon to be) newly developed blended animation sets.

Take a close look at the Blend function to see what's going on, and then I'll show you how to put your new class to good use.

void cBlendedAnimationCollection::Blend(
    char *AnimationSetName,
    DWORD Time, BOOL Loop,
    float Blend)
{

The Blend function prototype takes four parameters, the first of which is AnimationSetName. When calling Blend, you need to set AnimationSetName to the name of the animation set you are going to blend into the animation. Each animation set in your source .X file has a unique animation name (as defined by the AnimationSet data object's instance name). You must set AnimationSetName to a matching name from the .X file.

I'll get back to the animation sets in a bit. For now, I want to get back to the Blend prototype. The second parameter of Blend is Time, which represents the time in the animation that you are using to blend the animation. If you have an animation that is 1000 milliseconds in length, then Time can be any value from 0 to 999. Specifying a value larger than the animation's length forces the Blend function to use the last key frame in the list to blend the animation.

What about looping the animation? Well, that's the purpose of the third parameter, Loop. If you set Loop to FALSE, then your animations will refuse to update if you try to update using a time value that is greater than the length of the animation. However, if you set Loop to TRUE, the Blend function bounds−checks the time value (Time) to always fall within the range of the animation's time.

The previous paragraph may not make perfect sense at first, so to help you understand, imagine the following function:

void UpdateAnimation(DWORD Elapsed)
{
static DWORD AnimationTime = 0; // Animation time
	// Call Blend, using AnimationTime as the time in the animation
AnimationBlend.Blend("Walk", AnimationTime, FALSE, 1.0f);
	// Update the time of the animation
AnimationTime += ELapsed;
}

In the UpdateAnimation function, you are tracking the animation time via a static variable. Every time UpdateAnimation is called, the Blend function is used to blend in an animation called Walk, using a time value specified as AnimationTime. Assuming the Walk animation is 1000 milliseconds in length and the elapsed time between calls to UpdateAnimation is 50 ms, you can see tell that the animation would reach its end after 20 calls to the function. This means after you call UpdateAnimation 20 times, the animation will stop (because you set Loop to FALSE).

Going back and changing the Loop value to TRUE forces Blend to bounds−check the timing value and make sure it always uses a valid timing value. When I say bounds−check, I mean to use a modulus calculation. I'll show you how to use the modulus calculation in a moment; for now I want to get back to the fourth and final parameter.

The last parameter is Blend, which is a floating−point value that represents a scalar value used to modify the blended transformation matrix before it is applied to the skeletal structure. For example, if you are blending a walking animation, but you only want 50 percent of the transformation to be applied, then you would set Blend to 0.5.

Okay, that's enough for the parameters; let's get into the function code! If you've perused the cAnimationCollection::Update function, you'll notice that the majority of code in the Blend function is the same. Starting off, you'll find a bit of code that scans the linked list of animation sets to find the one that matches the name you provided as AnimationSetName.

cAnimationSet *AnimSet = m_AnimationSets;
// Look for matching animation set name if used
if(AnimationSetName) {
	// Find matching animation set name
while(AnimSet != NULL) {
// Break when match found
if(!stricmp(AnimSet−>m_Name, AnimationSetName))
break;
		// Go to next animation set object
AnimSet = AnimSet−>m_Next;
}
}
// Return no set found
if(AnimSet == NULL)
return;

If you set AnimationSetName to NULL, then Blend will use the first animation set in the linked list of animation sets. If you specified a name in AnimationSetName and none was found in the linked list, then Blend will return without any further ado.

Now that you have a pointer to the appropriate animation set object, you can bounds−check the time according to the value set in Time and the looping flag Loop.

// Bounds time to animation length
if(Time > AnimSet−>m_Length)
    Time = (Loop==TRUE)?Time % (AnimSet−>m_Length+1):AnimSet−>m_Length;

Quite an ingenious little bit of code, the previous tidbit does one of two things, depending on the Loop flag. If Loop is set to FALSE, then Time is checked against the length of the animation (AnimSet−>m_Length). If Time is greater than the length of the animation, then Time is set to the length of the animation, thus locking it at the last millisecond (and later on, the last key frame) of the animation. If you set Loop to TRUE, then a modulus calculation forces Time to always lie within the range of the animation's length (from 0 to AnimSet−>m_Length).

After you have calculated the appropriate Time to use for the animation, it is time to scan the list of bones in your skeletal structure. For each bone, you are going to track the combined transformations from the appropriate key frames. For each key frame found in the animation, you need to add (not multiply) the transformation to the skeletal structure's transformations.

// Go through each animation
cAnimation *Anim = AnimSet−>m_Animations;
while(Anim) {
//Only process if it's attached to a bone
if(Anim−>m_Bone) {
// Reset transformation
D3DXMATRIX matAnimation;
D3DXMatrixIdentity(&matAnimation);
		// Apply various matrices to transformation

From here, scan each key frame (depending on the type of keys used) and calculate the transformation to apply to your skeletal structure. For the sake of space, I'm only going to list the code that scans matrix keys.

// Matrix
if(Anim−>m_NumMatrixKeys && Anim−>m_MatrixKeys) {
// Loop for matching matrix key
DWORD Key1 = 0, Key2 = 0;
	for(DWORD i=0;i<Anim−>m_NumMatrixKeys;i++) {
if(Time >= Anim−>m_MatrixKeys[i].m_Time)
Key1 = i;
}
	// Get 2nd key number
Key2 = (Key1>=(Anim−>m_NumMatrixKeys−1))?Key1:Key1+1;
	// Get difference in keys' times
DWORD TimeDiff = Anim−>m_MatrixKeys[Key2].m_Time − Anim−>m_MatrixKeys[Key1].m_Time;
	if(!TimeDiff)
TimeDiff = 1;
	// Calculate a scalar value to use
float Scalar = (float)(Time − Anim−>m_MatrixKeys[Key1].m_Time) / (float)TimeDiff;
	// Calculate interpolated matrix
D3DXMATRIX matDiff;
matDiff = Anim−>m_MatrixKeys[Key2].m_matKey − Anim−>m_MatrixKeys[Key1].m_matKey;
matDiff *= Scalar;
matDiff += Anim−>m_MatrixKeys[Key1].m_matKey;
	// Combine with transformation
matAnimation *= matDiff;
}

Basically, the code is searching the key frames and calculating an appropriate transformation to use. This transformation is stored in
matAnimation.

From this point on, things take a decidedly different course than the cAnimationCollection::Update function code. Instead of storing the transformation matrix (matAnimation) in the skeletal structure's frame object, you will calculate the difference in the transformation from matAnimation to the skeletal structure's initial transformation (stored in matOriginal when the skeletal structure was loaded). This difference in transformation values is scaled using the floating−point Blend value you provided, and the resulting transformation is then added (not multiplied, as you do with concoction) to the skeletal structure's frame transformation. This ensures that the transformations are properly blended at the appropriate blending values.

After that, the next bone's key frames are scanned, and the loop continues until all bones have been processed.

			// Get the difference in transformations
D3DXMATRIX matDiff = matAnimation − Anim−>m_Bone−>matOriginal;
			// Adjust by blending amount
matDiff *= Blend;
			// Add to transformation matrix
Anim−>m_Bone−>TransformationMatrix += matDiff;
}
		// Go to next animation
Anim = Anim−>m_Next;
}
}

Congratulations, you've just completed your Blend function'! Let's put this puppy to work! Suppose you have a mesh and frame hierarchy already loaded, and you want to load a series of animations from an .X file. Suppose this .X file (called Anims.x) has four animation sets: Stand,Walk, Wave, and Shoot. That's two animations for the legs and two for the arms and torso. Here's a bit of code to load the animation sets:

// pFrame = root frame in frame hierarchy
cBlendedAnimationSet BlendedAnims;
BlendedAnims.Load("Anims.x");

// Map animations frame hierarchy
BlendedAnims.Map(pFrame);

Now that you have an animation collection loaded, you can begin blending the animations before updating and rendering your skinned mesh. Suppose you want to blend the Walk and Shoot animations, both using 100 percent of the transformations. To start, you must reset your frame hierarchy's transformations to their original states. This means you need to copy the D3DXFRAME_EX::matOriginal transformation into the D3DXFRAME_EX::TransformationMatrix transformation. This is very important because it serves as a base to which your animation set transformations are added during the blending operation.

// Use D3DXFRAME_EX::Reset to reset transformations
pFrame−>Reset();

Once the transformations have been reset to their original states, you can blend your animation sets.

// AnimationTime = time of animation, which is the elapsed time since start of the animation

// Blend in the walk animation
BlendedAnims.Blend("Walk", AnimationTime, TRUE, 1.0f);

// Blend in the shoot animation
BlendedAnims.Blend("Shoot", AnimationTime, TRUE, 1.0f);

Once you've blended all the animation sets you're going to use, you need to update your frame hierarchy, which is then used to update your skinned mesh.

// Update the frame hierarchy
pFrame−>UpdateHierarchy();

After you have updated the hierarchy (the transformation matrices have been combined and the results are stored in D3DXFRAME_EX::matCombined), you can update your skinned mesh and render away!


posted on 2008-04-25 19:35 lovedday 閱讀(369) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


公告

導航

統計

常用鏈接

隨筆分類(178)

3D游戲編程相關鏈接

搜索

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美一区二区三区精品| 最新日韩在线| 最新成人av网站| 最新日韩在线| 91久久在线| 一区二区高清视频| 亚洲少妇在线| 午夜一区二区三视频在线观看| 欧美精品系列| 1769国内精品视频在线播放| 国产视频亚洲| 国产欧美日韩免费| 在线日韩av片| 这里只有精品丝袜| 欧美一区成人| 欧美激情片在线观看| 欧美激情日韩| 午夜精品久久久久99热蜜桃导演| 午夜精品久久久久久久99热浪潮| 午夜精品久久99蜜桃的功能介绍| 久久成人精品一区二区三区| 免费亚洲网站| 国产精品久久999| 亚洲成人在线观看视频| 中文欧美在线视频| 久久夜色撩人精品| 99精品视频网| 免费一区视频| 在线观看91精品国产麻豆| 一区二区高清视频在线观看| 欧美专区第一页| 亚洲日韩欧美视频| 久久国产乱子精品免费女| 欧美精品一区二区三区四区| 国产亚洲福利| 欧美在线综合视频| 亚洲美女电影在线| 欧美激情中文不卡| 91久久黄色| 亚洲电影免费| 欧美精品久久久久a| 久久大综合网| 国产亚洲一区二区三区在线观看| 亚洲综合色在线| 亚洲少妇在线| 国产欧美日韩视频| 久久尤物电影视频在线观看| 久久国产黑丝| 亚洲视频网站在线观看| 欧美成人黑人xx视频免费观看| 一本大道久久a久久精二百| 欧美日韩一区二| 老色鬼久久亚洲一区二区| 欧美在线一二三| 欧美综合国产精品久久丁香| 日韩午夜在线观看视频| 亚洲二区在线视频| 久久精品视频一| 欧美大片一区二区三区| 一区二区三区在线视频播放| 欧美伊人精品成人久久综合97| 亚洲欧美日韩中文播放| 欧美日韩第一页| 99国内精品| 久久精品系列| 亚洲激情婷婷| 欧美三级网址| 午夜影院日韩| 免费试看一区| 亚洲一区亚洲二区| 国产中文一区二区| 麻豆av一区二区三区| 亚洲九九爱视频| 久久国产精品电影| 亚洲免费观看在线观看| 国产精品入口福利| 欧美jizz19性欧美| 欧美一区二区三区久久精品| 国产一区香蕉久久| 久久一区二区三区av| 在线视频你懂得一区| 欧美激情按摩在线| 久久久999精品| 亚洲欧美日韩国产综合在线| 亚洲国产色一区| 国产亚洲成精品久久| 久久久久久网| 亚洲国产成人不卡| 欧美一级专区免费大片| 亚洲欧洲一区二区三区在线观看 | 亚洲视频第一页| 欧美一级成年大片在线观看| 国内外成人免费激情在线视频| 欧美日韩国产专区| 亚洲精品一区在线观看香蕉| 亚洲欧美在线免费观看| 一区二区三区自拍| 国产精品久久久久一区| 久久久久九九视频| 欧美日韩一区二区三区在线看| 欧美一级理论片| 亚洲性视频h| 在线视频一区二区| 亚洲视屏一区| 一本久久知道综合久久| 亚洲第一网站免费视频| 久久久久网址| 欧美中文字幕久久| 欧美一区二区三区免费大片| 日韩一级免费| 激情欧美一区二区| 国产一区二区视频在线观看| 国产免费观看久久| 国产日韩一区欧美| 亚洲精品国产精品国自产在线| 亚洲福利久久| 亚洲国产精品999| 欧美国产91| 在线亚洲精品| 亚洲欧洲99久久| 美日韩精品视频| 免费91麻豆精品国产自产在线观看| 欧美高清视频一区| 国产麻豆视频精品| 亚洲少妇自拍| 一本色道久久加勒比88综合| 久久久久久久久久久久久女国产乱 | 免费成人黄色av| 最新中文字幕一区二区三区| 亚洲人成亚洲人成在线观看图片| 中文亚洲字幕| 欧美成人午夜剧场免费观看| 国产精品一区二区三区成人| 亚洲国产日韩在线一区模特| 午夜视频一区二区| 欧美激情综合色综合啪啪 | 亚洲自拍另类| 噜噜噜在线观看免费视频日韩| 亚洲精品一区二区在线观看| 午夜精品久久久久久99热| 欧美成人a视频| 久久精品五月| 亚洲第一福利在线观看| 亚洲人体1000| 国产亚洲欧洲| 亚洲欧美在线视频观看| 性高湖久久久久久久久| 精品91视频| 亚洲九九精品| 国语精品一区| 亚洲精品小视频| 国产视频亚洲精品| 亚洲人在线视频| 国产偷自视频区视频一区二区| 欧美在线免费播放| 久久久av水蜜桃| 欧美日韩中文| 国产一区91精品张津瑜| 一区二区三区日韩| 亚洲一区二区网站| 一区二区av| 欧美在线亚洲综合一区| 久久不射电影网| 久久久久成人网| 亚洲大片一区二区三区| 亚洲区免费影片| 久久久久国产精品一区| 欧美日韩1区| 好看的av在线不卡观看| 日韩视频免费| 久久综合色天天久久综合图片| 久久精品1区| 国产精品第13页| 亚洲色诱最新| 最新国产拍偷乱拍精品| 久久久亚洲高清| 雨宫琴音一区二区在线| 欧美一区国产一区| 亚洲视频999| 国产噜噜噜噜噜久久久久久久久| 伊人影院久久| 亚洲成色最大综合在线| 久久久久久999| 国产亚洲成年网址在线观看| 欧美69视频| 欧美一区国产二区| 亚洲色图在线视频| 香蕉国产精品偷在线观看不卡| 国模叶桐国产精品一区| 久久久亚洲欧洲日产国码αv | 国产精品久久久久77777| 精品69视频一区二区三区| 性欧美videos另类喷潮| 亚洲一区综合| 久久精品亚洲一区二区三区浴池| 久久精品国产亚洲a| 噜噜噜久久亚洲精品国产品小说| 亚洲国产老妈| 久久精品国产视频| 亚洲欧美在线免费观看|