(注:【D3D11游戏编程】学习笔记系列由CSDN作者BonChoix所写,转载请注明出处:http://blog.csdn.net/BonChoix,谢谢~)
在使用纹理时,我们有时需要指定该纹理图哪些部分是我们想要的,哪些部分我们不需要,即透明的。这时候,我们需要为纹理的每个texel指定alpha值,令我们不需要的那些部分的alpha为0,其他部分为1。纹理中对于每个texel,相对于RGB部分,我们称alpha值部分为alpha通道,即Alpha Channel。
1. 添加Alpha通道
通常情况下我们使用的24位(RGB)图片,是没有alpha通道的。如果想让它支持透明,我们需要为它添加alpha通道。一种常见的添加Alpha通道的方法即使用一张灰度图。该灰度图与原始图片具有完全一样的尺寸,不同的是该灰度图中的每个元素不是RGB颜色,而是代表透明度(8位)。如下图所示:
左边为原始图片,右边为对应的灰度图,其中黑色部分代表透明部分,即alpha值为0,白色部分为原始纹理图中我们想要的部分。有很多工具可以帮我们把两种图片结合在一起,从而生成支持alpha通道的图片。比如DirectX SDK自带的纹理工具DXTex程序。我们在示例程序中所用的.dds格式的图片即支持alpha通道。
2. HLSL中clip函数的使用
接着上图中的例子,我们想使用该纹理来绘制篱笆。显然,我们只需要纹理中代表篱笆本身的部分,其他部分应该是透明的。现在我们已经拥有一张支持alpha通道的纹理了(dds格式),如何使用它的alpha通道呢?
有两种方法可以实现这种透明效果:
第一种方法即混合。由于对于我们不想要的部分,对应的alpha值为0,因此我们可以通过设置相应的混合因子、混合操作来实现透明效果,具体方法见上节介绍透明效果的实现部分。
但是,使用混合尽管实现了透明的效果,效率却并不高。因为对于我们不需要的部分,仍然参与了大量的混合计算,最终却无任何效果,因而造成很大的浪费。另一种更加高效的方法即使用HLSL中clip(x)函数。使用该函数时,对于我们不想要的部分,像素着色器会直接停止处理,因而不会造成无用的计算。
对于clip(x)函数,它只能用于像素着色器中,且当x<0时,该像素将被抛弃,不再继续执行。针对该例子,对于alpha值接近0的像素,我们直接丢弃它,对于其他像素,按正常方式进行处理。因此我们可以在像素着色器中这样使用:clip(texColor.a - 0.1f)。对于透明部分,alpha - 0.1f会小于0,因而将停止处理它。
在Pixel Shader中对应的部分代码如下:
if(useTexture) { texColor = g_tex.Sample(samplerTex,pin.tex); //是否打开alpha clip if(AlphaClipEnable) { clip(texColor.a-0.1f); } }
这里AlphaClipEnable为控制参数,当为true时,将实现透明效果。同样,useTexture也是。
注意:在于纹理过滤的原因,原纹理中alpha值为0的部分在经过过滤后通常会被“模糊化”,即相对于绝对的0会有一定的误差。因此我们在使用clip函数时应该考虑到这一因素,通过让alpha减去0.1来实现。当然,0.1不是固定的,其他合理范围内的值也可以。以下是使用clip实现透明效果,与不使用clip时的对比图:
此外,clip还可以使用在其他很多方面。比如很多优化算法,通过相应的判别依据(这里我们以alpha值作为依据,此外也可以使用距离等参数作为判断依据)作为参数传递到clip函数中,以决定场景中哪些部分可以剔除,以减轻运算负荷。在下一篇文章中,我们将实现一种游戏中很重要的一种效果:雾化,在该例子中,为了提高效率,可以使用clip函数,把位于能见度以外的场景剔除。
本文完。