由于文字在程序里面出现的次数太多,所以d3d就将他独立出来,成为单独的一个部分。游戏中使用的太多了,也就有了研究的必要。我在学习的时候问题的确很多,现在照样一知半解,不过知识总是慢点梳理的,有所得记录下来还是很不错的。
我觉得D3D文字分为两类三种,第一类就是2D空间里面的文字,由于2D空间没有Z轴,所以文字的大小是很平均的,不会随着位置的改变大小发生变化。第二类就是3D空间里面的文字的,可以分为两种。第一种就是3D空间中的2D文字,比如说纹理图片里面的文字,显示的时候就会随着纹理的变化而变化。第二种就是3D文字模型,或者叫网格,我喜欢把Mesh翻译成模型,这样理解着好理解而已。例子就是类似高楼大厦顶上的文字图标,例如中国人民银行等等。这篇文章主要的实验对象是2D文字,属于哪一种我也说不是很清楚,因为看了半天,找了变天没有相应方面的知识,暂时先认为是2D空间中的文字吧。
程序中需要注意的地方我都用中文标了注释。需要研究程序框架的话参考DXUT框架就可以了。
#pragma once //win32 #pragma comment(lib,"comctl32.lib") //d3d #pragma comment(lib,"dxerr.lib") #pragma comment(lib,"d3dx9.lib") //dxut #pragma comment(lib,"dxut.lib") //dxut #include"DXUT.h" HRESULT CALLBACK OnDeviceCreate( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ); void CALLBACK OnDeviceDestroyed(void* pUserContext ); void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ); void SetUpMatrix(IDirect3DDevice9* pd3dDevice); void SetupLight(IDirect3DDevice9* pd3dDevice); //TODO: global variables. //1.字体和字体精灵 ID3DXFont* pFont=NULL; ID3DXSprite* pSprite=NULL; INT WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR, INT) { DXUTSetCallbackD3D9DeviceCreated( OnDeviceCreate, NULL); DXUTSetCallbackD3D9DeviceDestroyed( OnDeviceDestroyed, NULL); DXUTSetCallbackD3D9FrameRender( OnFrameRender, NULL); //0.dxut init. DXUTInit(true,true,NULL,true); //1.create window DXUTCreateWindow( L"dxut window", GetModuleHandle(NULL), NULL, NULL, CW_USEDEFAULT, CW_USEDEFAULT); //2.create device. DXUTCreateDevice(true,640,480); //3.main loop DXUTMainLoop(); //exit. return DXUTGetExitCode(); } HRESULT CALLBACK OnDeviceCreate( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ) { //TODO: create d3d device. //创建字体和字体精灵 D3DXCreateSprite(pd3dDevice,&pSprite); if(FAILED(D3DXCreateFont( pd3dDevice, 24, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, L"Arial", &pFont))) { return E_FAIL; } return S_OK; } void CALLBACK OnDeviceDestroyed( void* pUserContext ) { //TODO:destroy d3d device. if(pSprite != NULL) { pSprite->Release(); pSprite=NULL; } if(pFont != NULL) { pFont->Release(); pFont=NULL; } } void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ) { RECT rc; pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0); SetUpMatrix(pd3dDevice); SetupLight(pd3dDevice); if(SUCCEEDED(pd3dDevice->BeginScene())) { //TODO:render d3d scene. //绘制字体 pSprite->Begin(D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_TEXTURE); SetRect( &rc, 150, 200, 0, 0 ); pFont->DrawText( pSprite, L"你好,世界!", -1, &rc, DT_NOCLIP, D3DXCOLOR( 1.0f, 0.0f, 0.0f, 1.0f ) ); pSprite->End(); pd3dDevice->EndScene(); } pd3dDevice->Present(NULL,NULL,NULL,NULL); } void SetUpMatrix(IDirect3DDevice9* pd3dDevice) { D3DXMATRIXA16 viewMatrix; D3DXVECTOR3 vEye(0.0f,5.0f,-3.0f); D3DXVECTOR3 vLookAt(0.0f,0.0f,0.0f); D3DXVECTOR3 vUp(0.0f,1.0f,0.0f); D3DXMatrixLookAtLH(&viewMatrix,&vEye,&vLookAt,&vUp); pd3dDevice->SetTransform(D3DTS_VIEW,&viewMatrix); D3DXMATRIXA16 projectionMatrix; D3DXMatrixPerspectiveFovLH(&projectionMatrix,D3DX_PI/4,1.0f,1.0f,1000.0f); pd3dDevice->SetTransform(D3DTS_PROJECTION,&projectionMatrix); } void SetupLight(IDirect3DDevice9* pd3dDevice) { D3DMATERIAL9 mtrl; ZeroMemory(&mtrl,sizeof(mtrl)); mtrl.Ambient.r=mtrl.Diffuse.r=1.0f; mtrl.Ambient.g=mtrl.Diffuse.g=1.0f; mtrl.Ambient.b=mtrl.Diffuse.b=0.0f; mtrl.Ambient.a=mtrl.Diffuse.a=1.0f; pd3dDevice->SetMaterial(&mtrl); D3DLIGHT9 light; D3DXVECTOR3 dir(1.0f,0.0f,0.0f); D3DXCOLOR color(1.0f,1.0f,1.0f,0.0f); ZeroMemory(&light,sizeof(light)); light.Type=D3DLIGHT_DIRECTIONAL; light.Ambient=color*0.6f; light.Diffuse=color; light.Specular=color*0.6f; light.Direction=dir; pd3dDevice->SetLight(0,&light); pd3dDevice->LightEnable(0,TRUE); pd3dDevice->SetRenderState(D3DRS_LIGHTING,TRUE); pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS,TRUE); }
这个知识点觉得总结的地方挺少的。
1. 需要了解ID3DXFont 接口的作用,主要就是绘制文字。字符串-->字体设置-->文字显示。
2.需要了解ID3DXSprite接口的作用,这个有一些文章说直接指定NULL,我查阅MSDN上说最好指定,如果文字很多就会有优化,当然,只有一行文字指定NULL和指定其他的性能是一样的 。
3.ID3DXSprite 接口提升性能是牺牲空间为代价的,当绘制一次文字的时候,会将文字存放到空间中的纹理里面,以后如果再用就会直接从纹理取出,空间在内存还是显存现在还没有研究清楚。这样文字多的时候就会提高效率。DXUTTextHelper将ID3DXFont进行了封装到时候可以研究一下。
原文地址:http://blog.csdn.net/yonshi/article/details/38756567