• <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>

            天行健 君子當(dā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) 評論(0)  編輯 收藏 引用


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


            公告

            導(dǎo)航

            統(tǒng)計

            常用鏈接

            隨筆分類(178)

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

            搜索

            最新評論

            久久综合九色综合欧美就去吻| 亚洲精品tv久久久久| 久久无码国产专区精品| 色欲综合久久躁天天躁| 无码精品久久久天天影视| AAA级久久久精品无码片| 美女写真久久影院| 欧美成人免费观看久久| 国产精品久久久久久久久| 青青青青久久精品国产h| 久久综合色老色| 久久精品国产精品亚洲艾草网美妙| 亚洲国产成人精品无码久久久久久综合| 亚洲va久久久噜噜噜久久男同| 爱做久久久久久| 久久国产精品99精品国产| 亚洲精品国产第一综合99久久| 久久亚洲国产欧洲精品一| 无码精品久久久天天影视| 国内精品久久国产| 久久久精品人妻无码专区不卡| www.久久99| 国产成人无码久久久精品一| 一级做a爰片久久毛片看看| 久久久久一本毛久久久| 97久久精品人人澡人人爽| 91精品国产综合久久婷婷| 久久夜色精品国产欧美乱| 久久人人爽人人爽人人片AV高清 | 一级做a爰片久久毛片16| 久久香综合精品久久伊人| 亚洲国产成人精品久久久国产成人一区二区三区综 | 久久久青草青青国产亚洲免观| 国产麻豆精品久久一二三| 亚洲色大成网站www久久九| 久久精品国产亚洲av麻豆蜜芽 | 久久久久久久亚洲Av无码| 亚洲精品乱码久久久久久久久久久久| 久久最新免费视频| 久久久久久久精品成人热色戒| 亚洲精品视频久久久|