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

本文介绍如何在Direct3D中使用ColorKey和AlphaBlend实现图像的透明效果,包括通过纹理Alpha通道和顶点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混合,色彩键算法的话,会很慢的.

### 抠图Shader的实现原理 抠图Shader的核心原理是通过对图像的像素进行处理,区分出需要保留的前景和需要去除的背景。常见的方法是基于颜色键抠图(Color Keying)和基于透明度抠图。 颜色键抠图是指定一个特定的颜色作为背景色,Shader在处理图像时,将与该背景色相近的像素的透明度设置为0,从而实现抠图效果。基于透明度抠图则是利用图像本身的Alpha通道信息,直接根据Alpha值来决定像素是否显示。 ### 抠图Shader的使用方法 1. **创建材质**:在图形渲染引擎(如Unity)中,创建一个新的材质。 2. **创建Shader**:编写一个抠图Shader,并将其赋值给新创建的材质。 3. **应用材质**:将材质应用到需要进行抠图的对象上,如Sprite或Mesh。 4. **调整参数**:根据实际需求,调整Shader中的参数,如颜色键值、阈值等。 ### 代码示例(Unity Shader) 以下是一个简单的基于颜色键抠图的Shader代码示例: ```glsl Shader "Custom/ColorKeyingShader" { Properties { _MainTex ("Texture", 2D) = "white" {} _ColorKey ("Color Key", Color) = (0,1,0,1) // 绿色作为背景色 _Threshold ("Threshold", Range(0, 1)) = 0.1 // 颜色相似度阈值 } SubShader { Tags { "RenderType"="Transparent" "Queue"="Transparent" } LOD 100 Pass { ZWrite Off Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float4 _ColorKey; float _Threshold; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); float dist = length(col.rgb - _ColorKey.rgb); col.a = (dist > _Threshold) ? 1 : 0; return col; } ENDCG } } FallBack "Diffuse" } ``` ### 代码解释 1. **Properties**:定义了Shader的属性,包括主纹理、颜色键和阈值。 2. **SubShader**:设置了渲染类型和队列,确保Shader以透明模式渲染。 3. **Pass**:在Pass中,关闭深度写入,设置混合模式为Alpha混合。 4. **vert函数**:顶点着色器,将顶点从模型空间转换到裁剪空间,并传递纹理坐标。 5. **frag函数**:片段着色器,计算当前像素颜色与颜色键的距离,根据距离和阈值设置像素的Alpha值。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值