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

天行健 君子當(dāng)自強而不息

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 閱讀(370) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


公告

導(dǎo)航

統(tǒng)計

常用鏈接

隨筆分類(178)

3D游戲編程相關(guān)鏈接

搜索

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲国产一区二区在线| 欧美日韩不卡| 久久久久久夜| 国产一区二区精品久久99| 亚洲香蕉在线观看| 亚洲欧美清纯在线制服| 国产精品视频大全| 香蕉久久国产| 老司机午夜精品视频在线观看| 国产在线观看一区| 久久久久久久欧美精品| 美女国产一区| 亚洲激情网址| 欧美r片在线| 亚洲精品在线免费观看视频| 一区二区成人精品| 国产精品免费看久久久香蕉| 亚洲欧美视频在线观看视频| 欧美中文字幕久久| 在线观看成人av| 久久九九精品| 欧美高清在线视频| 一区二区不卡在线视频 午夜欧美不卡'| 欧美精品亚洲| 亚洲一区三区电影在线观看| 久久精品最新地址| 亚洲人成绝费网站色www| 欧美日韩国产精品自在自线| 亚洲在线视频网站| 久久久久久久网站| 最新成人av网站| 欧美大秀在线观看| 亚洲一区二区视频| 欧美大片免费观看| 亚洲欧美视频| 亚洲国产一区二区三区高清| 国产精品mm| 久久久久久一区二区三区| 亚洲欧洲在线观看| 久久激情五月婷婷| 99热免费精品在线观看| 国产日韩欧美一区二区三区在线观看| 久色成人在线| 亚洲精品国精品久久99热一| 午夜在线观看免费一区| 在线日韩电影| 国产精品久久久久影院色老大| 久久久精品tv| 亚洲男女毛片无遮挡| 亚洲国产精品ⅴa在线观看| 欧美一级电影久久| 日韩亚洲欧美一区二区三区| 国产一区在线播放| 国产精品theporn| 欧美成人高清| 久久久久成人精品免费播放动漫| 99re热这里只有精品免费视频| 免费不卡在线视频| 欧美在线一区二区| 一本色道久久综合亚洲精品不卡 | 久久婷婷久久| 一区二区三区四区五区精品视频| 尤物精品在线| 国产日韩精品一区二区| 欧美婷婷久久| 久久精品人人做人人爽电影蜜月| 中文精品一区二区三区| 亚洲二区视频| 欧美aⅴ一区二区三区视频| 久久成人人人人精品欧| 亚洲欧美经典视频| 一区二区免费在线观看| 亚洲人成高清| 亚洲国产精品va在线观看黑人| 国产精品稀缺呦系列在线| 欧美日本精品在线| 欧美国产日韩二区| 欧美成人免费观看| 美女国产一区| 免费中文日韩| 麻豆成人在线播放| 久久先锋影音| 久久亚洲国产成人| 久久综合亚洲社区| 久久天堂成人| 久久午夜av| 狼人天天伊人久久| 男人的天堂亚洲| 美女国产一区| 久久激情一区| 一区二区三区 在线观看视频| 欧美激情视频一区二区三区在线播放 | 日韩一级片网址| 亚洲人成小说网站色在线| 亚洲欧洲一区二区三区| 亚洲人成艺术| 一本大道久久a久久精品综合| 亚洲精品中文字幕有码专区| 亚洲免费观看高清在线观看| 日韩一级片网址| 亚洲一二区在线| 欧美一级一区| 久久艳片www.17c.com| 欧美成人精品1314www| 欧美二区在线播放| 女生裸体视频一区二区三区| 欧美国产先锋| av成人老司机| 性亚洲最疯狂xxxx高清| 久久视频一区| 欧美久久电影| 国产精品综合网站| 精品成人国产在线观看男人呻吟| 亚洲国产女人aaa毛片在线| 99re国产精品| 一区二区三区不卡视频在线观看 | 亚洲网站在线| 久久精品国产精品亚洲综合| 免费在线观看一区二区| 亚洲美女中出| 午夜精品福利一区二区蜜股av| 久久精品午夜| 久久久久久97三级| 欧美理论电影网| 国产午夜精品美女毛片视频| 在线激情影院一区| 亚洲一区二区精品| 久久午夜影视| 一区二区三区久久网| 久久精品99无色码中文字幕| 欧美成人精品一区| 欧美视频免费| 激情综合色综合久久综合| 9色精品在线| 久久免费精品日本久久中文字幕| 亚洲第一页在线| 午夜精品久久久久久99热| 欧美国产激情| 国产欧美在线看| 亚洲精品自在久久| 久久久久久久91| 99国产精品久久久久久久成人热| 久久久久成人精品免费播放动漫| 欧美日韩视频在线| 在线免费日韩片| 欧美伊人久久大香线蕉综合69| 亚洲国产精品黑人久久久| 香蕉国产精品偷在线观看不卡| 欧美剧在线观看| 又紧又大又爽精品一区二区| 午夜一区不卡| 亚洲精品婷婷| 久久中文精品| 亚洲国产天堂久久综合| 欧美大片在线观看一区二区| 久久久噜噜噜久久中文字免 | 伊人久久亚洲影院| 久久午夜色播影院免费高清| 欧美亚洲日本国产| 国产日韩在线看片| 久久久久久久久久看片| 欧美在线视频导航| 激情综合色综合久久| 欧美成人官网二区| 欧美成人在线免费视频| 亚洲另类自拍| 亚洲毛片视频| 国产精品久久久久久久久久久久| 亚洲欧美国产毛片在线| 亚洲欧美日本伦理| 国产一区香蕉久久| 欧美阿v一级看视频| 欧美成人免费va影院高清| 亚洲乱码国产乱码精品精| 亚洲精品乱码久久久久久蜜桃91| 欧美日本国产视频| 亚洲欧美国产va在线影院| 亚洲欧美精品中文字幕在线| 国产一区视频网站| 欧美成人网在线| 欧美日韩裸体免费视频| 先锋a资源在线看亚洲| 久久精品成人一区二区三区| 91久久精品美女高潮| 亚洲精品女人| 欧美性猛交一区二区三区精品| 欧美一二三视频| 久久嫩草精品久久久精品| 日韩午夜在线播放| 亚洲免费在线| 亚洲经典三级| 亚洲综合精品| 亚洲国产人成综合网站| 中文av一区二区| 激情久久影院| 亚洲最新在线| 又紧又大又爽精品一区二区| 亚洲裸体在线观看| 激情成人综合| 在线中文字幕一区|