51. 模型动画动画路径

直线:

#include<d3d9.h>
#include<d3dx9.h>
#include<mmsystem.h>

#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<d3d9.h>
#include<d3dx9.h>
#include<mmsystem.h>
#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<d3d9.h>
#include<d3dx9.h>
#include<mmsystem.h>
#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;
}
原文地址:https://www.cnblogs.com/kex1n/p/2203949.html