使用DirectX 9.0 创建一个带贴图的旋转Cube

stage3d的资料实在是太少了。 so~ dreamfairy 决定从directX 入手来学习stage3d. 毕竟彼此是师徒关系,所以API基本都一致,名字也无二。

d3dcube
和stage3d一样,要创建一个cube需要准备 顶点,顶点索引。 贴图还需要创建 Texture.
在directX中。 context3D 是以 IDirect3DDevice9 来存在的。

准备工作有以下几个类.
cube.h 申明了cube的顶点和索引信息,以及 IDirect3DDevice9 的引用
cube.cpp 对Cube进行填充顶点,索引,以及绘制
texCube.cpp 负责具体的渲染循环,包括矩阵,相机,创建贴图等。
vertex.h 顶点坐标类,保存了顶点坐标,以及UV贴图坐标

代码如下:

cube.h
[cc lang=”c++” nowrap = false”]
#include “d3dx9.h”

class Cube
{
public:
Cube(IDirect3DDevice9* device);
~Cube();

bool draw(D3DXMATRIX* world, D3DMATERIAL9* mtrl, IDirect3DTexture9* tex);
private:
IDirect3DDevice9* _device;
IDirect3DVertexBuffer9* _vb;
IDirect3DIndexBuffer9* _ib;
};
[/cc]

cube.cpp
[cc lang=”c++” nowrap = false”]
#include “cube.h”
#include “vertex.h”

Cube::Cube(IDirect3DDevice9* device)
{
_device = device;

_device->CreateVertexBuffer(
24 * sizeof(Vertex),
D3DUSAGE_WRITEONLY,
FVF_VERTEX,
D3DPOOL_MANAGED,
&_vb,
0);

Vertex* v;
_vb->Lock(0,0,(void**)&v,0);

// fill in the front face vertex data
v[0] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
v[1] = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[2] = Vertex( 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
v[3] = Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);

// fill in the back face vertex data
v[4] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
v[5] = Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f);
v[6] = Vertex( 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f);
v[7] = Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f);

// fill in the top face vertex data
v[8] = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
v[9] = Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
v[10] = Vertex( 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f);
v[11] = Vertex( 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);

// fill in the bottom face vertex data
v[12] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f);
v[13] = Vertex( 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f);
v[14] = Vertex( 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f);
v[15] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f);

// fill in the left face vertex data
v[16] = Vertex(-1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
v[17] = Vertex(-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
v[18] = Vertex(-1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
v[19] = Vertex(-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f);

// fill in the right face vertex data
v[20] = Vertex( 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
v[21] = Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
v[22] = Vertex( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
v[23] = Vertex( 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f);

_vb->Unlock();

_device->CreateIndexBuffer(
36 * sizeof(WORD),
D3DUSAGE_WRITEONLY,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,
&_ib,
0);

WORD* i = 0;
_ib->Lock(0,0,(void**)&i,0);

// fill in the front face index data
i[0] = 0; i[1] = 1; i[2] = 2;
i[3] = 0; i[4] = 2; i[5] = 3;

// fill in the back face index data
i[6] = 4; i[7] = 5; i[8] = 6;
i[9] = 4; i[10] = 6; i[11] = 7;

// fill in the top face index data
i[12] = 8; i[13] = 9; i[14] = 10;
i[15] = 8; i[16] = 10; i[17] = 11;

// fill in the bottom face index data
i[18] = 12; i[19] = 13; i[20] = 14;
i[21] = 12; i[22] = 14; i[23] = 15;

// fill in the left face index data
i[24] = 16; i[25] = 17; i[26] = 18;
i[27] = 16; i[28] = 18; i[29] = 19;

// fill in the right face index data
i[30] = 20; i[31] = 21; i[32] = 22;
i[33] = 20; i[34] = 22; i[35] = 23;

_ib->Unlock();
}

Cube::~Cube()
{
if(_vb){_vb->Release();_ib = 0;}
if(_ib){_ib->Release();_ib = 0;}
};

bool Cube::draw(D3DXMATRIX* world, D3DMATERIAL9* mtrl, IDirect3DTexture9* tex)
{
if(world)
_device->SetTransform(D3DTS_WORLD, world);
if(mtrl)
_device->SetMaterial(mtrl);
if(tex)
_device->SetTexture(0,tex);

_device->SetStreamSource(0,_vb,0,sizeof(Vertex));
_device->SetIndices(_ib);
_device->SetFVF(FVF_VERTEX);
_device->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST,
0,
0,
24,
0,
12);

return true;
}
[/cc]

vertex.h
[cc lang=”c++” nowrap = false”]
struct Vertex
{
Vertex(){}
Vertex(
float x, float y, float z,
float nx, float ny, float nz,
float u, float v)
{
_x = x; _y = y; _z = z;
_nx = nx; _ny = ny; _nz = nz;
_u = u; _v = v;
}
float _x,_y,_z;
float _nx,_ny,_nz;
float _u,_v;
};

#define FVF_VERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)
[/cc]

texCube.cpp
[cc lang=”c++” nowrap = false”]
#include “d3dUtility.h”
#include “cube.h”
#include “vertex.h”

IDirect3DDevice9* Device = 0;

const int Width = 640;
const int Height = 480;

Cube* Box = 0;
IDirect3DTexture9* Tex = 0;

bool Setup()
{
Box = new Cube(Device);

D3DLIGHT9 light;
::ZeroMemory(&light, sizeof(light));
light.Type = D3DLIGHT_DIRECTIONAL;
light.Ambient = D3DXCOLOR(0.8f,0.8f,0.8f,1.0f);
light.Diffuse = D3DXCOLOR(1.0f,1.0f,1.0f,1.0f);
light.Specular = D3DXCOLOR(0.2f,0.2f,0.2f,1.0f);
light.Direction = D3DXVECTOR3(1.0f,-1.0f,0.0f);
Device->SetLight(0,&light);
Device->LightEnable(0,true);

Device->SetRenderState(D3DRS_NORMALIZENORMALS,true);
Device->SetRenderState(D3DRS_SPECULARENABLE,true);

//创建材质
D3DXCreateTextureFromFile(
Device,
“biohazerd.jpg”,
&Tex);

//创建材质过滤
Device->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
Device->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
Device->SetSamplerState(0,D3DSAMP_MIPFILTER,D3DTEXF_LINEAR);

D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(
&proj,
D3DX_PI * 0.5f,
(float)Width / (float)Height,
1.0f,
1000.0f);
Device->SetTransform(D3DTS_PROJECTION,&proj);

return true;
}

void Cleanup()
{
d3d::Delete(Box);
d3d::Release(Tex);
}

bool Display(float timeDelta)
{
if(Device)
{
static float angle = (3.0f * D3DX_PI) / 2.0f;
static float height = 2.0f;

D3DXMATRIX roy;
static float y = 0.0f;

if(y >= 6.28f)
y = 0.0f;

bool keyDown = false;

if(::GetAsyncKeyState(VK_LEFT) & 0x8000f)
{
angle -= 0.5f * timeDelta;
keyDown = true;
}

if(::GetAsyncKeyState(VK_RIGHT) & 0x8000f)
{
angle += 0.5f * timeDelta;
keyDown = true;
}

if(::GetAsyncKeyState(VK_UP) & 0x8000f)
{
height += 5.0f * timeDelta;
keyDown = true;
}

if(::GetAsyncKeyState(VK_DOWN) & 0x8000f)
{
height -= 5.0f * timeDelta;
keyDown = true;
}

if(!keyDown) {
y += timeDelta;
D3DXMatrixRotationY(&roy, y);
Device->SetTransform(D3DTS_WORLD, &roy);
}

D3DXVECTOR3 position(cosf(angle) * 3.0f, height, sinf(angle) * 3.0f);
D3DXVECTOR3 target(0.0f,0.0f,0.0f);
D3DXVECTOR3 up(0.0f,1.0f,0.0f);
D3DXMATRIX V;
D3DXMatrixLookAtLH(&V, &position, &target, &up);

Device->SetTransform(D3DTS_VIEW, &V);

Device->Clear(0,0,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff,1.0f,0);
Device->BeginScene();

Device->SetMaterial(&d3d::WHITE_MTRL);
Device->SetTexture(0,Tex);

Box->draw(0,0,0);
Device->EndScene();
Device->Present(0,0,0,0);
}

return true;
}

LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch( msg )
{
case WM_DESTROY:
::PostQuitMessage(0);
break;

case WM_KEYDOWN:
if( wParam == VK_ESCAPE )
::DestroyWindow(hwnd);
break;
}
return ::DefWindowProc(hwnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hinstance,
HINSTANCE prevInstance,
PSTR cmdLine,
int showCmd)
{
if(!d3d::InitD3D(hinstance,
Width, Height, true, D3DDEVTYPE_HAL, &Device))
{
::MessageBox(0, “InitD3D() – FAILED”, 0, 0);
return 0;
}

if(!Setup())
{
::MessageBox(0, “Setup() – FAILED”, 0, 0);
return 0;
}

d3d::EnterMsgLoop( Display );

Cleanup();

Device->Release();

return 0;
}
[/cc]

发表评论

电子邮件地址不会被公开。 必填项已用*标注