很多年前就知道DirectX是用来做游戏的,从DOS时代直接操作显存,到Windows时代只能通过驱动,并觉得DirectX的API太多,弄不清楚,感觉太麻烦,一直以来想写个游戏都是用GDI,但是GDI的效率很低,游戏做不大,只好硬着头皮去啃DirectX的SDK了,还好现在网络发达,资源很多,总是能学会不是。
在网上看了很多文章,感觉对初学者还是太难,做2D游戏也不需要太多D3D知识,大概整理了一下可能对初学者有些帮忙吧。
以下是以DirectX9的SDK进行描述的,另外渲染跟绘制差不多意思。
1、初始化一个D3D的接口IDirect3D9,方法永远是Direct3DCreate9( D3D_SDK_VERSION );
2、获取设备能力,GetDeviceCaps,Adapter取默认值D3DADAPTER_DEFAULT,DeviceType一般选硬件显卡,即D3DDEVTYPE_HAL
3、获取显示模式描述表 GetAdapterDisplayMode,在这个描述表里可以修改高宽、颜色模式、缓冲区类型等一堆信息
4、创建设备IDirect3DDevice9,用CreateDevice来创建,设备有一个就行了,设备要与窗口句柄关联
5、其它设置,什么世界矩阵,渲染状态
HRESULT InitDirect3D( HWND hWnd, BOOL bWindowed )
{
g_pD3D = Direct3DCreate9( D3D_SDK_VERSION );
D3DCAPS9 d3dCaps;
g_pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps );
D3DDISPLAYMODE d3ddm;
g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm );
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
if( bWindowed == TRUE )
{
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format;
}
else
{
d3dpp.Windowed = FALSE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
}
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Do NOT sync to vertical retrace
//d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; // Sync to vertical retrace
d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice );
D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DXToRadian( 45.0f ),
SCREEN_WIDTH / SCREEN_HEIGHT, 0.1f, 100.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
return S_OK;
}
7、创建纹理,我们这里说的是加载2D图片,可以从文件加载,从内存加载,也可以创建一个空的,自己填数据
8、渲染,先Device.Clear,再开启设备渲染事务Device.BeginScene,然后可以进行精灵渲染,也可以通过获取设备后备缓冲直接写,最后结束设备渲染事务Device.EndScene
9、精灵渲染有很东西可以设置,很麻烦有兴趣的自己学习,这里只说一个一定要在精灵渲染事务里加允许透明渲染的标志D3DXSPRITE_ALPHABLEND,事务中可以进行多项纹理绘制,所有的绘制都必须在事务中才会生效
10、精灵渲染可以渲染整个纹理,也可以只渲染其中一部分
11、精灵渲染的缩放、旋转、位置的问题,在D3D里使用3D的向量,我们搞2D编程所以Z坐标永远是1.0,缩放可以纹理的表面进行复制自动缩放,有的版本可以直接在Draw方法里旋转和缩放
终于有时间,而且对渲染这一块又有了一些了解
12、渲染到纹理,一个纹理中可以有多个表面,不过通常只用一个,可以将这个表面设为当前渲染的表面,纹理创建时有要求
a)创建可以用GDI、GDI+作图的纹理,MipLevels=1,Usage=0,Pool=D3DPOOL_MANAGED
b)创建可以作为渲染目标的纹理,MipLevels=1,Usage=1,Pool=D3DPOOL_DEFAULT,取纹理第0个表面Texture.GetSurfaceLevel(0, surface);然后设置为渲染目标Device.SetRenderTarget(0, surface);,这样一样ID3DXLine、ID3DXFont都可以绘制到当前纹理了(太基础了,没什么人讲,弄了好久才明白),渲染完后应该还原
13、纹理之间可以通过Device.StrechRect、Device.UpdateSurface来进行数据复制(拉伸和原样复制,无法使用Alpha混合的效果)
14、Alpha混合,用于给纹理叠加颜色或叠加透明度,参数很多通过Device.SetRenderState来设置,用好了可以化腐朽为神奇
//设置Alpha混合模式
Sprite._Begin(D3DXSPRITE_DONOTSAVESTATE);
Device.SetRenderState(D3DRS_ALPHABLENDENABLE, 1);
Device.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_BLENDFACTOR);
Device.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
Device.SetRenderState(D3DRS_BLENDFACTOR,
D3DCOLOR_ARGB(Round(255.0* Rate),Round(255.0* Rate),Round(255.0* Rate),Round(255.0* Rate)));
//绘制纹理
TDXManager.Sprite.Draw(texture, nil, 0, nil, $FFFFFFFF);
//设置透明度
Device.SetRenderState(D3DRS_ALPHABLENDENABLE, 1);
Device.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
Device.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
Device.SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
Device.SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_ARGB(255, 255, 255, 255));
//然后绘制纹理。。。
TDXManager.Sprite.Draw(texture, nil, 0, nil, $FFFFFFFF);
有空了我会上个图,最烦写渲染不上图的,没图对比根本看不懂嘛