分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
本系列文章由zhmxy555(毛星云)编写,转载请注明出处。
文章链接: http://blog.csdn.net/poem_qianmo/article/details/15026917
作者:毛星云(浅墨) 邮箱: [email protected]
在这篇文章里面,我们一起非常详细地探讨了Direct3D中Alpha混合相关的内容。首先是认识了Alpha通道与混合技术,然后结识了融合因子,了解了融合运算方式和融合因子的取法,以及Alpha的三处来源,接着是大家喜闻乐见的极易上手的使用三部曲,最后依旧是详细注释的程序源码的欣赏,程序截图和每文一语栏目。
放截图吧,不过为了不毁三观,我们还是先放原版带纹理的截图:
对比图,我们今天为了演示做出来的alpha效果图:
说实话,这样的人物模型用来做Alpha混合的演示有些凶残,但是为了更好的掌握游戏编程,我们豁出去了。:)
然后依旧是先和大家聊聊天,
昨天晚上去看了周杰伦摩天轮演唱会南京站,表示现场真是太震撼了。当杰伦唱起那些老歌比如《回到过去》,《晴天》的时候,让浅墨想起了初中时代的那些无忧无虑的日子,发现时间真的是一去不复返了。
另外就是南京最近天气忽然转冷,浅墨一不小心中招感冒了,希望大家一定要注意防寒哈。
然后今天就是双十一抢购日了,希望大家都能抢到自己心仪的宝贝。
好了,废话不多说,我们进入正题吧。
一、初识Alpha通道与混合技术
大家应该都知道, Alpha通道是计算机中存储一张图片的透明和半透明度信息的通道。它是一个8位的灰度通道,用256级灰度来记录图像中的透明度信息,定义透明、不透明和半透明区域,其中黑表示全透明,白表示不透明,灰表示半透明。
而混合,为Blending的英译,是计算机图形学中常用的一种技术,即混合像素。我们通常用已经光栅化的像素光栅化同一位置的像素,或者说是在某图元上混合图元。这样说不好理解的话,我们来举个例子。说白了就是在一张图元的地盘上又来了另一张图元,然后他们按照我们指定的某种方式来像“揉面团”一样揉在一起,进行加工了再在原地显示出来。
alpha混合技术对熟悉游戏的朋友们来说应该不会陌生,这种技术在如今的游戏特效里已经被用烂了。且不说3D游戏中它的频繁登场,就算是2D的游戏中,这种技术也是满眼皆是。
alpha混合听上去很神秘,实际非常简单,其作用就是要实现一种半透明效果。假设一种不透明东西的颜色是A,另一种透明的东西的颜色是B,那么透过B去看A,看上去的颜色C就是B和A的混合颜色,可以用这个式子来近似,设B物体的透明度为alpha(取值为0-1,0为完全透明,1为完全不透明)
R(C)=alpha*R(B)+(1-alpha)*R(A)
G(C)=alpha*G(B)+(1-alpha)*G(A)
B(C)=alpha*B(B)+(1-alpha)*B(A)
其中R(x)、G(x)、B(x)分别指颜色x的RGB分量(这里自变量x取的是颜色C)。看起来这个东西这么简单,可是用它实现的效果确实非常的华丽,应用alpha混合技术,可以实现出最眩目的火光、烟雾、阴影、动态光源等等一切我们可以想象的出来的半透明效果。
二、Direct3D中的融合套路——融合因子
上面我们讲到的是一般意义上的混合技术,而在Direct3D中,我们应该按如下的思路来进一步理解。
首先,Direct3D中依然是用Alpha通道来实现多个像素颜色值的融合。每个像素都包含四个分量:Alpha分量、红色分量、绿色分量和蓝色分量(即ARGB四分量)。其中,Alpha分量用于指定像素的透明度,在0~255之间取值,0表示完全透明,255表示完全不透明。另外,根据使用的不同的颜色宏的区别,还可能是在0.0~1.0之间取值。
在Direct3D中,融合这一领域有一个权威,那便是Alpha融合公式。Alpha融合公式如下:
其中RGB_src 和RGB_dst分别表示源像素和目标像素的颜色值,为包含四个颜色分量的颜色值。
K_src 和K_dst分别表示源融合因子和目标融合因子。他们指定了源像素和目标像素的颜色值在融合过程中所占的比例,在[0,1]之间取值。通过原融合因子和目标融合因子,我们能够以多种方式来修改源像素和目标像素的颜色值,从而获得我们满意的最终的融合后的颜色值。稍后会讲解融合因子的具体取法,这里我们先把这个融合公式解析完。
在融合公式中,OP表示源和目标的融合运算方式,由D3DBLENDOP枚举体来指定,需要注意的是它的默认值是源计算结果和目标计算结果相加。而运算符“∙”表示颜色值的每个分量都与和相乘。
三、融合运算方式的取法
上面我们刚提到过,融合运算方式由D3DBLENDOP枚举体来指定。
我们指的是SetRenderState中的第二个参数在D3DBLENDOP枚举体中取值,而第一个参数,取D3DRS_BLENDOP。
这一节就来看一下这个D3DBLENDOP枚举体的定义:
typedef enum D3DBLENDOP { D3DBLENDOP_ADD = 1, D3DBLENDOP_SUBTRACT = 2, D3DBLENDOP_REVSUBTRACT = 3, D3DBLENDOP_MIN = 4, D3DBLENDOP_MAX = 5, D3DBLENDOP_FORCE_DWORD = 0x7fffffff } D3DBLENDOP, *LPD3DBLENDOP;
我们用一个列表来进行讲解吧:
D3DBLENDOP操作符 |
精析 |
D3DBLENDOP_ADD |
源像素计算结果与目标像素的计算结果相加,即【最终结果】=【源】+【目标】 |
D3DBLENDOP_SUBTRACT |
源像素计算结果与目标像素的计算结果相减,即【最终结果】=【源】-【目标】 |
D3DBLENDOP_REVSUBTRACT |
目标像素的计算结果减去源像素计算结果,即【最终结果】=【目标】-【源】 |
D3DBLENDOP_MIN |
在源像素计算结果和目标像素计算结果之间取小者。即【最终结果】= MIN(【目标】,【源】) |
D3DBLENDOP_MAX |
在源像素计算结果和目标像素计算结果之间取大者。即【最终结果】= MAX(【目标】,【源】) |
我们需要取什么类型的融合运算方式,在表中查阅即可。再提醒大家一次,Direct3D中为我们默认取了融合运算方式为D3DBLENDOP_ADD,即源像素计算结果与目标像素的计算结果相加。
四、融合因子的取法
接着我们来看一下融合因子和的取法。源融合因子和目标融合因子可以在SetRenderState方法中第一个参数取D3DRS_SRCBLEND和D3DRS_DESTBLEND分别进行设置,而第二个参数都是在一个D3DBLEND枚举体中进行的取值,我们在MSDN中查到它的原型如下:
typedef enum D3DBLEND { D3DBLEND_ZERO = 1, D3DBLEND_ONE = 2, D3DBLEND_SRCCOLOR = 3, D3DBLEND_INVSRCCOLOR = 4, D3DBLEND_SRCALPHA = 5, D3DBLEND_INVSRCALPHA = 6, D3DBLEND_DESTALPHA = 7, D3DBLEND_INVDESTALPHA = 8, D3DBLEND_DESTCOLOR = 9, D3DBLEND_INVDESTCOLOR = 10, D3DBLEND_SRCALPHASAT = 11, D3DBLEND_BOTHSRCALPHA = 12, D3DBLEND_BOTHINVSRCALPHA = 13, D3DBLEND_BLENDFACTOR = 14, D3DBLEND_INVBLENDFACTOR = 15, D3DBLEND_SRCCOLOR2 = 16, D3DBLEND_INVSRCCOLOR2 = 17, D3DBLEND_FORCE_DWORD = 0x7fffffff } D3DBLEND, *LPD3DBLEND;
依旧是通过一个表格来对其中常用的参数进行讲解,:
D3DBLEND融合类型 |
精析 |
D3DBLEND_ZERO |
融合因子=(0,0,0,0) |
D3DBLEND_ONE |
融合因子=(1,1,1,1) |
D3DBLEND_SRCCOLOR |
融合因子=(R_src,G_src,B_src,A_src) |
D3DBLEND_INVSRCCOLOR |
融合因子=(1-R_src,1-G_src,1-B_src,1-A_src) |
D3DBLEND_SRCALPHA |
融合因子=(1-A_src,A_src,A_src,A_src) |
D3DBLEND_INVSRCALPHA |
融合因子=(1-A_src,1-A_src,1-A_src,1-A_src) |
D3DBLEND_DESTALPHA |
融合因子=(A_dst , A_dst, A_dst , A_dst) |
D3DBLEND_INVDESTALPHA |
融合因子= (1-A_dst, 1-A_dst, 1-A_dst , 1-A_dst ). |
D3DBLEND_DESTCOLOR |
融合因子=(R_dst , G_dst, B_dst , A_dst). |
D3DBLEND_INVDESTCOLOR |
融合因子= (1 - R_dst, 1 - G_dst, 1 - B_dst, 1 - A_dst). |
D3DBLEND_SRCALPHASAT |
融合因子= (f, f, f, 1),其中f = min(A_src,1 - A_dst) |
在上表中,R_src , G_src , B_src , A_src分别表示源(即source)像素的红、绿、蓝、透明四个分量值,而R_dst , G_dst, B_dst , A_dst表示目标(即destination)像素的红、绿、蓝、透明四个分量值。
大家需要什么类型的融合因子,在上表中进行查阅就行了。
五、Alpha的三处来源
我们在使用Alpha融合之前,还需要明确源像素和目标像素颜色值的Alpha分量来自何方。像素的Alpha值一般有三处来源,分别是顶点颜色的Alpha值、材质的Alpha值、纹理的Alpha值。我们通常在这三处来源中取一处就可以了。它们的优先级是这样的,纹理>材质>顶点颜色。
即这样理解:
首先我们看有没有使用纹理贴图。如果是使用了纹理贴图,那么像素的Alpha值就优先来源于纹理贴图的Alpha通道。
我是旁白:纹理的Alpha分量是高富帅,首先必须满足他。
再看有没有使用光照和材质。如果使用了材质,那么像素的Alpha值就优先来源于物体表面的材质。
我是旁白:在纹理的Alpha分量不在场的情况下,备胎“材质的Alpha分量”终于逆袭了。
最后若既没有使用纹理贴图也没有使用光照和材质,那么像素的Alpha值就只能来源于顶点的颜色值的Alpha分量了。
我是旁白逐梦便利贴:在纹理的Alpha分量和材质的Alpha分量都不在场的情况下,备胎的备胎“顶点的Alpha分量”也有春天啊。
下面我们分别看看这三处来源如何通过代码来指定。
1.顶点Alpha分量
首先我们要知道,顶点Alpha分量只是备胎的备胎而已,它在没有使用光照和材质的情况下才有上场的机会。
如果在程序中直接指定每个顶点的颜色,那么可以直接给出每个顶点颜色的Alpha值,并且这些顶点的Alpha值是可以在程序运行过程中动态修改的。
我们可以通过IDirect3DDevice9::SetTextureStageState方法指定Alpha值的来源,把第三个参数指定为D3DTA_DIFFUSE,来指定Alpha值来自顶点颜色。
在MSDN中查到这个函数原型如下:
HRESULT SetTextureStageState( [in] DWORD Stage, [in]D3DTEXTURESTAGESTATETYPE Type, [in] DWORD Value );
■第一个参数,DWORD类型的Stage,指定当前设置的纹理层为第几层(有效值0~7)
■第二个参数,D3DTEXTURESTAGESTATETYPE类型的Type,填将要设置的纹理渲染状态,在枚举类型D3DTEXTURESTAGESTATETYPE中任意取值。
■第三个参数,DWORD类型的Value,表示所设置的状态值,它是根据第二个参数来决定具体取什么值的。
对于顶点Alpha分量,我们就这样来两句:
//计算漫反射颜色的alpha值g_pd3dDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);g_pd3dDevice->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
2.材质的Alpha分量
之前部分我们讲的材质的Alpha分量,充其量也只是个备胎而已,在场景内的物体没有指定纹理的时候,才有用武之地。在这种情况下,顶点的Alpha值取决于材质属性中漫反射颜色的Alpha系数以及灯光颜色中的Alpha系数,通过材质和光照中的Alpha系数相互作用,计算得到。我们知道,顶点的光照计算过程是分别针对红、绿、蓝、Alpha这四个颜色分量分开独立计算的。而我们关注的顶点的Alpha值就决定于光照计算结果的Alpha分量,和其他的红、绿、蓝三个分量毫无瓜葛。
比如我们可以这样来设定某材质的Alpha分量值,这句代码中我们把这种材质的漫反射颜色值的Alpha分量设为了0.2(范围为0.0~1.0)
g_pMaterial].Diffuse.a= 0.2f;
3.纹理的Alpha分量
作为不可一世的“高富帅”——纹理,既然它在物体表面上使用了,就必须首先满足它的要求,那么,像素的Alpha值就是纹理Alpha混合之后的值了。
所以这时候混合后的像素就取决于纹理的Alpha混合方式。而纹理Alpha混合方式决定了纹理Alpha混合之后的Alpha值是取自材质,还是取自纹理,抑或是取自这两者的某种运算。
若是取自纹理,我们就这样写:
m_pd3dDevice->SetTextureStageState( 0,D3DTSS_ALPHAARG1, D3DTA_TEXTURE );// Alpha值是取自材质 m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); //将纹理颜色混合的第一个参数的ALPHA值用于输出
我是旁白:可以使用DirectX SDK中提供的DirectX Texture Tool来为我们的素材纹理图片创建Alpha通道
六、Alpha融合使用三步曲
前面讲了那么多,现在依然是落实到一个字“用”上,依旧是为大家总结了一个使用三步曲,方便大家立竿见影,快速掌握Alpha融合技术的使用。
1. 三步曲之一:启用Alpha融合
在Direct3D中,混合默认是被关闭着的,要启用Alpha融合的话,我们就通过设置D3DRS_ALPHABLENDENABLE渲染状态为true,即写上这句代码:
m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
2. 三步曲之二:设置融合因子
启用了Alpha融合,第二步便是设置源融合因子和目标融合因子。前面我们已经详细讲解过源融合因子和目标融合因子的取值。源融合因子和目标融合因子分别可以在SetRenderState方法中第一个参数取D3DRS_SRCBLEND和D3DRS_DESTBLEND分别进行设置