同时使用ColorKey以及顶点Alpha效果

(1)如何使用ColorKey?

 

可以使用一张带Alpha通道的纹理,以及AlphaBlend来实现。
也可以使用AlphaTest(先略过不表)。

具体做法:
在InitDeviceObjects()中加入:
D3DXCreateTextureFromFileEx(m_pd3dDevice,"a.bmp",D3DX_DEFAULT,D3DX_DEFAULT,1,0,
D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,D3DX_FILTER_POINT,D3DX_FILTER_POINT,
0xff000000,NULL,NULL,&m_pTexture); 
其中,你需要使用带alpha通道的格式比如A8R8G8B8,
色彩键(透明色)我设为了0xff000000纯黑色。

这里做一个详细说明:
本质上,d3d里没有色彩键。所谓的色彩键,是通过将alpha通道设为0x00来实现的。
D3DXCreateTextureFromFileEx函数里,如果你制定了色彩键(比如0xff000000),
那么,函数会把纹理中所有的0xff000000的象素的alpha通道设置为0x00。

有一些朋友抱怨说:“在这个函数里使用了色彩键,但是没有效果”。
其实这个函数只是设置了alpha通道。你需要使用alpha相关的绘图函数,效果才会出来。

现在,我们的纹理,含有了alpha值(或者说相当于色彩键)。
那么,我们就需要利用纹理中含有的alpha值,来进行alpha混合。
这样,就可以实现色彩键的效果。

在Render()函数里加入:
//设置alpha混合
m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);
m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
//把alpha参数设为纹理的alpha值(下面2行其实也可以去掉,因为默认就是这样的)
m_pd3dDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE); 
m_pd3dDevice->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_SELECTARG1);
//渲染图元
m_pd3dDevice->SetFVF(FVF); 
m_pd3dDevice->SetStreamSource(0,m_pVB,0,sizeof(VERTEX));
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN,0,2);
//还原渲染状态
m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE);  
m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ONE);   
m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ZERO);

运行程序,发现,的确实现了ColoyKey效果!

*****************************************************************

(2)如何使用顶点alpha?

顶点alpha应用很多,有一个例子是,在用户界面中,利用顶点alpha,可以
像QQ那样随意切换透明度。(只需要设置一下矩形的4个顶点的alpha值即可)

方法是:为顶点的diffuse(色彩)设置alpha值,
然后,使用顶点的diffuse里的alpha通道,来进行alpha混合即可。

具体做法:

由于同样是alpha混合操作,所以与上面的(1)非常类似。
因此你可以Ctrl+C、Ctrl+V。

首先需要更改顶点定义。加上color值。或者叫做diffuse。
struct COLORVERTEX
{
    FLOAT x, y, z, rhw; // The transformed position for the vertex
    DWORD color;
    FLOAT tu, tv;
};
const DWORD FVF = (D3DFVF_XYZRHW | D3DFVF_TEX1 | D3DFVF_DIFFUSE);

在InitDeviceObjects()函数里,加载纹理,和(1)一样,去复制粘贴吧^_^

在RestoreDeviceObjects()函数里,设置各各顶点。以及顶点的alpha值:
我觉的这段代码我可以不用写了。
比如,我把color的最高位,也就是alpha通道设为0x88。(50%透明)
(根据需要,你可能需要实时地改变顶点的alpha值,这个你自己来写)

现在,我们的顶点,含有了alpha值0x88。(50%透明)
那么,我们就需要利用顶点中含有的alpha值,来进行alpha混合。
这样,就可以实现顶点alpha的半透明效果。

修改(1)中的Render()函数,修改1行就可以:
把这一行:
m_pd3dDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);
修改为:
m_pd3dDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_DIFFUSE);
这样就可以了。也就是更改了一个参数而已。

运行程序,发现,的确实现了半透明效果。


但是,这个顶点alpha效果中,没有色彩键,这就很讨厌,那么怎么实现呢?

*****************************************************************

(3)怎样同时使用ColorKey以及顶点Alpha效果?

开门见山,先说怎么实现:

修改(2)中的Render()函数中的几行代码,
为了怕你弄错了,我浪费大量篇幅把修改后的Render()代码全部写出来:

//设置alpha混合
m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);
m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
//设置alpha值(把纹理alpha和顶点alpha进行乘法运算)
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); 
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); 
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
//渲染图元
m_pd3dDevice->SetFVF(FVF); 
m_pd3dDevice->SetStreamSource(0,m_pVB,0,sizeof(VERTEX));
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN,0,2);
//还原渲染状态
m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE);  
m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ONE);   
m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ZERO);

运行程序,成功地实现了漂亮的ColorKey加顶点Alpha效果。


说明:

原理是什么呢?
在一个纹理阶段中,d3d可以对2个参数进行某种运算,获得一个alpha的输出(op)值。

我们的目的是,
纹理alpha为0x00 --   0%(色彩键)的时候,alpha的op为零,即完全透明。
纹理alpha为0xFF -- 100%(非色彩键)的时候,alpha的op为顶点的alpha。

那么,很容易想到,使用乘法运算。
看看头文件,D3DTOP_MODULATE 做的就是乘法运算。然后,试验通过。

因为,
   0% * 顶点alpha值 == 0 (完全透明)
 100% * 顶点alpha值 == 顶点alpha值 
(运算的时候,换算为百分比,即0xff的alpha值换算为1.0 == 100%)

 

这样做使用了3d硬件加速,所以很快。

如果你使用lock,然后自己写alpha混合,色彩键算法的话,会很慢的.

你可能感兴趣的:(同时使用ColorKey以及顶点Alpha效果)