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

天行健 君子當自強而不息

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>
            欧美一区二区视频在线观看2020 | 在线观看亚洲专区| 激情文学综合丁香| 亚洲午夜精品久久久久久app| 欧美一区二区三区日韩视频| 国产精品视频观看| 国产专区欧美精品| 一区二区久久久久| 欧美mv日韩mv国产网站| 亚洲成人在线网| 91久久视频| 欧美激情精品久久久久久变态 | 亚洲一区二区免费视频| 蜜桃av噜噜一区| 亚洲欧美日韩区| 国产麻豆成人精品| 久久狠狠一本精品综合网| 亚洲天堂成人| 国产一区久久| 欧美一区在线视频| 性欧美精品高清| 久久狠狠亚洲综合| 悠悠资源网亚洲青| 久久综合色播五月| 欧美极品在线播放| 亚洲视频第一页| 亚洲一级免费视频| 合欧美一区二区三区| 亚洲国产精品成人久久综合一区| 久久亚洲不卡| 一级日韩一区在线观看| 亚洲在线播放| 国产日韩精品一区二区浪潮av| 欧美一区日本一区韩国一区| 久久全球大尺度高清视频| 激情综合色综合久久| 亚洲丰满少妇videoshd| 国产精品豆花视频| 欧美一区二区视频网站| 久久伊人免费视频| 久久久国产午夜精品| 欧美日韩在线视频观看| 免费久久99精品国产| 欧美日韩一区二区在线观看| 久久亚洲精品伦理| 国产农村妇女精品一二区| 一区在线视频观看| 亚洲一区亚洲| 亚洲视频网站在线观看| 久久综合中文字幕| 欧美亚洲午夜视频在线观看| 欧美精品18| 亚洲二区视频在线| 亚洲精品国产欧美| 久久综合婷婷| 欧美1区免费| 亚洲欧洲综合另类在线| 久久中文久久字幕| 欧美激情网友自拍| 在线日韩欧美| 欧美精品18| 午夜在线电影亚洲一区| 久久丁香综合五月国产三级网站| 国产精品女主播| 午夜精品亚洲一区二区三区嫩草| 午夜综合激情| 伊人狠狠色丁香综合尤物| 久久这里有精品视频| 亚洲人成久久| 久久久欧美精品| 久久久91精品国产| 欧美片在线观看| 亚洲人永久免费| 精品电影在线观看| 欧美韩日一区| 香港成人在线视频| 亚洲人成人一区二区在线观看| 亚洲新中文字幕| 亚洲成人在线免费| 国产精品一区=区| 欧美激情1区| 欧美一级在线播放| 一区二区三区日韩在线观看| 久久国产精品久久久| 久久三级福利| 亚洲精品日韩激情在线电影| 国产精品高潮呻吟久久av无限| 欧美在线播放视频| 亚洲午夜一二三区视频| 亚洲娇小video精品| 久久爱另类一区二区小说| 亚洲婷婷综合色高清在线 | 欧美成人精品在线| 亚洲视频在线一区观看| 一本色道久久99精品综合| 亚洲国产婷婷香蕉久久久久久| 国产精品视频导航| 国产精品久久久久久久app| 久久国产精品一区二区| 欧美一区二区三区的| 亚洲视频1区2区| 亚洲欧美日韩在线| 欧美在线一级视频| 男同欧美伦乱| 国产精品国产三级国产普通话三级 | 亚洲国产欧美一区二区三区同亚洲 | 男人插女人欧美| av成人动漫| 欧美激情一区二区三区成人| 欧美激情一区二区三区| 一区二区三区视频在线| 久热成人在线视频| 国产亚洲视频在线| 在线亚洲+欧美+日本专区| 麻豆91精品91久久久的内涵| 亚洲最新中文字幕| 欧美激情一区二区三区在线视频观看 | 性伦欧美刺激片在线观看| 亚洲欧洲一区二区在线播放| 久久久精品久久久久| 国产欧美精品va在线观看| 亚洲狠狠婷婷| 欧美乱人伦中文字幕在线| 欧美日韩另类综合| 亚洲国产精品久久久久秋霞影院| 亚洲无亚洲人成网站77777| 亚洲国产精品va在线看黑人| 美女脱光内衣内裤视频久久影院 | 国产揄拍国内精品对白| 亚洲欧美韩国| 欧美一区=区| 亚洲国产成人不卡| 欧美成在线视频| 欧美日韩午夜视频在线观看| 亚洲精品美女在线| 男女视频一区二区| 蜜桃av一区二区三区| 亚洲香蕉网站| 午夜免费日韩视频| 亚洲国产成人久久综合| 一本大道久久a久久精二百| 国产日韩欧美一区在线 | 欧美不卡视频一区发布| 久久偷窥视频| 性色一区二区| 免费国产一区二区| 国产精品久久久久久妇女6080| 久久欧美肥婆一二区| 欧美性生交xxxxx久久久| 欧美激情成人在线视频| 欧美日韩一区二区三区高清| 久久久国际精品| 国产精品推荐精品| 亚洲精品1区| 亚洲第一精品久久忘忧草社区| 亚洲视频网在线直播| 日韩视频免费观看高清完整版| 亚洲欧洲av一区二区| 亚洲一区二区三区在线看| 欧美高清视频在线| 欧美福利视频在线| 亚洲精品人人| 欧美gay视频| 亚洲高清视频一区| 亚洲黄色免费| 欧美久久久久久久| 日韩视频在线免费| 亚洲在线网站| 国产一区二区三区久久久久久久久| 亚洲最黄网站| 久久国产精彩视频| 一区二区在线视频观看| 免费成人高清| 日韩视频中午一区| 亚欧成人在线| 亚洲精品日韩久久| 国产视频不卡| 一区二区三区四区国产精品| 欧美不卡高清| 亚洲伦理精品| 亚洲欧美日韩在线播放| 国产精品一二一区| 久久久久久噜噜噜久久久精品| 亚洲国产黄色片| 亚洲性视频网址| 在线观看亚洲精品视频| 欧美午夜一区| 免费日韩视频| 玖玖综合伊人| 欧美夜福利tv在线| 99国产一区二区三精品乱码| 快播亚洲色图| 久久aⅴ国产紧身牛仔裤| av成人老司机| 日韩亚洲欧美高清| 欧美性片在线观看| 久久伊人亚洲| 欧美在线观看一区| 亚洲性夜色噜噜噜7777| 老牛国产精品一区的观看方式|