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

天行健 君子當自強而不息

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 閱讀(462) 評論(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在线| 亚洲人成网站777色婷婷| 久久亚洲精品网站| 亚洲片区在线| 亚洲大胆女人| 欧美华人在线视频| 一区二区三区黄色| 国产精品99久久久久久宅男| 国产精品vvv| 欧美中日韩免费视频| 久久av老司机精品网站导航| 国产综合香蕉五月婷在线| 久久先锋资源| 欧美成人免费在线视频| 亚洲视频一区在线观看| 亚洲综合丁香| 在线观看三级视频欧美| 亚洲福利小视频| 欧美日韩一视频区二区| 久久国产精品久久久久久久久久| 久久er99精品| 亚洲美女电影在线| 亚洲专区一二三| 亚洲国产精品尤物yw在线观看| 亚洲国产精品成人一区二区| 久久亚洲午夜电影| 欧美激情一区二区三区成人| 亚洲一级片在线观看| 久久精品女人的天堂av| 一区二区三区四区五区在线| 午夜精品影院| 一区二区三区精品| 久久婷婷国产麻豆91天堂| 中文亚洲视频在线| 久久久久久久久久看片| 亚洲天堂黄色| 裸体歌舞表演一区二区| 亚洲欧美日本国产专区一区| 老司机久久99久久精品播放免费| 亚洲一区高清| 欧美成人精品高清在线播放| 欧美与黑人午夜性猛交久久久| 免费在线观看一区二区| 久久九九免费| 国产精品美女久久久浪潮软件| 欧美刺激性大交免费视频| 国产精品视频自拍| 99热在线精品观看| 亚洲精品1区2区| 欧美在线亚洲综合一区| 亚洲欧美日韩区| 欧美精品久久一区二区| 欧美aaaaaaaa牛牛影院| 国产欧美日韩精品专区| 中文亚洲欧美| 一区二区电影免费观看| 欧美电影电视剧在线观看| 久久中文在线| 国产手机视频精品| 亚洲一区二区三区免费在线观看 | 亚洲视屏在线播放| 亚洲看片免费| 老司机67194精品线观看| 久久久夜色精品亚洲| 国产精品免费小视频| 日韩亚洲欧美一区| 亚洲视频图片小说| 欧美日韩另类综合| 亚洲毛片播放| 一区二区三区高清| 欧美日韩福利| 亚洲人成绝费网站色www| 9久re热视频在线精品| 欧美国产在线电影| 亚洲精品久久视频| 亚洲一区精品在线| 国产精品二区在线观看| 亚洲视频在线二区| 性欧美超级视频| 国产美女搞久久| 欧美一区二区三区男人的天堂| 欧美一区二区三区在线视频 | 久久免费视频在线| 欧美大片在线影院| 99视频一区二区三区| 裸体一区二区| 亚洲电影一级黄| 欧美精品在线播放| 夜夜夜久久久| 久久成人精品无人区| 国产美女在线精品免费观看| 欧美综合77777色婷婷| 免费观看欧美在线视频的网站| 亚洲第一色中文字幕| 欧美日韩喷水| 欧美一级片一区| 欧美成人一区二区| 中文精品视频| 国产欧美一区二区三区久久| 久久久久国产免费免费| 亚洲人成艺术| 久久久噜噜噜久久中文字幕色伊伊 | 亚洲国产精品一区制服丝袜| 一区二区免费在线视频| 国产欧美大片| 欧美成人首页| 小嫩嫩精品导航| 亚洲国产高清视频| 欧美亚洲日本国产| 最新国产成人在线观看| 国产精品啊啊啊| 久久婷婷蜜乳一本欲蜜臀| 99在线|亚洲一区二区| 狼人社综合社区| 亚洲视频电影在线| 亚洲国产免费看| 国产精品天天看| 欧美激情精品久久久久久大尺度| 亚洲一区二区视频| 亚洲精品久久久久久久久久久| 久久国产视频网| 亚洲色图在线视频| 亚洲狠狠婷婷| 国语自产精品视频在线看抢先版结局 | 午夜精品福利电影| 欧美大片一区二区三区| 欧美在线播放一区二区| 亚洲精品美女在线观看| 久久久久欧美| 午夜精彩视频在线观看不卡| 亚洲美女黄网| 亚洲国产经典视频| 国产亚洲综合性久久久影院| 欧美日韩一区二区三区免费看| 久久一二三四| 欧美在线视频免费播放| 亚洲欧美日韩国产成人| 亚洲精品久久久久久一区二区 | 国内外成人免费视频 | 欧美亚洲综合另类| 中文久久精品| 在线亚洲观看| 一区二区不卡在线视频 午夜欧美不卡在 | 亚洲精品乱码久久久久久按摩观| 欧美成人免费大片| 久久午夜精品一区二区| 久久精品系列| 久久久久久亚洲精品不卡4k岛国| 亚洲欧美视频在线观看| 亚洲一区三区视频在线观看| 99国内精品久久| 一区二区三区.www| 亚洲调教视频在线观看| 亚洲一区二区三区视频播放| 亚洲一区二区三区777| 中国av一区| 亚洲欧美日韩国产精品| 午夜欧美不卡精品aaaaa| 新片速递亚洲合集欧美合集| 欧美一区二区免费视频| 久久精品一区二区| 久久综合五月| 亚洲国产精品一区二区www| 亚洲人精品午夜| 9l视频自拍蝌蚪9l视频成人| 在线亚洲欧美视频| 亚洲欧美日韩第一区| 久久九九免费视频| 欧美www在线| 欧美日韩在线视频首页| 国产精品免费视频xxxx| 狠狠色2019综合网| 亚洲精品日韩一| 午夜精品国产更新| 久久免费视频在线| 欧美国产日韩二区| 野花国产精品入口| 久久高清免费观看| 欧美日韩第一区| 国产一区二区三区免费在线观看| 亚洲高清在线观看一区| 亚洲网站啪啪| 玖玖玖免费嫩草在线影院一区| 亚洲精美视频| 欧美一级二级三级蜜桃| 欧美a一区二区| 国产乱人伦精品一区二区| 亚洲国产va精品久久久不卡综合| 妖精成人www高清在线观看| 欧美在线视频一区| 91久久综合亚洲鲁鲁五月天| 亚洲欧美日韩精品久久亚洲区| 久久婷婷国产综合尤物精品| 欧美午夜剧场| 亚洲精品国产精品国自产在线| 欧美亚洲免费| 亚洲精品社区|