DirectX Graphics
中有专门的文字显示接口ID3DXFont, 和GDI中的HFONT的创建类似, 显示文字的函数也和GDI中相同. 使用以下两个函数来创建字体,
HRESULT D3DXCreateFont(LPDIRECT3DDEVICE9 pDevice,
INT Height,
UINT Width,
UINT Weight,
UINT MipLevels,
BOOL Italic,
DWORD CharSet,
DWORD OutputPrecision,
DWORD Quality,
DWORD PitchAndFamily,
LPCTSTR pFacename,
LPD3DXFONT * ppFont);
HRESULT D3DXCreateFontIndirect(LPDIRECT3DDEVICE9 pDevice,
CONST D3DXFONT_DESC * pDesc,
LPD3DXFONT * ppFont);
实际上, ID3DXFont的创建和显示字体还是依赖于GDI的FONT的创建和显示字体的函数的, 所以ID3DXFont显示字体并非是由DirectX Graphics中的Direct3D来完成的, 如果想提高性能, 建议少量的字体显示用9.3.1的方式, 大量的字体显示可事先转换成bitmap.
9.4 Pick
的例子
9.4.1 game9 project
代码更新
game9
中只是演示了
Picking, ID3DXLINE
和文字显示.
---------------------------------------------------------------
//
全局变量, 用来保存4个测试球的半径, 原始圆心位置, 变动圆心位置
//
最后两个向量是Picking Ray的端点和方向
FLOAT g_fRad[4];
D3DXVECTOR3 g_vCenter[4];
D3DXVECTOR3 g_vTest[4];
D3DXVECTOR3 g_pos;
D3DXVECTOR3 g_n;
// game9.cpp, LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
//
加入对WM_MOUSEHOVER的消息探测, 大概1秒钟的鼠标停顿产生WM_MOUSEHOVER
//
注意使用WM_MOUSEHOVER 必须定义 #define _WIN32_WINNT 0x0500(0x400以上)
case WM_MOUSEMOVE:
{
TRACKMOUSEEVENT tme = { 0 };
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE | TME_HOVER;
tme.hwndTrack = hWnd;
tme.dwHoverTime = 0x0400;
TrackMouseEvent(&tme);
if (g_bHover)
{
g_bHover = FALSE;
g_pGame->EndPick();
}
}
break;
case WM_MOUSEHOVER :
{
if (g_bHover == FALSE)
{
g_bHover = g_pGame->Picking((DWORD)lParam);
}
}
break;
// direct9.cpp,
保存Picking Ray的端点和方向, 以为当4个模型自动旋转时有自动Pick的功能
BOOL CD9Game::Picking(DWORD dwPt)
{
LONG x = XLPARAM(dwPt);
LONG y = YLPARAM(dwPt);
FLOAT Rx = 0.0;
FLOAT Ry = 0.0;
FLOAT mx = 0.0;
FLOAT my = 0.0;
D3DVIEWPORT9 mv;
D3DXMATRIX mProj;
D3DXMATRIX mView;
m_pD3DDev->GetViewport(&mv);
m_pD3DDev->GetTransform(D3DTS_PROJECTION, &mProj);
m_pD3DDev->GetTransform(D3DTS_VIEW, &mView);
D3DXMatrixInverse(&mView, NULL, &mView);
mx = mProj(0, 0);
my = mProj(1, 1);
Rx = (FLOAT)((x * 2.0) - mv.Width) / (mv.Width * mx);
Ry = (FLOAT)(mv.Height - (y * 2.0)) / (mv.Height * my);
g_pos.x = 0.0;
g_pos.y = 0.0;
g_pos.z = 0.0;
g_n.x = Rx;
g_n.y = Ry;
g_n.z = 1.0;
D3DXVec3TransformCoord(&g_pos, &g_pos, &mView);
D3DXVec3TransformNormal(&g_n, &g_n, &mView);
D3DXVec3Normalize(&g_n, &g_n);
return WhoAmI();
}
// direct9.cpp,
确定当前选中的物体
BOOL CD9Game::WhoAmI()
{
BOOL bPick = FALSE;
D3DXVECTOR3 v;
FLOAT b, c;
INT i = 0;
for (; i < 4; i++)
{
v = g_pos - g_vTest[i];
b = FLOAT(2.0 * D3DXVec3Dot(&g_n, &v));
c = D3DXVec3Dot(&v, &v) - g_fRad[i] * g_fRad[i];
FLOAT del = b * b - 4 * c;
if (del > 0.0)
{
del = sqrtf(del);
FLOAT x1 = (FLOAT)(( del - b) / 2.0);
FLOAT x2 = (FLOAT)((-del - b) / 2.0);
if ((x1 >= 0.0) || (x2 >= 0.0))
{
bPick = TRUE;
break;
}
}
}
lstrcpyn(g_szPick, g_szObj[i], 512);
return bPick;
}
// direct9.cpp,
渲染物体, 如果自动旋转时有自动Pick
VOID CD9Game::Render()
{
if (m_dwRot >= MAXROT)
{
m_dwRot = 1L;
}
else
if (m_bRot)
{
m_dwRot++;
}
D3DXMATRIX mWorld, mWorldX, mWorldY, mWorldZ;
FLOAT rat = m_dwRot * ROT;
D3DXMatrixRotationX(&mWorldX, rat);
D3DXMatrixRotationY(&mWorldY, rat);
D3DXMatrixRotationZ(&mWorldZ, rat);
D3DXMatrixMultiply(&mWorld, &mWorldX, &mWorldY);
D3DXMatrixMultiply(&mWorld, &mWorld, &mWorldZ);
D3DXMATRIX m1, m2, m3, m4;
D3DXMatrixMultiply(&m1, &g_m1, &mWorld);
D3DXMatrixMultiply(&m2, &g_m2, &mWorld);
D3DXMatrixMultiply(&m3, &g_m3, &mWorld);
D3DXMatrixMultiply(&m4, &g_m4, &mWorld);
if (m_bRot)
{ //
如果自动旋转时有自动Pick
D3DXVec3TransformCoord(&g_vTest[0], &g_vCenter[0], &m1);
D3DXVec3TransformCoord(&g_vTest[1], &g_vCenter[1], &m2);
D3DXVec3TransformCoord(&g_vTest[2], &g_vCenter[2], &m3);
D3DXVec3TransformCoord(&g_vTest[3], &g_vCenter[3], &m4);
WhoAmI();
}
m_pD3DDev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
m_pD3DDev->BeginScene();
m_pD3DDev->SetTransform(D3DTS_WORLD, &m1);
m_pMeshShip->Render();
m_pD3DDev->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
m_pMeshSphere->DrawSubset(0);
m_pD3DDev->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
m_pD3DDev->SetTransform(D3DTS_WORLD, &m2);
m_pMesh1->DrawSubset(0);
m_pD3DDev->SetTransform(D3DTS_WORLD, &m3);
m_pMesh2->DrawSubset(0);
m_pD3DDev->SetTransform(D3DTS_WORLD, &m4);
m_pMesh3->DrawSubset(0);
//
画Y轴向上或向下的偏移, X轴向左或向右的偏移
D3DXVECTOR2* pLine = g_vy;
m_pLine->Begin();
m_pLine->Draw(pLine, 8, D3DCOLOR_XRGB(0, 128, 0));
pLine += 8;
m_pLine->Draw(pLine, 2, D3DCOLOR_XRGB(0, 255, 0));
pLine += 2;
m_pLine->Draw(pLine, 8, D3DCOLOR_XRGB(0, 128, 0));
pLine += 8;
m_pLine->Draw(pLine, 2, D3DCOLOR_XRGB(0, 255, 0));
m_pLine->End();
//
显示每秒帧数和选择物体的类型
RECT rect = { 16, 16, 512, 48 };
wsprintf(g_szFPS, _T("Current FPS : %ld"), g_dwFPS);
m_pFont->DrawText(NULL, g_szFPS, -1, &rect,
DT_NOCLIP | DT_VCENTER, D3DCOLOR_XRGB(0, 128, 0));
rect.top = 48;
rect.bottom += 32;
m_pFont->DrawText(NULL, g_szPick, -1, &rect, DT_NOCLIP, D3DCOLOR_XRGB(0, 128, 0));
m_pD3DDev->EndScene();
m_pD3DDev->Present(NULL, NULL, NULL, NULL);
}
---------------------------------------------------------------
9.4.2 game9 project
说明
为代码简单, 在鼠标停留在某地一定时间产生
WM_MOUSEHOVER
消息时, 才会有Pick功能的调用, 物体类型在左上角显示
.
自动旋转/停止用Space切换, 自动旋转时有自动Picking功能, 也就是鼠标不动, 当物体旋转到鼠标位子将自动识别物体.
识别物体有延迟现象, 作为例子就不改的太复杂了. 还有这种Picking技术是最普通的, 物体少的时候用还不错, 实际的游戏可以使用BSP, 反馈法, 直接映射法等.
第九集 小结
这一集我们学习了要进行DirectX Graphics 3D编程中的物体Pick和文字显示.