欢迎来到EasyLiu的博客!
到目前为止我们仅仅创建了一些单个的三角形。我们知道3D模型是由很多三角形连接起来形成一个几何体的。在这节课中,我们讲一下怎样利用三角形来建立一下一些简单的集合图形,以及怎样移动、旋转和缩放他们。
绘制一个四边形
一个四边形可以看做是由两个三角形组成,如下所示:
代码实现也比较简单:
HRESULT InitQuad()
{
// Initialize three vertices for rendering a triangle
CUSTOMVERTEX vertices[] =
{
{ -3.0f, 3.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), }, // x, y, z, color
{ 3.0f, 3.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 255), },
{ -3.0f, -3.0f, 0.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, -3.0f, 0.0f, D3DCOLOR_XRGB(0, 0, 255), },
};
if (FAILED(g_pd3dDevice->CreateVertexBuffer(
4 * sizeof(CUSTOMVERTEX),
0,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,
&g_pQuadVb,
NULL)))
{
return E_FAIL;
}
// Now we fill the vertex buffer. To do this, we need to Lock() the VB to
// gain access to the vertices. This mechanism is required becuase vertex
// buffers may be in device memory.
VOID* pVertices;
if (FAILED(g_pQuadVb->Lock(0, sizeof(vertices), (void**)&pVertices, 0)))
return E_FAIL;
memcpy(pVertices, vertices, sizeof(vertices));
g_pQuadVb->Unlock();
return S_OK;
}
然后怎样显示呢?
代码如下:这里绘制图元的时候使用的是D3DPT_TRIANGLESTRIP(线段条带)而不是 D3DPT_TRIANGLELIST(三角形列表),至于图元类型下节再详细讲解!
g_pd3dDevice->SetStreamSource(0, g_pQuadVb, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
绘制一个立方体
其实我们没有必要为每一个四边形创建四个顶点,当我们绘制一个立方体的时候,如果还按顶点索引的方式,将需要24个顶点,但是实际上立方体只有8个顶点。如果我们只需要创建8个顶点就会很简单,然后用这些顶点来组成6个四边形。
我们可以使用索引缓存来解决这个问题。在DirectX中,一个索引是一个存储顶点序号的int型。它们是以一定的顺序
的表示出来,所以第一个顶点在缓冲区中顶点号0,第二个顶点是顶点号2,以此类推。
索引缓存是一个存储顶点渲染顺序的位于内存中的缓冲区,不同于存储一个长包含坐标的列表,它是存储一个长的包含索引的列表。
举个例子,如下所示的立方体:
这个立方体有8个角,每个角有一个坐标,但是在这里这个立方体以索引号的形式标注了出来。
我们还是用8个不同的顶点建立一个顶点缓存,每个顶点代表立方体的一个角,包括坐标和颜色,代码如下所示:
CUSTOMVERTEX vertices[] =
{
{ -3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), }, // vertex 0
{ 3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 0), }, // vertex 1
{ -3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(255, 0, 0), }, // 2
{ 3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 255), }, // 3
{ -3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(0, 0, 255), }, // ...
{ 3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ -3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 255), },
};
但是以上代码没有创建任何三角形或者四边形,只是角而已。为了建立三角形,我们指定三个索引为一行。如果我们使用“0,1,2”以及"2,1,3“,我们将得到两个三角形,如下图所示,注意我们可以为每个面重复相同的操作,为每个面生成一个四边形。
在我们说我们想要用哪些索引之前,我们需要创建一个索引缓存。需要调用函数CreateIndexBuffer来创建:
HRESULT CreateIndexBuffer(
UINT Length,
DWORD Usage,
D3DFORMAT Format,
D3DPOOL Pool,
LPDIRECT3DINDEXBUFFER9 ppIndexBuffer,
HANDLE* pSharedHandle);
这个函数和CreateVertexBuffer函数类似,只是第三个不一样,在这里指定顶点格式比如D3DFMT_INDEX16。
创建索引缓存的代码如下:
// create the indices using an int array
short indices[] =
{
0, 1, 2, // side 1
2, 1, 3,
4, 0, 6, // side 2
6, 0, 2,
7, 5, 6, // side 3
6, 5, 4,
3, 1, 7, // side 4
7, 1, 5,
4, 5, 0, // side 5
0, 5, 1,
3, 7, 2, // side 6
2, 7, 6,
};
// create an index buffer interface called i_buffer
g_pd3dDevice->CreateIndexBuffer(36 * sizeof(short), // 3 per triangle, 12 triangles
0,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,
&g_pCubeIndex,
NULL);
VOID* pVoid;
// lock i_buffer and load the indices into it
g_pCubeIndex->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, indices, sizeof(indices));
g_pCubeIndex->Unlock();
把顶点缓存和索引缓存合起来就是如下代码:
CUSTOMVERTEX vertices[] =
{
{ -3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), }, // vertex 0
{ 3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 0), }, // vertex 1
{ -3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(255, 0, 0), }, // 2
{ 3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 255), }, // 3
{ -3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(0, 0, 255), }, // ...
{ 3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ -3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 255), },
};
if (FAILED(g_pd3dDevice->CreateVertexBuffer(
8 * sizeof(CUSTOMVERTEX),
0,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,
&g_pCubeVb,
NULL)))
{
return E_FAIL;
}
VOID* pVertices;
if (FAILED(g_pCubeVb->Lock(0, sizeof(vertices), (void**)&pVertices, 0)))
return E_FAIL;
memcpy(pVertices, vertices, sizeof(vertices));
g_pCubeVb->Unlock();
// create the indices using an int array
short indices[] =
{
0, 1, 2, // side 1
2, 1, 3,
4, 0, 6, // side 2
6, 0, 2,
7, 5, 6, // side 3
6, 5, 4,
3, 1, 7, // side 4
7, 1, 5,
4, 5, 0, // side 5
0, 5, 1,
3, 7, 2, // side 6
2, 7, 6,
};
// create an index buffer interface called i_buffer
g_pd3dDevice->CreateIndexBuffer(36 * sizeof(short), // 3 per triangle, 12 triangles
0,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,
&g_pCubeIndex,
NULL);
VOID* pVoid;
// lock i_buffer and load the indices into it
g_pCubeIndex->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, indices, sizeof(indices));
g_pCubeIndex->Unlock();
那么怎么显示呢?代码如下:
// select the vertex and index buffers to use
g_pd3dDevice->SetStreamSource(0, g_pCubeVb, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetIndices(g_pCubeIndex);
// draw the cube
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);
使用到了两个新函数:SetIndices:为Direct3D设备设置索引缓存,DrawIndexedPrimitive:使用顶点缓存绘制图形,具体各个参数的含义不细讲。
绘制一个金字塔
我们还可以绘制一些别的形状,比如绘制一个金字塔,如下所示:
代码如下:
初始化代码:
HRESULT InitPyramid(){
// create the vertices using the CUSTOMVERTEX
CUSTOMVERTEX vertices[] =
{
// base
{ -3.0f, 0.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 3.0f, 0.0f, 3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -3.0f, 0.0f, -3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, 0.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 255), },
// top
{ 0.0f, 7.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
};
// create a vertex buffer interface called v_buffer
if (FAILED(g_pd3dDevice->CreateVertexBuffer(5 * sizeof(CUSTOMVERTEX),
0,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,
&g_pPyramidVb,
NULL)))
{
return E_FAIL;
}
VOID* pVertices;
if (FAILED(g_pPyramidVb->Lock(0, sizeof(vertices), (void**)&pVertices, 0)))
return E_FAIL;
memcpy(pVertices, vertices, sizeof(vertices));
g_pPyramidVb->Unlock();
// create the indices using an int array
short indices[] =
{
0, 2, 1, // base
1, 2, 3,
0, 1, 4, // sides
1, 3, 4,
3, 2, 4,
2, 0, 4,
};
// create a index buffer interface called i_buffer
if (FAILED(g_pd3dDevice->CreateIndexBuffer(18 * sizeof(short),
0,
D3DFMT_INDEX16,
D3DPOOL_DEFAULT,
&g_pPyramidIndex,
NULL)))
{
return E_FAIL;
}
VOID* pVoid;
// lock i_buffer and load the indices into it
if (FAILED(g_pPyramidIndex->Lock(0, 0, (void**)&pVoid, 0)))
{
return E_FAIL;
}
memcpy(pVoid, indices, sizeof(indices));
g_pPyramidIndex->Unlock();
return S_OK;
}
显示代码:
//draw the pyramid
g_pd3dDevice->SetTransform(D3DTS_WORLD, &(matRotateY*matTranslateC));
// select the vertex and index buffers to use
g_pd3dDevice->SetStreamSource(0, g_pPyramidVb, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetIndices(g_pPyramidIndex);
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 5, 0, 6);
HRESULT InitHyperCraft(){
// create the vertices using the CUSTOMVERTEX
struct CUSTOMVERTEX vertices[] =
{
// fuselage
{ 3.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 0.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 0.0f, 0.0f, 10.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ -3.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 255), },
// left gun
{ 3.2f, -1.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.2f, -1.0f, 11.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 2.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0), },
// right gun
{ -3.2f, -1.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -3.2f, -1.0f, 11.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -2.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0), },
};
// create a vertex buffer interface called v_buffer
if (FAILED(g_pd3dDevice->CreateVertexBuffer(10 * sizeof(CUSTOMVERTEX),
0,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,
&g_pHyperCraftVb,
NULL)))
{
return E_FAIL;
}
VOID* pVertices;
if (FAILED(g_pHyperCraftVb->Lock(0, sizeof(vertices), (void**)&pVertices, 0)))
return E_FAIL;
memcpy(pVertices, vertices, sizeof(vertices));
g_pHyperCraftVb->Unlock();
// create the indices using an int array
short indices[] =
{
0, 1, 2, // fuselage
2, 1, 3,
3, 1, 0,
0, 2, 3,
4, 5, 6, // wings
7, 8, 9,
};
// create a index buffer interface called i_buffer
g_pd3dDevice->CreateIndexBuffer(18 * sizeof(short),
0,
D3DFMT_INDEX16,
D3DPOOL_DEFAULT,
&g_pHyperCraftIndex,
NULL);
VOID* pVoid;
// lock i_buffer and load the indices into it
if (FAILED(g_pHyperCraftIndex->Lock(0, 0, (void**)&pVoid, 0)))
{
return E_FAIL;
}
memcpy(pVoid, indices, sizeof(indices));
g_pHyperCraftIndex->Unlock();
return S_OK;
}
显示代码:
//draw the hypercraft
g_pd3dDevice->SetTransform(D3DTS_WORLD, &(matRotateY*matTranslateD));
// select the vertex and index buffers to use
g_pd3dDevice->SetStreamSource(0, g_pHyperCraftVb, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetIndices(g_pHyperCraftIndex);
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 10, 0, 6);
通过把以上形状放在一个窗口中显示,同时使形状都绕自身的y轴旋转,达到的效果如下所示:
main.c源代码如下:
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib,"winmm.lib")
#include <d3d9.h>
#include <d3dx9.h>
#include "Windows.h"
#include <mmsystem.h>
#pragma warning( disable : 4996 ) // disable deprecated warning
#include <strsafe.h>
#pragma warning( default : 4996 )
// define the screen resolution
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 800;
LPDIRECT3D9 g_pD3D = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Our rendering device
LPDIRECT3DVERTEXBUFFER9 g_pQuadVb = NULL; // Buffer to hold quad vertices
LPDIRECT3DVERTEXBUFFER9 g_pCubeVb = NULL; // Buffer to hold cube vertices
LPDIRECT3DINDEXBUFFER9 g_pCubeIndex = NULL;//buffer to hold cube index
LPDIRECT3DVERTEXBUFFER9 g_pPyramidVb = NULL;//buffer to hold pyramid vertices
LPDIRECT3DINDEXBUFFER9 g_pPyramidIndex = NULL;//buffer to hold pyramid index
LPDIRECT3DVERTEXBUFFER9 g_pHyperCraftVb = NULL;
LPDIRECT3DINDEXBUFFER9 g_pHyperCraftIndex = NULL;
// A structure for our custom vertex type
struct CUSTOMVERTEX
{
FLOAT x, y, z;
DWORD color; // The vertex color
};
// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
HRESULT InitD3D(HWND hWnd)
{
// Create the D3D object.
if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
return E_FAIL;
//fill D3DCAPS9 struct with the capabilities of the primary display adapter
D3DCAPS9 caps;
g_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
//can we use hardware vertex processing?
DWORD vp = 0;
if (caps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT)
{
//yes,support hardware vertex processing
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
else
{
//no,
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
// Set up the structure used to create the D3DDevice
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;
d3dpp.EnableAutoDepthStencil = TRUE; // automatically run the z-buffer for us
d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // 16-bit pixel format for the z-buffer
// Create the D3DDevice
if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
vp,
&d3dpp, &g_pd3dDevice)))
{
return E_FAIL;
}
// Device state would normally be set here
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); // turn off the 3D lighting
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); // both sides of the triangles
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE); // turn on the z-buffer
return S_OK;
}
HRESULT InitQuad()
{
// Initialize three vertices for rendering a triangle
CUSTOMVERTEX vertices[] =
{
{ -3.0f, 3.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), }, // x, y, z, color
{ 3.0f, 3.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 255), },
{ -3.0f, -3.0f, 0.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, -3.0f, 0.0f, D3DCOLOR_XRGB(0, 0, 255), },
};
if (FAILED(g_pd3dDevice->CreateVertexBuffer(
4 * sizeof(CUSTOMVERTEX),
0,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,
&g_pQuadVb,
NULL)))
{
return E_FAIL;
}
// Now we fill the vertex buffer. To do this, we need to Lock() the VB to
// gain access to the vertices. This mechanism is required becuase vertex
// buffers may be in device memory.
VOID* pVertices;
if (FAILED(g_pQuadVb->Lock(0, sizeof(vertices), (void**)&pVertices, 0)))
return E_FAIL;
memcpy(pVertices, vertices, sizeof(vertices));
g_pQuadVb->Unlock();
return S_OK;
}
HRESULT InitCube()
{
CUSTOMVERTEX vertices[] =
{
{ -3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), }, // vertex 0
{ 3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 0), }, // vertex 1
{ -3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(255, 0, 0), }, // 2
{ 3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 255), }, // 3
{ -3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(0, 0, 255), }, // ...
{ 3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ -3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 255), },
};
if (FAILED(g_pd3dDevice->CreateVertexBuffer(
8 * sizeof(CUSTOMVERTEX),
0,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,
&g_pCubeVb,
NULL)))
{
return E_FAIL;
}
VOID* pVertices;
if (FAILED(g_pCubeVb->Lock(0, sizeof(vertices), (void**)&pVertices, 0)))
return E_FAIL;
memcpy(pVertices, vertices, sizeof(vertices));
g_pCubeVb->Unlock();
// create the indices using an int array
short indices[] =
{
0, 1, 2, // side 1
2, 1, 3,
4, 0, 6, // side 2
6, 0, 2,
7, 5, 6, // side 3
6, 5, 4,
3, 1, 7, // side 4
7, 1, 5,
4, 5, 0, // side 5
0, 5, 1,
3, 7, 2, // side 6
2, 7, 6,
};
// create an index buffer interface called i_buffer
if (FAILED(g_pd3dDevice->CreateIndexBuffer(36 * sizeof(short), // 3 per triangle, 12 triangles
0,
D3DFMT_INDEX16,
D3DPOOL_DEFAULT,
&g_pCubeIndex,
NULL)))
{
return E_FAIL;
}
VOID* pVoid;
// lock i_buffer and load the indices into it
if (FAILED(g_pCubeIndex->Lock(0, 0, (void**)&pVoid, 0)))
{
return E_FAIL;
}
memcpy(pVoid, indices, sizeof(indices));
g_pCubeIndex->Unlock();
return S_OK;
}
HRESULT InitPyramid(){
// create the vertices using the CUSTOMVERTEX
CUSTOMVERTEX vertices[] =
{
// base
{ -3.0f, 0.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 3.0f, 0.0f, 3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -3.0f, 0.0f, -3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, 0.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 255), },
// top
{ 0.0f, 7.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
};
// create a vertex buffer interface called v_buffer
if (FAILED(g_pd3dDevice->CreateVertexBuffer(5 * sizeof(CUSTOMVERTEX),
0,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,
&g_pPyramidVb,
NULL)))
{
return E_FAIL;
}
VOID* pVertices;
if (FAILED(g_pPyramidVb->Lock(0, sizeof(vertices), (void**)&pVertices, 0)))
return E_FAIL;
memcpy(pVertices, vertices, sizeof(vertices));
g_pPyramidVb->Unlock();
// create the indices using an int array
short indices[] =
{
0, 2, 1, // base
1, 2, 3,
0, 1, 4, // sides
1, 3, 4,
3, 2, 4,
2, 0, 4,
};
// create a index buffer interface called i_buffer
if (FAILED(g_pd3dDevice->CreateIndexBuffer(18 * sizeof(short),
0,
D3DFMT_INDEX16,
D3DPOOL_DEFAULT,
&g_pPyramidIndex,
NULL)))
{
return E_FAIL;
}
VOID* pVoid;
// lock i_buffer and load the indices into it
if (FAILED(g_pPyramidIndex->Lock(0, 0, (void**)&pVoid, 0)))
{
return E_FAIL;
}
memcpy(pVoid, indices, sizeof(indices));
g_pPyramidIndex->Unlock();
return S_OK;
}
HRESULT InitHyperCraft(){
// create the vertices using the CUSTOMVERTEX
struct CUSTOMVERTEX vertices[] =
{
// fuselage
{ 3.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 0.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 0.0f, 0.0f, 10.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ -3.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 255), },
// left gun
{ 3.2f, -1.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.2f, -1.0f, 11.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 2.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0), },
// right gun
{ -3.2f, -1.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -3.2f, -1.0f, 11.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -2.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0), },
};
// create a vertex buffer interface called v_buffer
if (FAILED(g_pd3dDevice->CreateVertexBuffer(10 * sizeof(CUSTOMVERTEX),
0,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,
&g_pHyperCraftVb,
NULL)))
{
return E_FAIL;
}
VOID* pVertices;
if (FAILED(g_pHyperCraftVb->Lock(0, sizeof(vertices), (void**)&pVertices, 0)))
return E_FAIL;
memcpy(pVertices, vertices, sizeof(vertices));
g_pHyperCraftVb->Unlock();
// create the indices using an int array
short indices[] =
{
0, 1, 2, // fuselage
2, 1, 3,
3, 1, 0,
0, 2, 3,
4, 5, 6, // wings
7, 8, 9,
};
// create a index buffer interface called i_buffer
g_pd3dDevice->CreateIndexBuffer(18 * sizeof(short),
0,
D3DFMT_INDEX16,
D3DPOOL_DEFAULT,
&g_pHyperCraftIndex,
NULL);
VOID* pVoid;
// lock i_buffer and load the indices into it
if (FAILED(g_pHyperCraftIndex->Lock(0, 0, (void**)&pVoid, 0)))
{
return E_FAIL;
}
memcpy(pVoid, indices, sizeof(indices));
g_pHyperCraftIndex->Unlock();
return S_OK;
}
HRESULT InitModel(){
return InitCube()|InitQuad()|InitPyramid()|InitHyperCraft();
}
VOID SetupMatrices()
{
D3DXVECTOR3 vEyePt(0.0f, 0.0f, -30.0f);//摄像头位置,决定了场景中物体的大小
D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f);//摄像头朝向
D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);//垂直方向为y轴,这个一般是y轴
D3DXMATRIXA16 matView;
D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);
D3DXMATRIXA16 matProj;
D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4, (FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, 1.0f, 100.0f);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);
}
VOID Render()
{
// Clear the backbuffer to a blue color
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
// Begin the scene
if (SUCCEEDED(g_pd3dDevice->BeginScene()))
{
SetupMatrices();//设置转换矩阵
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX); //设置顶点格式
D3DXMATRIXA16 matTranslateA; // a matrix to store the translation for triangle A
D3DXMATRIXA16 matTranslateB; // a matrix to store the translation for triangle B
D3DXMATRIXA16 matTranslateC; // a matrix to store the translation for triangle C
D3DXMATRIXA16 matTranslateD; // a matrix to store the translation for triangle D
D3DXMATRIXA16 matRotateY; // a matrix to store the rotation for each triangle
UINT iTime = timeGetTime() % 2000;//获取当前时间
FLOAT fAngle = iTime * (2.0f * D3DX_PI) / 2000.0f;//1000ms旋转360度
D3DXMatrixRotationY(&matRotateY, fAngle); // the front side
// build MULTIPLE matrices to translate the model and one to rotate
D3DXMatrixTranslation(&matTranslateA, 7.0f, 7.0f, 0.0f);
D3DXMatrixTranslation(&matTranslateB, -7.0f, 7.0f,0.0f);
D3DXMatrixTranslation(&matTranslateC, -7.0f, -7.0f,0.0f);
D3DXMatrixTranslation(&matTranslateD, 4.0f, -4.0f, 0.0f);
//draw the quad
g_pd3dDevice->SetTransform(D3DTS_WORLD, &(matRotateY*matTranslateA));//矩阵相乘的顺序有区别,这里先旋转再平移,就改变了旋转中心!
g_pd3dDevice->SetStreamSource(0, g_pQuadVb, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
// draw the cube
g_pd3dDevice->SetTransform(D3DTS_WORLD, &(matRotateY*matTranslateB));
// select the vertex and index buffers to use
g_pd3dDevice->SetStreamSource(0, g_pCubeVb, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetIndices(g_pCubeIndex);
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);
//draw the pyramid
g_pd3dDevice->SetTransform(D3DTS_WORLD, &(matRotateY*matTranslateC));
// select the vertex and index buffers to use
g_pd3dDevice->SetStreamSource(0, g_pPyramidVb, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetIndices(g_pPyramidIndex);
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 5, 0, 6);
//draw the hypercraft
g_pd3dDevice->SetTransform(D3DTS_WORLD, &(matRotateY*matTranslateD));
// select the vertex and index buffers to use
g_pd3dDevice->SetStreamSource(0, g_pHyperCraftVb, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetIndices(g_pHyperCraftIndex);
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 10, 0, 6);
// End the scene
g_pd3dDevice->EndScene();
}
// Present the backbuffer contents to the display
g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}
//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------
VOID Cleanup()
{
if (g_pQuadVb != NULL)
g_pQuadVb->Release();
if (g_pCubeVb!=NULL)
g_pCubeVb->Release();
if (g_pd3dDevice != NULL)
g_pd3dDevice->Release();
if (g_pD3D != NULL)
g_pD3D->Release();
}
//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
Cleanup();
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
//-----------------------------------------------------------------------------
// Name: wWinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
INT WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, INT)
{
UNREFERENCED_PARAMETER(hInst);
// Register the window class
WNDCLASSEX wc =
{
sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
L"D3D Tutorial", NULL
};
RegisterClassEx(&wc);
// Create the application's window
HWND hWnd = CreateWindow(L"D3D Tutorial", L"D3D Tutorial 08: Model",
WS_OVERLAPPEDWINDOW, 100, 100, SCREEN_WIDTH, SCREEN_HEIGHT,
NULL, NULL, wc.hInstance, NULL);
// Initialize Direct3D
if (SUCCEEDED(InitD3D(hWnd)))
{
// Create the vertex buffer
if (SUCCEEDED(InitModel()))
{
// Show the window
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
// 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
Render();
}
}
}
UnregisterClass(L"D3D Tutorial", wc.hInstance);
return 0;
}