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

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

Timing in Animation and Movement(2)

Animating with Time

In the olden days, games were made to animate graphics based on every frame processed. To ensure that the animations always ran at the same speed, those games sometimes limited the number of frames per second that could be processed. Of course, those old games were made for computers that couldn't easily process more than 20 to 30 frames per second, so it was safe to assume that limiting the number of frames per second would never surpass that 20 or 30 frames per second mark.

But that was then, and this is now. Modern computers can run circles around their ancestors, and limiting the number of frames to control animation is a definite no−no in this day and age. You need to base the speed of animation on the amount of time that has elapsed since the start of the animation sequence. Doing so is no problem because you already know that you can record the time when the animation started. Additionally, for each frame to update, you can read the current time and subtract the starting animation time. The result is a time value to use as an offset to your animation sequence.

Suppose you are using time−based key frames in your animation engine. You can use a simple key−frame structure that stores the time and a transformation matrix to use, such as this:

typedef struct sKeyframe {
  DWORD Time;
  D3DMATRIX matTransformation;
} sKeyframe;

As is typical for key frames, you can store an array of matrices, each with its own unique time. These structures are stored in chronological order, with the lower time values first. Therefore, you can create a small sequence of transformations to orient an object over time (see Figure 2.1).

To replicate the key frames shown in Figure 2.1, I've constructed the following array:

sKeyframe Keyframes[4] = {
{ 0, 1.00000f, 0.00000f, 0.00000f, 0.00000f,
0.00000f, 1.00000f, 0.00000f, 0.00000f,
0.00000f, 0.00000f, 1.00000f, 0.00000f,
0.00000f, 0.00000f, 0.00000f, 1.00000f; },

{ 400, 0.000796f, 1.00000f, 0.00000f, 0.00000f,
−1.00000f, 0.000796f, 0.00000f, 0.00000f,
0.00000f, 0.00000f, 1.00000f, 0.00000f,
50.00000f, 0.00000f, 0.00000f, 1.00000f; },

{ 800, −0.99999f, 0.001593f, 0.00000f, 0.00000f,
−0.001593f, −0.99999f, 0.00000f, 0.00000f,
0.00000f, 0.00000f, 1.00000f, 0.00000f,
25.00000f, 25.00000f, 0.00000f, 1.00000f; },

{ 1200, 1.00000f, 0.00000f, 0.00000f, 0.00000f,
0.00000f, 1.00000f, 0.00000f, 0.00000f,
0.00000f, 0.00000f, 1.00000f, 0.00000f,
0.00000f, 0.00000f, 0.00000f, 1.00000f; }
};

Now comes the fun part. Using the timing methods you read about previously, you can record the time at which the animation started. And, for each frame to update the animation, you can calculate the elapsed time since the animation started (using that as an offset to the key frames). Create a simple frame update function that will determine which transformation to use depending on the elapsed time since the update function was first called.

void FrameUpdate()
{
  static DWORD StartTime = timeGetTime();
  DWORD Elapsed = timeGetTime() − StartTime;

With the elapsed time now in hand, you can scan the key frames to look for the two between which the time value lies. For example, if the current time is 60 milliseconds, the animation is somewhere between key frame #0 (at 0 milliseconds) and key frame #1 (at 400 milliseconds). A quick scan through the key frames determines which to use based on the elapsed time.

DWORD Keyframe = 0; // Start at 1st keyframe

for(DWORD i=0;i<4;i++) {
  // If time is greater or equal to a key−frame's time then update the keyframe to use
  if(Time >= Keyframes[i].Time)
    Keyframe = i;
}

At the end of the loop, the Keyframe variable will hold the first of the two key frames between which the animation time lies. If Keyframe isn't the last key frame in the array (in which there are four key frames), then you can add 1 to Keyframe to obtain the second key frame. If Keyframe is the last key frame in the array, you can use the same key−frame value in your calculations.

Using a second variable to store the next key frame in line is perfect. Remember that if Keyframe is the last key frame in the array, you need to set this new key frame to the same value.

DWORD Keyframe2 = (Keyframe==3) ? Keyframe:Keyframe + 1;

Now you need to grab the time values and calculate a scalar based on the time difference of the keys and the position of the key frame between the keys.

DWORD TimeDiff = Keyframes[Keyframe2].Time − Keyframes[Keyframe].Time;

// Make sure there's a time difference to avoid divide−by−zero errors later on.
if(!TimeDiff)
  TimeDiff=1;

float Scalar = (Time − Keyframes[Keyframe].Time) / TimeDiff;

You now have the scalar value (which ranges from 0 to 1) used to interpolate the transformation matrices of the keys. To make it easy to deal with the transformation matrices, those matrices are cast to a D3DXMATRIX type so that D3DX does the hard work for you.

// Calculate the difference in transformations
D3DXMATRIX matInt = D3DXMATRIX(Keyframes[Keyframe2].matTransformation) −
                                    D3DXMATRIX(Keyframes[Keyframe].matTransformation);

matInt *= Scalar; // Scale the difference

// Add scaled transformation matrix back to 1st keyframe matrix
matInt += D3DXMATRIX(Keyframes[Keyframe].matTransformation);

At this point, you have the proper animated transformation matrix to use stored in matInt. To see your hard work come to life, set matInt as the world transformation and render your animated mesh.

 

Main Routine:

#include <windows.h>
#include 
"d3d9.h"
#include 
"d3dx9.h"
#include 
"Direct3D.h"

IDirect3D9
*                g_d3d;
IDirect3DDevice9
*        g_device;
D3DXMESHCONTAINER_EX
*    g_robot_mesh_container;

struct sKeyFrame
{
    DWORD        time;
    D3DMATRIX    mat_trans;
};

// NOTE: transfromation matrix of key frame 0 is same as key frame 3.
sKeyFrame g_key_frames[4= 
{
  
// key_frame 1, 0ms
  {   01.000000f0.000000f0.000000f0.000000f,
         
0.000000f1.000000f0.000000f0.000000f,
         
0.000000f0.000000f1.000000f0.000000f,
         
0.000000f0.000000f0.000000f1.000000f },

  
// key_frame 2, 40ms
  {  4000.000796f1.000000f0.000000f0.000000f,
         
-1.000000f0.000796f0.000000f0.000000f,
          
0.000000f0.000000f1.000000f0.000000f,
         
50.000000f0.000000f0.000000f1.000000f },

  
// key_frame 3, 80ms
  {  800-0.999999f,  0.001593f0.000000f0.000000f,
          
-0.001593f-0.999999f0.000000f0.000000f,
           
0.000000f,  0.000000f1.000000f0.000000f,
          
25.000000f25.000000f0.000000f1.000000f },

  
// key_frame 4, 120ms
  { 12001.000000f0.000000f0.000000f0.000000f,
          
0.000000f1.000000f0.000000f0.000000f,
          
0.000000f0.000000f1.000000f0.000000f,
          
0.000000f0.000000f0.000000f1.000000f }
};

const char g_class_name[] = "TimeAnimClass";
const char g_caption[] = "Timed Animation";

LRESULT FAR PASCAL window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

bool do_init(HWND hwnd);
void do_shutdown();
void do_frame();

//////////////////////////////////////////////////////////////////////////////////////////////

int PASCAL WinMain(HINSTANCE inst, HINSTANCE, LPSTR, int cmd_show)
{      
  CoInitialize(NULL);    
// Initialize the COM system

  WNDCLASSEX win_class;

  
// Create the window class here and register it
  win_class.cbSize        = sizeof(win_class);
  win_class.style         
= CS_CLASSDC;
  win_class.lpfnWndProc   
= window_proc;
  win_class.cbClsExtra    
= 0;
  win_class.cbWndExtra    
= 0;
  win_class.hInstance     
= inst;
  win_class.hIcon         
= LoadIcon(NULL, IDI_APPLICATION);
  win_class.hCursor       
= LoadCursor(NULL, IDC_ARROW);
  win_class.hbrBackground 
= NULL;
  win_class.lpszMenuName  
= NULL;
  win_class.lpszClassName 
= g_class_name;
  win_class.hIconSm       
= LoadIcon(NULL, IDI_APPLICATION);

  
if(!RegisterClassEx(&win_class))
    
return FALSE;

  
// Create the main window
  HWND hwnd = CreateWindow(g_class_name, g_caption, WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
                           
00640480, NULL, NULL, inst, NULL);

  
if(hwnd == NULL)
    
return FALSE;

  ShowWindow(hwnd, cmd_show);
  UpdateWindow(hwnd);

  
// Call init function and enter message pump
  if(do_init(hwnd)) 
  {
    MSG msg;    
    ZeroMemory(
&msg, sizeof(MSG));

    
// Start message pump, waiting for user to exit
    while(msg.message != WM_QUIT) 
    {
      
if(PeekMessage(&msg, NULL, 00, PM_REMOVE)) 
      {
        TranslateMessage(
&msg);
        DispatchMessage(
&msg);
      }
      
      do_frame();    
// Render a single frame
    }
  }
  
  do_shutdown();
 
  UnregisterClass(g_class_name, inst);
  CoUninitialize();

  
return 0;
}

LRESULT FAR PASCAL window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  
// Only handle window destruction messages
  switch(msg) 
  {
    
case WM_DESTROY:
      PostQuitMessage(
0);
      
break;

    
case WM_KEYDOWN:
        
if(wParam == VK_ESCAPE)
            DestroyWindow(hwnd);

        
break;
  }

  
return DefWindowProc(hwnd, msg, wParam, lParam);
}

bool do_init(HWND hwnd)
{
    init_d3d(
&g_d3d, &g_device, hwnd, falsefalse);

    
if(FAILED(load_mesh(&g_robot_mesh_container, g_device, "..\\Data\\robot.x""..\\Data\\"00)))
        
return FALSE;

    
// setup a directional light

    D3DLIGHT9 light;
    ZeroMemory(
&light, sizeof(D3DLIGHT9));

    light.Type 
= D3DLIGHT_DIRECTIONAL;
    light.Diffuse.r 
= light.Diffuse.g = light.Diffuse.b = light.Diffuse.a = 1.0f;
    light.Direction 
= D3DXVECTOR3(0.0f-0.5f0.5f);

    g_device
->SetLight(0&light);
    g_device
->LightEnable(0, TRUE);

    
return true;
}

void do_shutdown()
{
    
// free mesh data
    delete g_robot_mesh_container;
    g_robot_mesh_container 
= NULL;

    
// release D3D objects
    release_com(g_device);
    release_com(g_d3d);
}

void do_frame()
{
    
static DWORD start_time = timeGetTime();

    DWORD elapsed_time 
= timeGetTime() - start_time;

    
// bounds the time to the animation time, important!!
    elapsed_time %= (g_key_frames[3].time + 1);

    
// dertermin which keyframe to use

    DWORD key_frame 
= 0;

    
for(DWORD i = 0; i < 4; i++)
    {
        
// if time is greater or equal to a key-frame's time then update the keyframe to use
        if(elapsed_time >= g_key_frames[i].time)
            key_frame 
= i;
    }

    
// get second key frame
    DWORD key_frame_2 = (key_frame == 3? key_frame : (key_frame + 1);

    
// Calculate the difference in time between keyframes and calculate a scalar value to use 
    
// for adjusting the transformations.
    DWORD time_diff = g_key_frames[key_frame_2].time - g_key_frames[key_frame].time;

    
if(time_diff == 0)
        time_diff 
= 1;

    
float scalar = (float)(elapsed_time - g_key_frames[key_frame].time) / time_diff;

    
// calculate the difference in transformations
    D3DXMATRIX mat = D3DXMATRIX(g_key_frames[key_frame_2].mat_trans) - D3DXMATRIX(g_key_frames[key_frame].mat_trans);

    mat 
*= scalar;    // scale the difference

    
// add scaled transformation matrix back to 1st key frame matrix
    mat += D3DXMATRIX(g_key_frames[key_frame].mat_trans);

    g_device
->SetTransform(D3DTS_WORLD, &mat);

    
// set a view transformation matrix

    D3DXMATRIX  mat_view;
    D3DXVECTOR3 eye(
25.0f0.0f-80.0f);
    D3DXVECTOR3 at(
25.0f0.0f0.0f);
    D3DXVECTOR3 up(
0.0f1.0f0.0f);

    D3DXMatrixLookAtLH(
&mat_view, &eye, &at, &up);
    g_device
->SetTransform(D3DTS_VIEW, &mat_view);

    
// clear the device and start drawing the scene

    g_device
->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(000255), 1.0f0);

    g_device
->BeginScene();

    g_device
->SetRenderState(D3DRS_LIGHTING, TRUE);
    draw_mesh(g_robot_mesh_container);
    g_device
->SetRenderState(D3DRS_LIGHTING, FALSE);

    g_device
->EndScene();

    g_device
->Present(NULL, NULL, NULL, NULL);
}


Runtime Snap:

As you can see, using time−based animation is pretty simple. Even if you don't use key frames in your animation, you can still rely on these methods of using time in your own code. Now that you've seen how easy it is to use time−based animation, take a look at how easy it is to use time−based movement.

 

download source file

 

posted on 2008-04-15 16:27 lovedday 閱讀(454) 評(píng)論(0)  編輯 收藏 引用


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


公告

導(dǎo)航

統(tǒng)計(jì)

常用鏈接

隨筆分類(178)

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

搜索

最新評(píng)論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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免费一区| 国产精品久久精品日日| 国产日韩欧美制服另类| 久久久精品动漫| 久久国产精品72免费观看| 在线免费观看视频一区| 欧美超级免费视 在线| 欧美日韩国产在线播放| 小黄鸭精品密入口导航| 久久久久久久一区二区| 激情校园亚洲| 亚洲小说欧美另类社区| 激情91久久| 午夜激情亚洲| 99成人在线| 狼狼综合久久久久综合网| 亚洲性图久久| 欧美成人精品一区| 久久久久久久久久久久久久一区| 久久综合狠狠| 久久久久女教师免费一区| 葵司免费一区二区三区四区五区| 亚洲伊人色欲综合网| 亚洲人成亚洲人成在线观看| 午夜精品一区二区在线观看| 在线观看免费视频综合| 亚洲永久视频| 亚洲性av在线| 欧美午夜电影完整版| 亚洲精品美女在线观看播放| 韩国成人福利片在线播放| 这里只有精品电影| 亚洲欧美日韩国产综合精品二区 | 欧美日韩国产999| 久久都是精品| 影音先锋日韩精品| 久久黄色级2电影| 老色批av在线精品| 亚洲黄色免费| 欧美日韩美女| 亚洲欧美视频在线| 久久不见久久见免费视频1| 国产欧美一级| 久久精品国产久精国产爱| 免费日本视频一区| 亚洲天堂av电影| 国产欧美在线观看一区| 欧美一区二区网站| 亚洲国产精品va在线观看黑人| 亚洲美女精品久久| 国产精品入口麻豆原神| 久久精品在线| 亚洲一区二区三区视频| 蜜臀va亚洲va欧美va天堂 | 蜜臀91精品一区二区三区| 麻豆91精品| 香蕉久久夜色精品国产使用方法| 国自产拍偷拍福利精品免费一| 欧美精品高清视频| 久久久久九九九| 午夜精品一区二区在线观看| 亚洲第一在线综合在线| 久久精品国产综合| 日韩写真在线| 日韩视频中文字幕| 欧美人成在线| 亚洲中无吗在线| 亚洲乱码国产乱码精品精天堂| 久热国产精品| 性欧美暴力猛交69hd| 亚洲影院在线观看| 9久草视频在线视频精品| 亚洲国产一区二区三区高清| 狠狠综合久久av一区二区老牛| 欧美亚州一区二区三区| 欧美揉bbbbb揉bbbbb| 国产精品国产自产拍高清av王其 | 欧美成人午夜免费视在线看片| 久久久www| 亚洲国产精品99久久久久久久久| 欧美有码在线观看视频| 亚洲视频你懂的| 午夜一区在线| 美国十次了思思久久精品导航| 你懂的视频一区二区| 亚洲日韩成人| 亚洲一区精彩视频| 麻豆亚洲精品| 国产精品爽爽爽| 亚洲另类黄色| 欧美在线视频二区| 亚洲国产视频a| 欧美一区二区免费观在线| 看片网站欧美日韩| 国产欧美日韩精品a在线观看| 狠狠噜噜久久| 欧美一级一区| 亚洲欧洲日韩综合二区| 久久久久国内| 国产日韩欧美一区二区三区四区 | 欧美一区永久视频免费观看| 免费欧美日韩国产三级电影| 亚洲一区日本| 欧美视频四区| 亚洲欧美日韩国产综合在线 | av成人免费在线观看| 免播放器亚洲一区| 亚洲国产导航| 欧美成人乱码一区二区三区| 亚洲自拍都市欧美小说| 欧美日韩一区精品| 欧美乱大交xxxxx| 国内精品视频在线观看| 久久精品30| 久久成人这里只有精品| 亚洲电影免费观看高清| 另类酷文…触手系列精品集v1小说| 欧美一级视频| 一区在线播放| 亚洲理伦在线| 国产欧美日韩综合| 欧美成人亚洲成人| 欧美日韩不卡一区| 欧美在线免费看| 欧美国产欧美亚洲国产日韩mv天天看完整 | 欧美性做爰猛烈叫床潮| 午夜宅男久久久| 男人天堂欧美日韩| 亚洲欧美综合精品久久成人| 欧美一区免费| 亚洲一二三四久久| 久久天天狠狠| 午夜精品一区二区三区在线 | 国产亚洲欧美色| 亚洲黄网站在线观看| 国产精品久久久久天堂| 欧美激情国产日韩精品一区18| 欧美午夜不卡| 中国成人亚色综合网站| 亚洲人成网站777色婷婷| 午夜精品视频在线观看| 亚洲人成网站色ww在线| 午夜久久资源| 久久久噜噜噜久久人人看| 国产精品第一区| 亚洲主播在线播放| 亚洲欧美国产精品桃花| 欧美伦理一区二区| 一区二区三区高清不卡| 一本大道久久a久久综合婷婷 | 亚洲人体偷拍| 99成人在线| 国产精品美女一区二区| 亚洲一区在线直播| 久久9热精品视频| 伊人久久大香线| 女仆av观看一区| 一级日韩一区在线观看| 久久大逼视频| 亚洲乱码国产乱码精品精可以看 | 久久嫩草精品久久久精品一| 国产欧美精品xxxx另类| 性久久久久久久| 欧美激情久久久久| 亚洲婷婷综合久久一本伊一区| 国产精品白丝av嫩草影院| 欧美在线资源| 一区二区三区欧美亚洲| 久久亚洲免费| 欧美一级一区| 在线性视频日韩欧美| 国产在线观看91精品一区| 欧美高清视频在线| 欧美中文在线免费| 一区二区动漫| 亚洲欧洲在线观看| 欧美成人综合一区| 欧美一区二区三区四区视频| 亚洲精品乱码久久久久久日本蜜臀| 国产精品高清在线| 欧美日韩福利视频| 欧美激情视频一区二区三区免费| 欧美一区二区三区在线视频| 99热在这里有精品免费| 亚洲高清av| 亚洲精品激情| 亚洲影院在线| 亚洲欧美韩国| 久久久久久尹人网香蕉| 久久精品国产综合| 久久久五月天| 牛人盗摄一区二区三区视频| 免费高清在线一区| 欧美国产日韩在线| 欧美日韩一区二区在线| 国产精品高精视频免费| 国产一区二区三区高清播放| 国内精品国产成人| 亚洲精品免费在线| 亚洲一区二区免费看|