使用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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#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;
};

cube.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#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;
}

vertex.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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)

texCube.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#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<Cube*>(Box);
    d3d::Release<IDirect3DTexture9*>(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;
}

发表评论

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.