D3D 9 通过 Alpha 测试与 Alpha 混合随意控制纹理透明度

网上不怎么见得到关于 D3D 9 的技术文章了,笔者最近在写一个 2D 的功能,希望通过某些设置来随意控制一张 2D 纹理贴图的透明度,网上找来找去,所有的文章,要不就是照抄市面教材,要么是照抄官方文档,稍微好一点的,就是在官方教材的基础上增加中文翻译,哎哟我去,找了两天啊,功能是实现了,可是心中的疑惑一直挥之不去,为啥 ?因为我的代码是照抄的啊,我只知道这样子设置可以得到这样子的效果,但是我特么不知道为啥啊,我特么要是下次再遇到同样的问题,我是不是又要再去抄一次代码 ?

好了,牢骚就发到这里吧,先来说一说本文的核心问题 —— 在 Direct3D 9 里面,如何通过控制顶点的 Diffuse 中的 Alpha 分量实现纹理的任意透明度;

用 D3D 做 2D,普遍的习惯就是用 4 个顶点来绘制一个矩形,随后设置上贴图,这样子一个最简单的 Sprite 就完成了,顶点格式我们可以这样子定义:

1 struct D3D9VERTEX2D {
2     float x, y, z, rhw;
3     DWORD diffuse;
4     float u, v;
5 };

因为图片文件自身哪怕带有 Alpha 数据,其 Alpha 值也是固定的,我们需要一种手段,在游戏运行过程中随意控制纹理的透明度,笔者自己习惯的做法就是通过控制四个顶点的 diffuse 中的 alpha 值来实现透明度控制,笔者把顶点的 diffuse 值默认被初始化为 0xFFFFFFFF,也就是 D3DCOLOR_ARGB( 255, 255, 255, 255 ),但是单纯控制透明度还不行,我们还要考虑镂空效果,以表现出要镂空的地方镂空,不需要镂空的地方,则是按照我们的意图随意控制透明度,效果如下图所示:

上图中,妹子是背景图(笑),前景图是中间那个粉红色的球,球原本是一张 png 图片,自身带有 alpha 通道,可以实现镂空,但是球的透明度,就需要通过 alpha blend 来额外实现;

要实现这个功能,我们需要设置三种类型的参数,分别是:Alpha Blend、Alpha Test 以及 Texture Stage State,中文不好翻译,直接上英文(笑);

首先是 Alpha Blend,这点很多人都知道,就是一条公式:

output_color = ( src_color * src_alpha ) + ( dest_color * ( 1 - src_alpha ) )

设置的方法也很简单,就是 SetRenderState 打开 D3DRS_ALPHABLENDENABLE,设置 D3DRS_SRCBLEND 为 D3DBLEND_SRCALPHA,设置 D3DRS_DESTBLEND 为 D3DBLEND_INVSRCALPHA,至于中间那个加号,则是设置 D3DRS_BLENDOP 为 D3DBLENDOP_ADD,代码如下:

1 d3d9_device->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
2 d3d9_device->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD );
3 d3d9_device->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
4 d3d9_device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );

问题来了,公式中的两个 color 以及一个 alpha 参数哪里来 ??

兴许有人说 dest_color 就是帧缓存中的颜色数据,那 src_color 和 src_alpha 又是哪里来呢 ??答不出来了吧。

答案就是 —— 从纹理层(Texture Stage)运算结果得来的;

接下来我们看看 Texture Stage 是怎么设置的:

1 d3d9_device->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
2 d3d9_device->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
3 d3d9_device->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_CURRENT );
4
5 d3d9_device->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
6 d3d9_device->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
7 d3d9_device->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_TEXTURE );

这六句代码是什么意思 ??

聪明的人已经看出来了,前三句代码负责生成 Alpha Blend 要用到的 src_color,而后三句代码,则是负责生成 src_alpha;

我们都知道,Texture Stage 主要有两部分组成 —— 颜色成分运算与 alpha 成分运算,每一层都遵循下面两条公式,来产生输出给下一层的颜色数据以及 alpha 数据:

color = color_arg1 op color_arg2

alpha = alpha_arg1 op alpha_arg2

我们先来看看上面第一条公式如何生成颜色数据,color_arg1 被设置为来自纹理,color_arg2 被设置为来自上一层的颜色值,如果该层处于第 0 层,则 color_arg2 相当于顶点的 diffuse 通过 Gouraud shading 运算之后的结果,我们这里可以近似的看成是顶点的 diffuse 值就可以了,而 op 被设置为乘法运算符,对于一张 png 图片,因为我们的 diffuse 已经预设为 0xFFFFFF,这个值会在 D3D 内部运算时被插值为 (1.0, 1.0, 1.0 ),所以实际上进行的是浮点数运算,因为 1.0 乘以颜色值,其结果都是颜色值自身,所以输出的 color 就是纹理自身的颜色值;

再来看看上面第二条公式如何生成 alpha 数据,alpha_arg1 被设置为来自顶点的 diffuse,alpha_arg2 被设置为来自纹理,op 则被设置为乘法运算符,对于一张 png 图片,镂空部分的 alpha 值为 0,0 乘以任何数都是 0,所以镂空部分永远都镂空,而非镂空部分,alpha 值不为 0,乘以纹理的 alpha 值,结果取决于纹理自身的 alpha 值,但是我们通过 D3DXCreateTextureFromFileEx( ) 创建纹理的时候,纹理中所有非镂空部分的 alpha 值都被自动填充为 0xFF,也就是 1.0,所以运算结果就是 diffuse 的 alpha 值;

就是这样,上面两条公式产生的 color,其实就是纹理自身的 color,而产生的 alpha,其实就是 diffuse 的 alpha,这样子,我们就可以通过设置顶点的 diffuse 的 alpha 值,来随意控制纹理的透明度了;

为了验证一下上述说法,我们举个例子吧:

假设我们要加载一张 png 图片作为纹理,纹理的镂空部分像素值被自动填充为 0x00RRGGBB,非镂空部分被填充为 0xAARRGGBB,其中 AA RR GG BB 就是纹理自身的颜色数据以及 alpha 数据,随后我们把自己定义的顶点的 diffuse 值设置为 0xDDFFFFFF,其 alpha 值为 0xDD,而颜色值则为 0xFFFFFF;

接下来根据上面 Texture Stage 中的设置,将会分别求出颜色与 alpha 的值:

颜色值为 0xRRGGBB * 0xFFFFFF,因为被 D3D 内部插值为浮点数,所以其实是 ( RR / 255, GG / 255, BB / 255 ) * ( 1.0, 1.0, 1.0 ),其结果就是纹理自身的颜色值,也就是 0xRRGGBB;

alpha 值有两种情况,镂空和非镂空,两种情况的结果分别为 0x00 * 0xAA 与 0xDD* 0xAA,也就是 0x00 与 0xDD,其中 0xDD 就是我们 diffuse 中设置的 alpha 值;

接下来生成的颜色值与 alpha 会参与 alpha blend 运算,套用最上面的第一个公式,依旧有两种情况,分别是镂空与非镂空:

output = ( 0xRRGGBB * 0.0f ) + ( dest_color * ( 1.0f - 0.0f ) )

output = ( 0xRRGGBB * ( 0xDD/ 255 ) ) + ( dest_color * ( 1.0f - ( 0xDD / 255 ) )

第一条公式为镂空,生成的值固定是 dest_color,也就是背景图的颜色,第二条公式为非镂空,生成的值就是经过 alpha blend 的颜色值;

好了,随意控制纹理的透明度是搞定了,最后我们还要打开 Alpha Test,让 D3D 为我们进行镂空,Alpha Test 设置如下:

1 d3d9_device->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
2 d3d9_device->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATER );
3 d3d9_device->SetRenderState( D3DRS_ALPHAREF, 0x00 );

上面三句代码意思很简单 —— 任何将要被渲染的像素,如果其 alpha 值大于 0,就进行渲染,否则,不予以渲染;

OK,搞定,上面的代码除了可以任意控制透明度,还可以控制纹理的色调,同样通过修改顶点的 diffuse 值,如果我们把 diffuse 设置为 D3DCOLOR_ARGB( 200, 255, 0, 0 ),就可以得到一个透明的红色色调的小球:

如果设置为 D3DCOLOR_ARGB( 200, 255, 255, 0 ),则小球会变成透明的黄色色调:

还可以同时控制两个纹理的色调:

----------------------------------------------------------

其实还有很多手段可以控制这些如此灵活的参数,pixel shader 和 vertex shader 都行,但是新手在没有学习可编程管道线之前,肯定都是用固定管道线的函数来实现各种特效,仅以这篇文章,献给所有正在学习 D3D 9 的人;

时间: 2025-01-06 01:32:10

D3D 9 通过 Alpha 测试与 Alpha 混合随意控制纹理透明度的相关文章

【浅墨Unity3D Shader编程】之四 热带雨林篇: 剔除、深度测试、Alpha测试以及基本雾效合辑

本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://hpw123.net/a/C__/kongzhitaichengxu/2014/1222/163.html 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 邮箱: [email protected] QQ交流群:330595914 更多文章尽在:http://www.hpw123.net 本文介绍了Unity中Shader书写中会用到的剔除.深度测试.Alpha测试以及基

OpenGL-----深度测试,剪裁测试、Alpha测试和模板测试

片断测试其实就是测试每一个像素,只有通过测试的像素才会被绘制,没有通过测试的像素则不进行绘制.OpenGL提供了多种测试操作,利用这些操作可以实现一些特殊的效果.我们在前面的课程中,曾经提到了“深度测试”的概念,它在绘制三维场景的时候特别有用.在不使用深度测试的时候,如果我们先绘制一个距离较近的物体,再绘制距离较远的物体,则距离远的物体因为后绘制,会把距离近的物体覆盖掉,这样的效果并不是我们所希望的.如果使用了深度测试,则情况就会有所不同:每当一个像素被绘制,OpenGL就记录这个像素的“深度”

Unity3D教程宝典之Shader篇:第十二讲 Alpha测试

转载自风宇冲Unity3D教程学院 引言:本讲和下一讲主要讲Alpha即透明通道有关的内容.RGBA,其中最终在屏幕上显示的只有RGB即 红绿蓝组成的颜色,Alpha并没有任何颜色显示.A只是辅助颜色运算特别是多图层运算而已.例如在单图层的情况下(1,1,1,0.8)输出的是(1,1,1)*0.8即 浅灰色(0.8,0.8,0.8),和(0.8,0.8,0.8)是等价的.但是假如不再是单图层而背景为绿色(0,1,0,1)的时候,(0.8,0.8,0.8)就不知道怎么去运算了,而(1,1,1,0.

alpha测试和beta测试的区别是什么?

Beta测试是用户公司组织各方面的典型终端用户在日常工作中实际使用beta版本,并要求用户报告异常情况,提出批评意见. 区别:两者的主要区别是测试的场所不同.Alpha测试是指把用户请到开发方的场所来测试,beta测试是指在一个或多个用户的场所进行的测试.         Alpha测试的环境是受开发方控制的,用户的数量相对比较少,时间比较集中.而beta测试的环境是不受开发方控制的,谁也不知道用户如何折磨软件,用户数量相对比较多,时间不集中.一般地,alpha测试先于beta测试执行.通用的软

Alpha测试、Beta测试的区别?

Alpha测试也称开发方测试,是在用户组织模拟软件系统的运行环境下的一种验收测试,由用户或第三方测试公司进行的测试,模拟各类用户行为对即将面市的软件产品进行测试,试图发现并修改错误. Beta测试是内部测试之后的外部公开测试,用户公司组织各方面的典型终端用户在日常工作中实际使用beta版本,并要求用户报告异常情况,提出批评意见. 两者区别: 两者的主要区别是测试的场所不同. Alpha测试是指把用户请到开发方的场所来测试,Beta测试是指在一个或多个用户的场所进行的测试. Alpha测试的环境是

alpha测试和beta测试的区别

alpha测试版,有点相当于内部测试,一般开发人员在场   ,是由用户做测试,但开发人员在场,一般是请用户到开发现场去测试 beta测试版,完全交给用户,由用户做测试,返回测试报告,相当于发行前的一个版本 Alpha测试 在系统开发接近完成时对应用系统的测试:测试后仍然会有少量的设计变更.这种测试一般由最终用户或其它人员完成,不能由程序或测试员完成. Beta测试 当开发和测试根本完成时所做的测试,最终的错误和问题需要在最终发行前找到.这种测试一般由最终用户或其它人员完成,不能由程序员或测试员完

Alpha测试与Beta测试

粗略说一下Alpha测试与beta测试 1.Alpha测试 α测试是由一个用户在开发环境下进行的测试,也可以是公司内部的用户在模拟实际操作环境下进行的测试.α测试的目的是评价软件产品的功能.局域化.可使用性.可靠性.性能和支持.尤其注重产品的界面和特色.α测试可以从软件产品编码结束之时开始,或在模块(子系统)测试完成之后开始,也可以在确认测试过程中产品达到一定的稳定和可靠程度之后再开始. 简单来说α测试就是公司内部员工假装自己是各类用户,来进行使用,从而发现使用过程终会出现的问题,软件的表现.界

【Unity Shaders】Alpha Test和Alpha Blending

写在前面 关于alpha的问题一直是个比较容易摸不清头脑的事情,尤其是涉及到半透明问题的时候,总是不知道为什么A就遮挡了B,而B明明在A前面.这篇文章就总结一下我现在的认识~ Alpha Test和Alpha Blending是两种处理透明的方法. Alpha Test采用一种很霸道极端的机制,只要一个像素的alpha不满足条件,那么它就会被fragment shader舍弃,"我才不要你类!":否则,就会按正常方式写入到缓存中,并进行正常的深度检验等等,也就是说,Alpha Test

(转)【Unity Shaders】Alpha Test和Alpha Blending

转自:http://blog.csdn.net/candycat1992/article/details/41599167 写在前面 关于alpha的问题一直是个比较容易摸不清头脑的事情,尤其是涉及到半透明问题的时候,总是不知道为什么A就遮挡了B,而B明明在A前面.这篇文章就总结一下我现在的认识~ Alpha Test和Alpha Blending是两种处理透明的方法. Alpha Test采用一种很霸道极端的机制,只要一个像素的alpha不满足条件,那么它就会被fragment shader舍