该实例程序是创建和渲染一个如图12.8所示的场景。你能够通过键盘输入在场景中自由地飞行。下面是相应键盘设置:
W/S—向前/向后移动
A/D—向左/向右平移
R/F—向上/向下飞行
Up/Down方向键—倾斜
Left/Right方向键—偏航
N/M—滚转
图12.8
class cTextureVertex
{
public:
float m_x, m_y, m_z;
float m_nx, m_ny, m_nz;
float m_u, m_v;
cTextureVertex() { }
cTextureVertex(float x, float y, float z,
float nx, float ny, float nz,
float u, float v)
{
m_x = x; m_y = y; m_z = z;
m_nx = nx; m_ny = ny; m_nz = nz;
m_u = u; m_v = v;
}
};
const DWORD TEXTURE_VERTEX_FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;
// function references "desert.bmp" internally, this file must be in the working directory.
bool draw_basic_scene(
IDirect3DDevice9* device, // pass in NULL for cleanup
float scale); // uniform scale
bool draw_basic_scene(IDirect3DDevice9* device, float scale)
{
static IDirect3DVertexBuffer9* floor_vb = NULL;
static IDirect3DTexture9* texture = NULL;
static ID3DXMesh* pillar_mesh = NULL;
if(device == NULL)
{
if(floor_vb && texture && pillar_mesh)
{
// they already exist, destroy them.
safe_release<IDirect3DVertexBuffer9*>(floor_vb);
safe_release<IDirect3DTexture9*>(texture);
safe_release<ID3DXMesh*>(pillar_mesh);
}
}
else if(floor_vb == NULL && texture == NULL && pillar_mesh == NULL)
{
// they don't exist, create them.
device->CreateVertexBuffer(6 * sizeof(cTextureVertex), 0, TEXTURE_VERTEX_FVF, D3DPOOL_MANAGED, &floor_vb, 0);
cTextureVertex* v;
floor_vb->Lock(0, 0, (void**)&v, 0);
v[0] = cTextureVertex(-20.0f, -2.5f, -20.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
v[1] = cTextureVertex(-20.0f, -2.5f, 20.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
v[2] = cTextureVertex( 20.0f, -2.5f, 20.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);
v[3] = cTextureVertex(-20.0f, -2.5f, -20.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
v[4] = cTextureVertex( 20.0f, -2.5f, 20.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);
v[5] = cTextureVertex( 20.0f, -2.5f, -20.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f);
floor_vb->Unlock();
D3DXCreateCylinder(device, 0.5f, 0.5f, 5.0f, 20, 20, &pillar_mesh, NULL);
D3DXCreateTextureFromFile(device, "desert.bmp", &texture);
}
else
{
// pre-render setup
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
D3DXVECTOR3 dir(0.707f, -0.707f, 0.707f);
D3DXCOLOR color(1.0f, 1.0f, 1.0f, 1.0f);
D3DLIGHT9 light = init_directional_light(&dir, &color);
device->SetLight(0, &light);
device->LightEnable(0, TRUE);
device->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE);
device->SetRenderState(D3DRS_SPECULARENABLE, TRUE);
// render
D3DXMATRIX transform_matrix, rotate_matrix, pillor_matrix, scale_matrix;
D3DXMatrixScaling(&scale_matrix, scale, scale, scale);
// used to rotate cylinders to be parallel with world's y-axis
D3DXMatrixRotationX(&rotate_matrix, -D3DX_PI * 0.5f);
// draw floor
D3DXMatrixIdentity(&transform_matrix);
transform_matrix *= scale_matrix;
device->SetTransform(D3DTS_WORLD, &transform_matrix);
device->SetMaterial(&WHITE_MATERIAL);
device->SetTexture(0, texture);
device->SetStreamSource(0, floor_vb, 0, sizeof(cTextureVertex));
device->SetFVF(TEXTURE_VERTEX_FVF);
device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
// draw pillars
device->SetMaterial(&BLUE_MATERIAL);
device->SetTexture(0, NULL);
for(int i = 0; i < 5; i++)
{
// left pillar
D3DXMatrixTranslation(&transform_matrix, -5.0f, 0.0f, -15.0f + (i * 7.5f));
pillor_matrix = rotate_matrix * transform_matrix * scale_matrix;
device->SetTransform(D3DTS_WORLD, &pillor_matrix);
pillar_mesh->DrawSubset(0);
// right pillar
D3DXMatrixTranslation(&transform_matrix, 5.0f, 0.0f, -15.0f + (i * 7.5f));
pillor_matrix = rotate_matrix * transform_matrix * scale_matrix;
device->SetTransform(D3DTS_WORLD, &pillor_matrix);
pillar_mesh->DrawSubset(0);
}
}
return true;
}
主程序:
/**************************************************************************************
Demonstrates using the Camera class.
**************************************************************************************/
#include "d3dUtility.h"
#include "camera.h"
#pragma warning(disable : 4100)
const int WIDTH = 640;
const int HEIGHT = 480;
IDirect3DDevice9* g_device;
cCamera g_camera(AIR_CRAFT);
////////////////////////////////////////////////////////////////////////////////////////////////////
bool setup()
{
// setup a basic scnen, the scene will be created the first time this function is called.
draw_basic_scene(g_device, 0.0f);
// set the projection matrix
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI/4.0f, (float)WIDTH/HEIGHT, 1.0f, 1000.0f);
g_device->SetTransform(D3DTS_PROJECTION, &proj);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
void cleanup()
{
// pass NULL for the first parameter to instruct cleanup
draw_basic_scene(NULL, 0.0f);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
bool display(float time_delta)
{
// update the camera
float change_value = 4.0f * time_delta;
if(GetAsyncKeyState('W') & 0x80000f)
g_camera.walk(change_value);
if( GetAsyncKeyState('S') & 0x8000f )
g_camera.walk(-change_value);
if( GetAsyncKeyState('A') & 0x8000f )
g_camera.strafe(-change_value);
if( GetAsyncKeyState('D') & 0x8000f )
g_camera.strafe(change_value);
if( GetAsyncKeyState('R') & 0x8000f )
g_camera.fly(change_value);
if( GetAsyncKeyState('F') & 0x8000f )
g_camera.fly(-change_value);
change_value = time_delta;
if( GetAsyncKeyState(VK_UP) & 0x8000f )
g_camera.pitch(change_value);
if( GetAsyncKeyState(VK_DOWN) & 0x8000f )
g_camera.pitch(-change_value);
if( GetAsyncKeyState(VK_LEFT) & 0x8000f )
g_camera.yaw(-change_value);
if( GetAsyncKeyState(VK_RIGHT) & 0x8000f )
g_camera.yaw(change_value);
if( GetAsyncKeyState('N') & 0x8000f )
g_camera.roll(change_value);
if( GetAsyncKeyState('M') & 0x8000f )
g_camera.roll(-change_value);
// update the view matrix representing the camera's new position/orientation
D3DXMATRIX view_matrix;
g_camera.get_view_matrix(&view_matrix);
g_device->SetTransform(D3DTS_VIEW, &view_matrix);
// render now
g_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
g_device->BeginScene();
draw_basic_scene(g_device, 1.0f);
g_device->EndScene();
g_device->Present(NULL, NULL, NULL, NULL);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK wnd_proc(HWND hwnd, UINT msg, WPARAM word_param, LPARAM long_param)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
if(word_param == VK_ESCAPE)
DestroyWindow(hwnd);
break;
}
return DefWindowProc(hwnd, msg, word_param, long_param);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, PSTR cmd_line, int cmd_show)
{
if(! init_d3d(inst, WIDTH, HEIGHT, true, D3DDEVTYPE_HAL, &g_device))
{
MessageBox(NULL, "init_d3d() - failed.", 0, MB_OK);
return 0;
}
if(! setup())
{
MessageBox(NULL, "Steup() - failed.", 0, MB_OK);
return 0;
}
enter_msg_loop(display);
cleanup();
g_device->Release();
return 0;
}
下载源程序