Theme NexT works best with JavaScript enabled
0%

创建三维文本网格模型

调用函数实现立体文本效果

思路简述

三维文本网格模型的绘制流程和茶壶模型绘制基本相同,都是调用系统自带的绘制函数,但由于绘制函数的参数不同,因此在InitGeometry部分作出一定修改即可。

为指定的文本创建网格模型

用户自定义函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
HRESULT CreateTextMesh( WCHAR* pText )
{
HRESULT hr;

//创建设备描述表
HDC hdc = CreateCompatibleDC( NULL );
if( hdc == NULL )
return E_OUTOFMEMORY;

//创建字体
HFONT hFont = CreateFont(0, 0, 0, 0, FW_BOLD , false, false, false,
DEFAULT_CHARSET,OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial");

//将字体选进设备描述表
SelectObject(hdc, hFont);

//创建三维文本网格模型
V_RETURN( D3DXCreateText( g_pd3dDevice, hdc, pText, 0.001f, 0.4f, &g_pTextMesh, NULL, NULL ));

//释放字体和设备描述表
DeleteObject( hFont );
DeleteDC( hdc );
}

CreateFont

系统字体创建函数

1
2
3
HFONT hFont = CreateFont(0, 0, 0, 0, FW_BOLD , false, false, false, 
DEFAULT_CHARSET,OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial");

函数原型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
HRESULT D3DXCreateFont(
_In_  LPDIRECT3DDEVICE9 pDevice, \\ 指向IDirect3DDevice9接口的指针,该接口与字体对象关联
_In_  INT               Height, \\ 字符的高度,以逻辑单位表示
_In_  UINT              Width, \\ 字符的宽度,以逻辑单位表示
_In_  UINT              Weight, \\ 字体重量。一个例子是粗体。
_In_  UINT              MipLevels,\\ mipmap级别数
_In_  BOOL              Italic, \\ 斜体字体为true,否则为false
_In_  DWORD             CharSet, \\ 字体的字符集
_In_  DWORD             OutputPrecision, \\ 指定Windows应如何尝试将所需的字体大小和特征与实际字体进行匹配
_In_  DWORD             Quality, \\指定Windows如何将所需字体与实际字体匹配
_In_  DWORD             PitchAndFamily, \\
_In_  LPCTSTR           pFacename, \\ 包含字体名称的字符串
_Out_ LPD3DXFONT        *ppFont \\ 返回一个指向ID3DXFont接口的指针,该接口代表创建的字体对象
);

D3DXCreateText

系统三维文本绘制函数

1
D3DXCreateText( g_pd3dDevice, hdc, pText, 0.001f, 0.4f, &g_pTextMesh, NULL, NULL )

函数原型

1
2
3
4
5
6
7
8
9
10
HRESULT D3DXCreateText(
_In_  LPDIRECT3DDEVICE9   pDevice, \\ 指向创建网格的设备的指针
_In_  HDC                 hDC, \\ 设备上下文,包含用于输出的字体
_In_  LPCTSTR             pText, \\ 指向指定要生成的文本的字符串的指针
_In_  FLOAT               Deviation, \\ 与TrueType字体轮廓的最大弦偏差
_In_  FLOAT               Extrusion, \\ 沿负z方向挤出文本的量
_Out_ LPD3DXMESH          *ppMesh, \\ 指向返回的网格的指针
_Out_ LPD3DXBUFFER        *ppAdjacency,\\ 指向包含邻接信息的缓冲区的指针
_Out_ LPGLYPHMETRICSFLOAT pGlyphMetrics\\ 指向包含字形指标数据的GLYPHMETRICSFLOAT结构数组的指针
);

返回值:

  • 如果函数成功,则返回值为D3D_OK
  • 如果函数失败,则返回值可以是以下之一:D3DERR_INVALIDCALL,D3DXERR_INVALIDDATA,E_OUTOFMEMORY

文件源码

Main.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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
//=============================================================================
// Desc: 三维文本绘制示例程序
//=============================================================================
#include <d3dx9.h>
#include <tchar.h>
#include <d3dx9core.h>
#include "UtilMacro.h";


//-----------------------------------------------------------------------------
// Desc: 全局变量
//-----------------------------------------------------------------------------
LPDIRECT3D9 g_pD3D = NULL; //Direct3D对象
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; //Direct3D设备对象
LPD3DXFONT g_pFont = 0; //字体对象
LPD3DXMESH g_pTextMesh = NULL; //三维字体网格模型

RECT g_ClientRect; //窗口客户区
float g_FPS = 0; //帧速率
WCHAR g_strFPS[20]; //包含帧速率的字符数组


//-----------------------------------------------------------------------------
// Desc: 顶点结构和顶点格式
//-----------------------------------------------------------------------------
struct CUSTOMVERTEX
{
D3DXVECTOR3 position;
DWORD color;
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)


//-----------------------------------------------------------------------------
// Desc: 设置世界矩阵
//-----------------------------------------------------------------------------
void SetWorldMatrix()
{
//创建并设置世界矩阵
D3DXMATRIXA16 matWorld, matTrans, matRotate;
float time = timeGetTime() * 0.001f;
float fAngle = time * D3DX_PI / 2;
//fAngle = -D3DX_PI/4;

D3DXMatrixTranslation(&matTrans,-3.0f,0.0f,0.0f); //平移
D3DXMatrixRotationY( &matRotate, fAngle ); //旋转
matWorld = matTrans * matRotate; //先平移, 后旋转
g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
}


//-----------------------------------------------------------------------------
// Desc: 设置观察矩阵和投影矩阵
//-----------------------------------------------------------------------------
void SetViewandProjMatrices()
{
//建立并设置观察矩阵
D3DXVECTOR3 vEyePt( 0.0f, 0.0f,-8.0f );
D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
D3DXMATRIXA16 matView;
D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

//建立并设置投影矩阵
D3DXMATRIXA16 matProj;
float aspect = (float)(g_ClientRect.right - g_ClientRect.left)/(g_ClientRect.bottom - g_ClientRect.top);
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, aspect, 1.0f, 100.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}


//-----------------------------------------------------------------------------
// Desc: 设置灯光
//-----------------------------------------------------------------------------
void SetLights()
{
//方向光
D3DXVECTOR3 vecDir;
D3DLIGHT9 light;
ZeroMemory( &light, sizeof(D3DLIGHT9) );
light.Type = D3DLIGHT_DIRECTIONAL;
light.Diffuse.r = 1.0f;
light.Diffuse.g = 1.0f;
light.Diffuse.b = 1.0f;
vecDir = D3DXVECTOR3(-1, -1, 1);
D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecDir );
light.Range = 1000.0f;
g_pd3dDevice->SetLight( 0, &light );
g_pd3dDevice->LightEnable( 0, TRUE );
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, true );

//全局环境光
g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xff505050);
}

//-----------------------------------------------------------------------------
// Desc: 设置灯光
//-----------------------------------------------------------------------------
void SetMaterial()
{
//设置材质
D3DMATERIAL9 mtrl;
ZeroMemory( &mtrl, sizeof(D3DMATERIAL9) );
mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;
mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;
mtrl.Diffuse.b = mtrl.Ambient.b = 0.0f;
mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;
g_pd3dDevice->SetMaterial( &mtrl );
}


//-----------------------------------------------------------------------------
// Desc: 为指定的文本创建网格模型
//-----------------------------------------------------------------------------
HRESULT CreateTextMesh( WCHAR* pText )
{
HRESULT hr;

//创建设备描述表
HDC hdc = CreateCompatibleDC( NULL );
if( hdc == NULL )
return E_OUTOFMEMORY;

//创建字体
HFONT hFont = CreateFont(0, 0, 0, 0, FW_BOLD , false, false, false,
DEFAULT_CHARSET,OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial");

//将字体选进设备描述表
SelectObject(hdc, hFont);

//创建三维文本网格模型
V_RETURN( D3DXCreateText( g_pd3dDevice, hdc, pText, 0.001f, 0.4f, &g_pTextMesh, NULL, NULL ));

//释放字体和设备描述表
DeleteObject( hFont );
DeleteDC( hdc );
}


//-----------------------------------------------------------------------------
// Desc: 初始化Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
HRESULT hr;

//创建Direct3D对象, 该对象用来创建Direct3D设备对象
g_pD3D = Direct3DCreate9( D3D_SDK_VERSION );
if( g_pD3D == NULL)
return E_FAIL;

//检查设备性能
D3DCAPS9 caps;
g_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);

//检查设备是否支持硬件顶点处理
int vp=0;
if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
{
vp=D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
else
{
vp=D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}

//设置D3DPRESENT_PARAMETERS结构
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

//创建Direct3D设备对象
V_RETURN( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, vp, &d3dpp, &g_pd3dDevice ));

//创建字体对象
V_RETURN( D3DXCreateFont(g_pd3dDevice,0,0,0,0,0,0,0,0,0, L"Arial", &g_pFont ));

//获取窗口客户区
GetClientRect(hWnd, &g_ClientRect);

//设置观察和投影矩阵
SetViewandProjMatrices( );

return S_OK;
}


//-----------------------------------------------------------------------------
// Desc: 创建文本网格模型
//-----------------------------------------------------------------------------
HRESULT InitGeometry()
{
HRESULT hr;
V_RETURN (CreateTextMesh(L"Hello Direct3D!" ));
return S_OK;
}


//-----------------------------------------------------------------------------
// Desc: 计算帧速率
//-----------------------------------------------------------------------------
float GetFPS()
{
static float fps = 0;
static int frameCount = 0;
static float currentTime =0.0f;
static float lastTime = 0.0f;

frameCount++;
currentTime = timeGetTime()*0.001f;

if(currentTime - lastTime > 1.0f)
{
fps = (float)frameCount /(currentTime - lastTime);
lastTime = currentTime;
frameCount = 0;
}

return fps;
}


//-----------------------------------------------------------------------------
// Desc: 渲染图形
//-----------------------------------------------------------------------------
void Render()
{
//清空后台缓存
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(45, 50, 170), 1.0f, 0 );

//开始在后台缓存绘制图形
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
//设置灯光和材质
SetLights();
SetMaterial();

//设置世界矩阵
SetWorldMatrix();

//绘制三维文本
g_pTextMesh->DrawSubset(0);

//在窗口左上角绘制文本
int charCount = swprintf_s(g_strFPS, 20, L"FPS: %0.2f", GetFPS() );
g_pFont->DrawText(NULL, g_strFPS, charCount, &g_ClientRect, DT_TOP | DT_LEFT, 0xffffffff);

//结束在后台缓存渲染图形
g_pd3dDevice->EndScene();
}

//将在后台缓存绘制的图形提交到前台缓存显示
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}


//-----------------------------------------------------------------------------
// Desc: 释放创建的对象
//-----------------------------------------------------------------------------
void Cleanup()
{
SAFE_RELEASE(g_pTextMesh);
SAFE_RELEASE(g_pFont);
SAFE_RELEASE(g_pd3dDevice);
SAFE_RELEASE(g_pD3D);
}


//-----------------------------------------------------------------------------
// Desc: 消息处理
//-----------------------------------------------------------------------------
LRESULT WINAPI WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_KEYDOWN:
if( wParam == VK_ESCAPE )
PostQuitMessage( 0 );
break;

case WM_DESTROY:
PostQuitMessage( 0 );
break;
}

return DefWindowProc( hWnd, msg, wParam, lParam );
}


//-----------------------------------------------------------------------------
// Desc: 程序入口
//-----------------------------------------------------------------------------
int _stdcall _tWinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,
PTSTR szCmdLine, int iCmdShow )
{
//定义窗口类
WNDCLASSEX wndClassEx;
wndClassEx.cbSize = sizeof(WNDCLASSEX);
wndClassEx.style = CS_CLASSDC;
wndClassEx.lpfnWndProc = WndProc;
wndClassEx.cbClsExtra = 0;
wndClassEx.cbWndExtra = 0;
wndClassEx.hInstance = hInstance;
wndClassEx.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndClassEx.hCursor = LoadCursor (NULL, IDC_ARROW);
wndClassEx.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wndClassEx.lpszMenuName = NULL;
wndClassEx.lpszClassName = L"ClassName" ;
wndClassEx.hIconSm = NULL;

//注册窗口类
if(!RegisterClassEx (&wndClassEx))
{
MessageBox(NULL, L"注册窗口类失败!", L"Text3D", 0);
return 0;
}

//创建窗口
HWND hWnd = NULL;
hWnd = CreateWindowEx( NULL, //窗口扩展风格
L"ClassName", //窗口类名称
L"Text3D", //窗口标题
WS_OVERLAPPEDWINDOW, //窗口风格
CW_USEDEFAULT, //窗口初始X位置
CW_USEDEFAULT, //窗口初始Y位置
600, //窗口初始宽度
480, //窗口初始高度
NULL, //父窗口句柄
NULL, //窗口菜单句柄
hInstance, //程序实例句柄
NULL ); // 创建参数

if(hWnd == NULL)
{
MessageBox(NULL, L"创建窗口失败!", L"Text3D", 0);
return 0;
}


//初始化Direct3D
if( SUCCEEDED( InitD3D( hWnd ) ) )
{
//创建并填充顶点缓存
if( SUCCEEDED( InitGeometry() ) )
{
//显示窗口
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );

//进入消息循环
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(); //渲染图形
}
}
}
}

//释放创建的相关对象
Cleanup();

return 0;
}

UtilMacro.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//=============================================================================
// Desc: 辅助宏定义
//=============================================================================

#pragma once

#ifndef V
#define V(x) { hr = x; }
#endif

#ifndef V_RETURN
#define V_RETURN(x) { hr = x; if( FAILED(hr) ) { return hr; } }
#endif

#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
#endif
#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
#endif
#ifndef SAFE_RELEASE
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
#endif