直线:
#include#include #include #pragma comment(lib, "d3d9.lib") #pragma comment(lib, "d3dx9.lib") #pragma comment(lib, "winmm.lib") #define WINDOW_CLASS "UGPDX" #define WINDOW_NAME "Straight Line Animation" #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 #define FULLSCREEN 0 // Function Prototypes... bool InitializeD3D(); bool InitializeObjects(); void RenderScene(); void Shutdown(); // Global window handle. HWND g_hwnd = 0; // Direct3D object and device. LPDIRECT3D9 g_D3D = NULL; LPDIRECT3DDEVICE9 g_D3DDevice = NULL; // Matrices. D3DXMATRIX g_projection; D3DXMATRIX g_worldMatrix; D3DXMATRIX g_ViewMatrix; // Display object. LPD3DXMESH g_model = NULL; // struct stVector { stVector() : x(0), y(0), z(0) {} float x, y, z; }; // Path will hold the start and end position of our animation. stVector Path[4]; stVector objPos; // CurrentPath will hold which of the two striaght line paths we are on. int CurrentPath = 1; // Used for time based calculations. float StartTime = 0; LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DESTROY: case WM_CLOSE: PostQuitMessage(0); return 0; break; case WM_KEYUP: if(wParam == VK_ESCAPE) PostQuitMessage(0); break; } return DefWindowProc(hWnd, msg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInst, HINSTANCE prevhInst, LPSTR cmdLine, int show) { // Register the window class WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, WINDOW_CLASS, NULL }; RegisterClassEx(&wc); // Create the application's window HWND hWnd = CreateWindow(WINDOW_CLASS, WINDOW_NAME, WS_OVERLAPPEDWINDOW, 100, 100, WINDOW_WIDTH, WINDOW_HEIGHT, GetDesktopWindow(), NULL, wc.hInstance, NULL); // Show the window ShowWindow(hWnd, SW_SHOWDEFAULT); UpdateWindow(hWnd); // Record for global. g_hwnd = hWnd; // Initialize Direct3D if(InitializeD3D()) { // Enter the message loop MSG msg; ZeroMemory(&msg, sizeof(msg)); while(msg.message != WM_QUIT) { if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else RenderScene(); } } // Release any and all resources. Shutdown(); // Unregister our window. UnregisterClass(WINDOW_CLASS, wc.hInstance); return 0; } bool InitializeD3D() { D3DDISPLAYMODE displayMode; // Create the D3D object. g_D3D = Direct3DCreate9(D3D_SDK_VERSION); if(g_D3D == NULL) return false; // Get the desktop display mode. if(FAILED(g_D3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode))) return false; // Set up the structure used to create the D3DDevice D3DPRESENT_PARAMETERS d3dpp; ZeroMemory(&d3dpp, sizeof(d3dpp)); if(FULLSCREEN) { d3dpp.Windowed = FALSE; d3dpp.BackBufferWidth = WINDOW_WIDTH; d3dpp.BackBufferHeight = WINDOW_HEIGHT; } else d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = displayMode.Format; d3dpp.BackBufferCount = 1; d3dpp.EnableAutoDepthStencil = TRUE; d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // Create the D3DDevice if(FAILED(g_D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &d3dpp, &g_D3DDevice))) return false; // Initialize any objects we will be displaying. if(!InitializeObjects()) return false; return true; } bool InitializeObjects() { // Set default rendering states. g_D3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE); g_D3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); g_D3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); // Here we are setting our striaght line path. Path[0].x = -2.5f; Path[0].y = 1.0f; Path[0].z = 0.0f; Path[1].x = 2.5f; Path[1].y = 1.0f; Path[1].z = 0.0f; Path[2].x = 2.5f; Path[2].y = 1.0f; Path[2].z = 0.0f; Path[3].x = -2.5f; Path[3].y = 1.0f; Path[3].z = 0.0f; // Initialize the start time for this simulation. StartTime = (float)timeGetTime(); // Create mesh. if(FAILED(D3DXCreateBox(g_D3DDevice, 1, 1, 1, &g_model, NULL))) return false; // Set the projection matrix. D3DXMatrixPerspectiveFovLH(&g_projection, D3DX_PI / 4, WINDOW_WIDTH/WINDOW_HEIGHT, 0.1f, 1000.0f); g_D3DDevice->SetTransform(D3DTS_PROJECTION, &g_projection); // Define camera information. D3DXVECTOR3 cameraPos(0.0f, 0.0f, -10.0f); D3DXVECTOR3 lookAtPos(0.0f, 0.0f, 0.0f); D3DXVECTOR3 upDir(0.0f, 1.0f, 0.0f); // Build view matrix. D3DXMatrixLookAtLH(&g_ViewMatrix, &cameraPos, &lookAtPos, &upDir); return true; } void RenderScene() { // Clear the backbuffer. g_D3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0); // Begin the scene. Start rendering. g_D3DDevice->BeginScene(); // Apply the view (camera). g_D3DDevice->SetTransform(D3DTS_VIEW, &g_ViewMatrix); // Update the time. Since we are using time based movements // and calculations we get the time, sub from the start time, // then multiply that by the speed of the simulation. float Scalar = (float)timeGetTime(); Scalar = (Scalar - StartTime) * 0.003f; // Get the new object position by using a simple interpolation equation. If we are // in the first path, then we use the first path data, else the second path data. if(CurrentPath == 1) { // We must divide the scalar by the length of the path so our animation is // smooth and correct. Then we use the interpolation calculation to determine // the position. stVector diff; diff.x = Path[1].x - Path[0].x; diff.y = Path[1].y - Path[0].y; diff.z = Path[1].z - Path[0].z; float len = (float)sqrt((diff.x * diff.x + diff.y * diff.y + diff.z * diff.z)); Scalar = Scalar / len; objPos.x = (Path[1].x - Path[0].x) * Scalar + Path[0].x; objPos.y = (Path[1].y - Path[0].y) * Scalar + Path[0].y; objPos.z = (Path[1].z - Path[0].z) * Scalar + Path[0].z; } else { stVector diff; diff.x = Path[3].x - Path[2].x; diff.y = Path[3].y - Path[2].y; diff.z = Path[3].z - Path[2].z; float len = (float)sqrt((diff.x * diff.x + diff.y * diff.y + diff.z * diff.z)); Scalar = Scalar / len; objPos.x = (Path[3].x - Path[2].x) * Scalar + Path[2].x; objPos.y = (Path[3].y - Path[2].y) * Scalar + Path[2].y; objPos.z = (Path[3].z - Path[2].z) * Scalar + Path[2].z; } // If Scalar reaches 1.0f then that means we are at the end of the animation. We // simply reset the start time then increase the value that represents which path // we are on. Since we have only two paths we then check to make sure we dont go // over that value. if(Scalar >= 1.0f) { // Reset the start time. StartTime = (float)timeGetTime(); // Move to the next path. CurrentPath++; // We only have 2 paths so make sure we don't go over that number. if(CurrentPath > 2) CurrentPath = 1; } D3DXMATRIX mat; D3DXMatrixTranslation(&mat, objPos.x, objPos.y, objPos.z); g_D3DDevice->SetTransform(D3DTS_WORLD, &mat); // Draw the model. g_model->DrawSubset(0); // End the scene. Stop rendering. g_D3DDevice->EndScene(); // Display the scene. g_D3DDevice->Present(NULL, NULL, NULL, NULL); } void Shutdown() { if(g_D3DDevice != NULL) g_D3DDevice->Release(); g_D3DDevice = NULL; if(g_D3D != NULL) g_D3D->Release(); g_D3D = NULL; if(g_model != NULL) g_model->Release(); g_model = NULL; }
2. 曲线路径
接下来要介绍的一种动画是曲线路径。该路径从点A到点B是取线而不是直线。用大量相互连接的小直线连接在一起就可以创建一条曲线。用的直线越多,曲线看上去就越平滑。这虽不完美,但为了非常接近完美就要用大量的数据。直线路径和曲线路径的差异在于后者使用了点A和点B两个点以及两个控制点,总计4个点。这类曲线即为三次方贝塞尔曲线。控制点用于将直线弯折者曲线。
直线演示程序用到了两点和一个计算物体最终位置的比值。对于三次方贝塞尔曲线而言,要使用4个点和1个比值。曲线可以根据控制点的位置以任意方式弯曲扭转。像直线路径一样,0%意味着物体在点A,100%意味着物体在点B。计算曲线上点的位置的方程并不像直线的那样简单。
程序清单13.6中的A代表点A,B代表点B,C1代表控制点1,C2代表控制点2。同样方程中S代表比值,S2代表比值的平方,S3代表比值的三次方。
三次方贝塞尔曲线公式:Final = A * (1-S)3 + C1 * 3 * S * (1-S)2 + C2 * 3 * S2 * (1-S) + B * S3
验证该例子的演示程序在本配套光盘上的CHAPTER13文件夹中,名为CurvePath(曲线路径)。为了更方便地创建该演示程序,可以只采用直线演示程序的代码,将其修改为曲线路径即可。CurvePath演示程序的全局部分如程序清单13.7所示。这里用包含了一些重载操作符3D矢量类来代表点,使用该类可以比在每个轴上分别处理要清晰得多。
#include#include #include #include"Vector.h" #pragma comment(lib, "d3d9.lib") #pragma comment(lib, "d3dx9.lib") #pragma comment(lib, "winmm.lib") #define WINDOW_CLASS "UGPDX" #define WINDOW_NAME "Curve Line Animation" #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 #define FULLSCREEN 0 // Function Prototypes... bool InitializeD3D(); bool InitializeObjects(); void RenderScene(); void Shutdown(); // Global window handle. HWND g_hwnd = 0; // Direct3D object and device. LPDIRECT3D9 g_D3D = NULL; LPDIRECT3DDEVICE9 g_D3DDevice = NULL; // Matrices. D3DXMATRIX g_projection; D3DXMATRIX g_worldMatrix; D3DXMATRIX g_ViewMatrix; // Display object. LPD3DXMESH g_model = NULL; // Path will hold the start and end position of our animation. CVector3 Path[4]; CVector3 objPos; // Used for time based calculations. float StartTime = 0; LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DESTROY: case WM_CLOSE: PostQuitMessage(0); return 0; break; case WM_KEYUP: if(wParam == VK_ESCAPE) PostQuitMessage(0); break; } return DefWindowProc(hWnd, msg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInst, HINSTANCE prevhInst, LPSTR cmdLine, int show) { // Register the window class WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, WINDOW_CLASS, NULL }; RegisterClassEx(&wc); // Create the application's window HWND hWnd = CreateWindow(WINDOW_CLASS, WINDOW_NAME, WS_OVERLAPPEDWINDOW, 100, 100, WINDOW_WIDTH, WINDOW_HEIGHT, GetDesktopWindow(), NULL, wc.hInstance, NULL); // Show the window ShowWindow(hWnd, SW_SHOWDEFAULT); UpdateWindow(hWnd); // Record for global. g_hwnd = hWnd; // Initialize Direct3D if(InitializeD3D()) { // Enter the message loop MSG msg; ZeroMemory(&msg, sizeof(msg)); while(msg.message != WM_QUIT) { if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else RenderScene(); } } // Release any and all resources. Shutdown(); // Unregister our window. UnregisterClass(WINDOW_CLASS, wc.hInstance); return 0; } bool InitializeD3D() { D3DDISPLAYMODE displayMode; // Create the D3D object. g_D3D = Direct3DCreate9(D3D_SDK_VERSION); if(g_D3D == NULL) return false; // Get the desktop display mode. if(FAILED(g_D3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode))) return false; // Set up the structure used to create the D3DDevice D3DPRESENT_PARAMETERS d3dpp; ZeroMemory(&d3dpp, sizeof(d3dpp)); if(FULLSCREEN) { d3dpp.Windowed = FALSE; d3dpp.BackBufferWidth = WINDOW_WIDTH; d3dpp.BackBufferHeight = WINDOW_HEIGHT; } else d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = displayMode.Format; d3dpp.BackBufferCount = 1; d3dpp.EnableAutoDepthStencil = TRUE; d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // Create the D3DDevice if(FAILED(g_D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &d3dpp, &g_D3DDevice))) return false; // Initialize any objects we will be displaying. if(!InitializeObjects()) return false; return true; } bool InitializeObjects() { // Set default rendering states. g_D3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE); g_D3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); g_D3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); // Here we are setting our striaght line path. Path[0].x = -2.0f; Path[0].y = 1.0f; Path[0].z = 0.0f; Path[1].x = -1.0f; Path[1].y = 0.0f; Path[1].z = 0.0f; Path[2].x = 1.0f; Path[2].y = 0.0f; Path[2].z = 0.0f; Path[3].x = 2.0f; Path[3].y = 1.0f; Path[3].z = 0.0f; // Initialize the start time for this simulation. StartTime = (float)timeGetTime(); // Create mesh. if(FAILED(D3DXCreateBox(g_D3DDevice, 1, 1, 1, &g_model, NULL))) return false; D3DXMatrixPerspectiveFovLH(&g_projection, D3DX_PI / 4, WINDOW_WIDTH/WINDOW_HEIGHT, 0.1f, 1000.0f); g_D3DDevice->SetTransform(D3DTS_PROJECTION, &g_projection); D3DXVECTOR3 cameraPos(0.0f, 0.0f, -10.0f); D3DXVECTOR3 lookAtPos(0.0f, 0.0f, 0.0f); D3DXVECTOR3 upDir(0.0f, 1.0f, 0.0f); D3DXMatrixLookAtLH(&g_ViewMatrix, &cameraPos, &lookAtPos, &upDir); return true; } CVector3 CalcBezierCurvePos(CVector3 start, CVector3 cnt1, CVector3 cnt2, CVector3 end, float Scalar) { CVector3 out; // Here we have a formula that is used to calculate a position on the cubic bezier curve // based on the Scalar value. out = start * (1.0f - Scalar) * (1.0f - Scalar) * (1.0f - Scalar) + cnt1 * 3.0f * Scalar * (1.0f - Scalar) * (1.0f - Scalar) + cnt2 * 3.0f * Scalar * Scalar * (1.0f - Scalar) + end * Scalar * Scalar * Scalar; return out; } void RenderScene() { g_D3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0); g_D3DDevice->BeginScene(); g_D3DDevice->SetTransform(D3DTS_VIEW, &g_ViewMatrix); // First we must calculate the object position along the curve. Since we are using time // based movements for everything we first get the time in seconds. The value 0.001 will // act as the speed of the animation. float Time = (float)timeGetTime(); Time = (Time - StartTime) * 0.003f; // Next we take that value and sin() it, add 1, then divide by half. This will give us // a value between 0 and 1. 0 is the start of the curve, 1 is the end, and anything between // the two is on the curve. Using a sine wave will allow us to loop the animation back // and forward. float Scalar = (((float)sin(Time)) + 1.0f) * 0.5f; // Now we calculate the position on the curve by taking the curve path data and // using the Scalar to dictate where on that curve the position lies. objPos = CalcBezierCurvePos(Path[0], Path[1], Path[2], Path[3], Scalar); D3DXMATRIX mat; D3DXMatrixTranslation(&mat, objPos.x, objPos.y, objPos.z); g_D3DDevice->SetTransform(D3DTS_WORLD, &mat); g_model->DrawSubset(0); g_D3DDevice->EndScene(); g_D3DDevice->Present(NULL, NULL, NULL, NULL); } void Shutdown() { if(g_D3DDevice != NULL) g_D3DDevice->Release(); g_D3DDevice = NULL; if(g_D3D != NULL) g_D3D->Release(); g_D3D = NULL; if(g_model != NULL) g_model->Release(); g_model = NULL; }
3. 圆形路径
要介绍的最后一种路径是圆形路径。物体将在一个完整的圆上围绕着一个轴移动。为了定义圆形路径,需要知道圆心、半径、起始点、物体移动的平面法线、平面上的u和v两个正交矢量。计算矢量u和平面法线的外积(或叉积)就可得到矢量v。由矢量u的长度可计算出半径。圆形、平面法线和起始点都是定义圆形路径要用到的矢量。
一旦有了u、v、半径和圆心位置,就可以根据提供的0(0%)和1(100%)之间的数值计算圆上任意点的位置,就像前面在其他函数中所做的一样。本例中,比值作为沿着圆上的一个角度。可以将这个角度值转换成半径,在计算中使用该转换后的值。例子如程序清单13.10所示,它包含了一个名为CalcCirclePos()的函数。像计算三次方贝塞尔曲线上点的位置的CalcBezierCurvePos()函数一样,通过该函数可以计算圆上点的位置。
#include#include #include #include"Vector.h" #pragma comment(lib, "d3d9.lib") #pragma comment(lib, "d3dx9.lib") #pragma comment(lib, "winmm.lib") #define WINDOW_CLASS "UGPDX" #define WINDOW_NAME "Circle Path Animation" #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 #define FULLSCREEN 0 #define M_PI 3.141592654f // Function Prototypes... bool InitializeD3D(); bool InitializeObjects(); void RenderScene(); void Shutdown(); // Global window handle. HWND g_hwnd = 0; // Direct3D object and device. LPDIRECT3D9 g_D3D = NULL; LPDIRECT3DDEVICE9 g_D3DDevice = NULL; // Matrices. D3DXMATRIX g_projection; D3DXMATRIX g_worldMatrix; D3DXMATRIX g_ViewMatrix; // Display object. LPD3DXMESH g_model = NULL; // Center of circle path. CVector3 g_center(0.0f, 0.0f, 0.0f); // Start position of the animation and the point in the plane (direction). CVector3 start(2.0f, 0.0f, 0.0f); CVector3 planeDirection(0.0f, 0.0f, 1.0f); // u and v are orthonormal vectors in the plane. 正规化的向量u,v // u points from the center to the start and v is perpendicular(正交) to u. CVector3 g_u, g_v; // Circle's radius. float g_radius = 0; // objPos will hold the objects current position on the curve path. CVector3 objPos; // Used for time based calculations. float StartTime = 0; LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DESTROY: case WM_CLOSE: PostQuitMessage(0); return 0; break; case WM_KEYUP: if(wParam == VK_ESCAPE) PostQuitMessage(0); break; } return DefWindowProc(hWnd, msg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInst, HINSTANCE prevhInst, LPSTR cmdLine, int show) { // Register the window class WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, WINDOW_CLASS, NULL }; RegisterClassEx(&wc); // Create the application's window HWND hWnd = CreateWindow(WINDOW_CLASS, WINDOW_NAME, WS_OVERLAPPEDWINDOW, 100, 100, WINDOW_WIDTH, WINDOW_HEIGHT, GetDesktopWindow(), NULL, wc.hInstance, NULL); // Show the window ShowWindow(hWnd, SW_SHOWDEFAULT); UpdateWindow(hWnd); // Record for global. g_hwnd = hWnd; // Initialize Direct3D if(InitializeD3D()) { // Enter the message loop MSG msg; ZeroMemory(&msg, sizeof(msg)); while(msg.message != WM_QUIT) { if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else RenderScene(); } } // Release any and all resources. Shutdown(); // Unregister our window. UnregisterClass(WINDOW_CLASS, wc.hInstance); return 0; } bool InitializeD3D() { D3DDISPLAYMODE displayMode; // Create the D3D object. g_D3D = Direct3DCreate9(D3D_SDK_VERSION); if(g_D3D == NULL) return false; // Get the desktop display mode. if(FAILED(g_D3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode))) return false; // Set up the structure used to create the D3DDevice D3DPRESENT_PARAMETERS d3dpp; ZeroMemory(&d3dpp, sizeof(d3dpp)); if(FULLSCREEN) { d3dpp.Windowed = FALSE; d3dpp.BackBufferWidth = WINDOW_WIDTH; d3dpp.BackBufferHeight = WINDOW_HEIGHT; } else d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = displayMode.Format; d3dpp.BackBufferCount = 1; d3dpp.EnableAutoDepthStencil = TRUE; d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // Create the D3DDevice if(FAILED(g_D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &d3dpp, &g_D3DDevice))) return false; // Initialize any objects we will be displaying. if(!InitializeObjects()) return false; return true; } bool InitializeObjects() { // Set default rendering states. g_D3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE); g_D3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); g_D3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); // First we make sure that the center, start pos, and point in the plane are colinear(共线). CVector3 planeNormal; planeNormal.CrossProduct(start - g_center, planeDirection - g_center); // Check if they are colinear. if(planeNormal.GetLength() < 0.01f) { MessageBox(0, "Circle path must be colinear!", "Error...", MB_OK); return false; } // If they are then we normalize and continue the calculation. planeNormal.Normal(); // The radius will be determined by where the center of the circle is and the start // position of the animation. The u and v are orthonormal vectors. u goes from // the start to center while v is perpendicular to the u. g_radius = (start - g_center).GetLength(); g_u = (start - g_center); g_u.Normal(); g_v.CrossProduct(g_u, planeNormal); // Initialize the start time for this simulation. StartTime = (float)timeGetTime(); // Create mesh. if(FAILED(D3DXCreateBox(g_D3DDevice, 1, 1, 1, &g_model, NULL))) return false; // Set the projection matrix. D3DXMatrixPerspectiveFovLH(&g_projection, D3DX_PI / 4, WINDOW_WIDTH/WINDOW_HEIGHT, 0.1f, 1000.0f); g_D3DDevice->SetTransform(D3DTS_PROJECTION, &g_projection); // Define camera information. D3DXVECTOR3 cameraPos(0.0f, 0.0f, -10.0f); D3DXVECTOR3 lookAtPos(0.0f, 0.0f, 0.0f); D3DXVECTOR3 upDir(0.0f, 1.0f, 0.0f); // Build view matrix. D3DXMatrixLookAtLH(&g_ViewMatrix, &cameraPos, &lookAtPos, &upDir); return true; } CVector3 CalcCirclePos(float angle, CVector3 center, CVector3 u, CVector3 v, float radius) { float newAngle = angle * (float)(M_PI / 180); return center + u * radius * float(cos(newAngle)) + v * radius * float(sin(newAngle)); } void RenderScene() { // Clear the backbuffer. g_D3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0); // Begin the scene. Start rendering. g_D3DDevice->BeginScene(); // Apply the view (camera). g_D3DDevice->SetTransform(D3DTS_VIEW, &g_ViewMatrix); // First we must calculate the object position along the // circle. Since we are using time based movements for // everything we first get the time in seconds. The value 0.06 will // act as the speed of the animation. float Time = (float)timeGetTime(); Time = (Time - StartTime) * 0.06f; // Now we calculate the position on the curve by taking the circle path data and // using the scalar Time to dictate where on that circle (the angle) the position lies. objPos = CalcCirclePos(Time, g_center, g_u, g_v, g_radius); D3DXMATRIX mat; D3DXMatrixTranslation(&mat, objPos.x, objPos.y, objPos.z); g_D3DDevice->SetTransform(D3DTS_WORLD, &mat); // Draw the model. g_model->DrawSubset(0); // End the scene. Stop rendering. g_D3DDevice->EndScene(); // Display the scene. g_D3DDevice->Present(NULL, NULL, NULL, NULL); } void Shutdown() { if(g_D3DDevice != NULL) g_D3DDevice->Release(); g_D3DDevice = NULL; if(g_D3D != NULL) g_D3D->Release(); g_D3D = NULL; if(g_model != NULL) g_model->Release(); g_model = NULL; }