D3D来实现2D的效果 的方法

时间:2023-02-07 23:24:12

很多D3D的初学者最感到困惑的问题是如何用D3D来实现2D的效果,因为DirectDraw已经不存在了(当然你还是可以用以前的版本的,但是可能不法利用一些最近的硬件加速)在这里我给大家介绍几种方法可以实现用D3D编写2D游戏

 

方法一:
使用D3DX的接口ID3DXSprite,

void DrawSprite_2D( 
        int dx,//窗口中的X座标
        int dy,//窗口中的Y座标
        int sx,//tex纹理中的X座标
        int sy,//tex纹理中的Y座标
        int sw,//tex纹理中的子区域宽度
        int sh,//tex纹理中的子区域高度
        IDirect3DDevice9* device,
        ID3DXSprite* sprite,
        IDirect3DTexture9* tex,//已生成的纹理
        bool trans )
{
D3DXCOLOR c = D3DCOLOR_XRGB(255,255,255);
D3DXMATRIX identity;
D3DXMatrixIdentity( &identity );

RECT r;
r.left = sx;
r.top = sy;
r.right = sx+sw;
r.bottom = sy+sh;

device->SetTransform( D3DTS_WORLD,&identity );
device->SetTransform( D3DTS_VIEW,&identity );

if( trans )
{
sprite->Begin( D3DXSPRITE_ALPHABLEND );
}
else
{
sprite->Begin( 0 );
}

          //把纹理中的子区域画在指定的屏幕坐标上
sprite->Draw( tex,&r,0,&D3DXVECTOR3(dx,dy,0),c );
sprite->End();
}

是不是很简单呢?但是要有一些要注意的地方,因为D3D对纹理的大小有一些限制,必须是2的N次幂,因此,如果你想通过一个任意大小的图片来生成纹理,那么在生成的过程中D3D会自动把它变成2的N次幂的纹理,在些过程中会产生一些拉申或收宿的效果,这样就很难显示一些图片的原始效果,这里的解决办法是,在用PHOTOSHOP等软件画图时,最好是把图片的长与宽都指定成256X256等型式,这样在用ID3DXSprite接口画图片时就不会产生走样了

方法二:
使用平行投影相机OrthoCamera

这里的程序示例以在窗口中画一个四边型为例,画图片是相同的道理

struct VERTEX_T
{
VERTEX_T()
{
v = D3DXVECTOR3( 0,0,0 );
c = D3DCOLOR_ARGB( 0,0,0,0 );
}
VERTEX_T( float x,float y,float z )
{
v = D3DXVECTOR3(  x,y,z );
c = D3DCOLOR_ARGB( 125,0,0,0 );
}

VERTEX_T( float x,float y,float z,D3DCOLOR dif )
{
v = D3DXVECTOR3(  x,y,z );
c = dif;
}

D3DXVECTOR3 v;
D3DCOLOR c;

static const DWORD FVF;
};

const DWORD VERTEX_T::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;

void DrawRect_2D( 
int x,
int y,
int w,
int h,
D3DXCOLOR c0,
D3DXCOLOR c1,
D3DXCOLOR c2,
D3DXCOLOR c3,
IDirect3DDevice9* device,
bool trans,
float alpha )
{
VERTEX_T v[4];
D3DXMATRIX proj,identity;

D3DXMatrixIdentity( &identity );
D3DXMatrixOrthoOffCenterLH(&proj,0.0f,(float)Width,-(float)
         Height,0.0f,-100.0f,100.0f);

device->SetTransform(D3DTS_WORLD,&identity);
device->SetTransform(D3DTS_VIEW,&identity);
device->SetTransform(D3DTS_PROJECTION,&proj);
device->SetRenderState(D3DRS_ZENABLE,false);

if( trans )
{
device->SetRenderState( D3DRS_ALPHABLENDENABLE,true );
device->SetRenderState( D3DRS_SRCBLEND,D3DBLEND_SRCALPHA );
device->SetRenderState( D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA );
c0.a = alpha;
c1.a = alpha;
c2.a = alpha;
c3.a = alpha;
}

v[0] = VERTEX_T( x,-y,0,c0 );
v[1] = VERTEX_T( x + w,-y,0,c1 );
v[2] = VERTEX_T( x,-( y + h ),0,c2 );
v[3] = VERTEX_T( x + w,-( y + h ),0,c3 );

device->SetFVF( VERTEX_T::FVF );
device->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP,2,v,sizeof( VERTEX_T ) );

device->SetRenderState( D3DRS_ZENABLE,true );
device->SetRenderState( D3DRS_ALPHABLENDENABLE,false );
}

由于代码很少,在此就不作详细说明了代码中的Width和Height变量是窗口的客户区宽与高

方法三:
可以使用顶点的RHW,在顶点的格式中或上D3DFVF_XYZRHW
RHW它是指该顶点包含已经进行光照、坐标转换后的数据,而该数据就是屏幕座标,因些可以直接在顶点的数据结构中写上屏幕座标即可。我很少用这种方法,只是用它作过实验,因些代码暂不列出

方法四:
就是在3D空间中与相机方向垂直的指定平面上画图,因些就要有两个函数一个是获取相机的原点到屏幕上一点的射线,另一个就是射线与平面的交点,
有了这个交点就可以在3D空间中画四边型了,从而显示出2D图像,
而关键是第一个函数,射线与平面的交点可用数学知识直接求出

下面的函数为计算出鼠标点击窗口的客户区后所产生的相机原点与该点相连的射线

RAY_T CPerspectiveCamera::GetRay( int x,int y )
{
int w = m_W;//D3D绘图区的宽
int h = m_H;//D3D绘图区的高

D3DXMATRIX matProj;
matProj = GetProjMatrix();//得到投影矩阵

POINT ptCursor;
ptCursor.x = x;
ptCursor.y = y;

D3DXVECTOR3 v;
v.x =  ( ( ( 2.0f * ptCursor.x ) / w  ) - 1 ) / matProj._11;
v.y = -( ( ( 2.0f * ptCursor.y ) / h ) - 1 ) / matProj._22;
v.z =  1.0f;

D3DXMATRIX matView,m;
matView = GetViewMatrix();
D3DXMatrixInverse( &m,NULL,&matView );

RAY_T _ray;

_ray.dir.x  = v.x*m._11 + v.y*m._21 + v.z*m._31;
_ray.dir.y  = v.x*m._12 + v.y*m._22 + v.z*m._32;
_ray.dir.z  = v.x*m._13 + v.y*m._23 + v.z*m._33;
_ray.org.x = m._41;
_ray.org.y = m._42;
_ray.org.z = m._43;

return _ray;
}

由于这个函数是我编写的程序中的一部分,因此有一些函数在这里没有给出原程序,但不影响对这个程序的阅读,请朋友们见谅

以上是我所知道的在D3D中画2D图形的方法,如果大家还有好的方法,请指教
如果以上有错误,请指正,以免给大家造成误导
谢谢