引入

(1)上篇中学习了Alpha混合技术,其中涉及到顶点Alpha和材质Alpha两种。但是Alpha还有一种来源就是纹理(Texture)。另外,通过借助纹理的Alpha值,可以实现纹理的透明效果,这让游戏世界变得更有趣、更逼真!
(2)然而,这里虽然仍是学习Alpha混合,但是涉及到的是纹理Alpha的混合方式,这使得Alpha混合变得不再单纯,并且更加复杂!因为纹理就是一个尤其复杂的主题,想想最多可以设置8个纹理层就能感受的到,仅纹理的渲染状态的选择就够让我们手忙脚乱的,可选的枚举值大概有二十个。所以这里我们先初步了解纹理Alpha混合的使用,更复杂的内容将在后续文章中逐步展开。

Texture Alpha混合中像素Alpha值的形成

当对物体表面使用了纹理之后,像素Alpha值就是纹理Alpha混合之后的值,所以这又取决于纹理的Alpha混合方法,纹理Alpha混合方法决定了纹理Alpha混合之后的Alpha值是取自材料还是取自纹理,或者取自两者的某种运算。
像素的Alpha值的具体计算过程是这样的,首先得到顶点Alpha值,顶点Alpha值可能是直接指定的,也可能是光照计算得到的,然后根据着色模式对顶点Alpha值进行插值,得到的结果再根据纹理Alpha混合方法和纹理采样得到的Alpha值进行指定的运算,得到最终每个像素的Alpha的值。其中,纹理的混合方法与之前纹理颜色的混合方法基本相同,区别是纹理Alpha混合的结果是像素的Alpha值,纹理颜色混合的结果是像素颜色的RGB值。

“纹理阶段混合状态”

纹理映射本质上是从纹理中获取颜色值,然后应用到物体的表面,多层纹理映射本质上就是混合多层纹理的颜色,然后应用到物体的表面。为了处理上的方便,Direct3D将颜色的RGB通道和Alpha通道分别进行处理,具体的操作方法通过纹理阶段混合状态进行设置。也即纹理阶段混合状态用于指定当前纹理阶段(总共有八个阶段,即Stage0到Stage7)纹理颜色值和Alpha值的混合方法。
由于纹理混合对RGB颜色值混合和Alpha值混合是分别处理的,所以本节只讨论纹理的Alpha值混合,RGB颜色值混合在之后的文章中介绍,并且本节中只涉及1层(即第0层)纹理,所以相对好理解的多!
我们分几个步骤来介绍“纹理阶段混合状态”的设置方法:

(1)LPDIRECT3DDEVICE9::SetTextureStageState()函数的使用
(2)设置纹理渲染状态
(3)设置纹理渲染状态值
(4)“纹理混合状态”与纹理的Alpha混合

(1)LPDIRECT3DDEVICE9::SetTextureStageState()函数的使用
纹理混合状态由LPDIRECT3DDEVICE9::SetTextureStageState()设置,该函数的声明如下:

HRESULT SetTextureStageState() {DWORD Stage,D3DTEXTURESTAGESTATETYPE Type,DWORD Value
};


(2)设置纹理渲染状态
渲染状态是上面函数的第二个参数,通过设置渲染状态可以控制纹理的混合模式,如指定纹理颜色值的混合方法还是Alpha值的混合方法;也可以设置相关混合的参数,如指定Alpha值混合的第一个参数(Arg1)和第二个参数(Arg2)。
枚举类型D3DTEXTURESTAGESTATETYPE的定义为:

下面是枚举类型D3DTEXTURESTAGESTATETYPE的详细说明:

不要为此感到惊讶,毕竟最多可以有八层纹理!虽然有如此众多的可选项,但是还记的我们本节的主题吗,我们关心的纹理Alpha值的混合状态设置,为此我们只设置D3DTSS_ALPHAOP、D3DTSS_ALPHAARG1和D3DTSS_ALPHAARG2即可。下面我们来详细介绍一下这三个选项。

(1)D3DTSS_ALPHAOP的含义是:指定纹理层Alpha值混合方法,Vlaue值属于D3DTEXTUREOP枚举类型。
(2)D3DTSS_ALPHAARG1的含义是:Alpha混合的第一个参数,Value属于D3DTA类型常量默认为D3DTA_TEXTURE,即纹理Alpha值
(3)D3DTSS_ALPHAARG2的含义是:Alpha混合的第二个参数,Value属于D3DTA类型常量,默认为D3DTA_CURRENT,即前一个纹理层的输出Alpha值,当Stage=0时,Value值为D3DTA_DIFFUSE,即像素的漫反射Alpha值
解释:
通过这三个参数,我们指定了一个纹理Alpha混合的公式:

即括号中的两个参数通过指定的运算来得出当前阶段纹理的Alpha,然后传给下一个阶段,并将最终的Alpha值表现到显示器上。

剩下的就是设置这些选项的值了,接下来我们只介绍本节中我们使用到的3个选项的值的设定。
(3)设置纹理渲染状态值
我们的任务是设置3个与纹理Alpha混合相关选项的值,再重复一遍,分别是:D3DTSS_ALPHAOP,D3DTSS_ALPHAARG1和D3DTSS_ALPHAARG2。
通过上面的表格,我们知道D3DTSS_ALPHAOP的值取自D3DTEXTUREOP枚举值,下面是D3DTEXTUREOP的定义:

这仅供欣赏,具体的注释及含义可以查看源码文件和官方手册。我们本节实例示例中使用的相关设置是:

运算方式,我们选择了D3DTOP_MODULATE,它的含义是:

即将所提供的两个参数的Alpha值相乘;第一个参数我们设置为D3DTA_TEXTURE,即指定其Alpha值来源于纹理;第二个参数我们设置为D3DTA_DIFFUSE,即像素的漫反射颜色值。其实此处只有一个纹理阶段(即Stage0),即使我们不显式的指定,默认值也是像素的漫反Alpha值。
(4)“纹理混合状态”与纹理的Alpha混合
现在让我们总结一下我们为了实现纹理Alpha混合,我们对纹理阶段混合状态做了什么:首先,我们指定了纹理Alpha混合的操作方式是两个参数相乘,并且给了操作方式两个参数,又因为纹理可能有多级,这成为了我们设置这两个参数的依据。通过这些设置我们便告诉了Direct3D在进行纹理Alpha混合的时候应该怎么做,又应该从哪里取得Alpha值。


即使搞不清楚上面的那些可选项的设置方法和具体含义我们依旧可以在程序中使用纹理的Alpha混合,毕竟这只涉及到纹理混合的一小部分。下面通过一个示例来理解纹理Alpha混合的工作过程。

示例三——纹理Alpha

(1)运行结果

(2)What’s this?
看到运行结果,你可能会有些疑惑,程序是怎样体现出纹理Alpha混合的呢?
首先,我们准备了一幅精灵的图片,这张图片的格式值得我们注意,可以通过DirectX中的DxTex工具查看(相对路径为Microsoft DirectX SDK (June 2010)\Utilities\bin\x64):

从工具中可以看出,这是一幅颜色格式为32位的图像,RGBA每个通道各占8位,我们需要注意的是,这张图片是包含Alpha通道的,这很重要!因为只有纹理中包含Alpha通道,才存在纹理Alpha混合的概念。
另外,让我们打开图片的另一个视图(工具的View->Alpha Channel Only):

这个视图是只保留了Alpha通道。上图中的结果意味着什么?黑色部分代表Alpha值为0,即全透明;白色的部分代表Alpha值为1,表示完全不透明。那Alpha值只能非0即1吗?当然不是:

我们把另一张图片的Alpha通道与所用精灵图片进行对比,可以知道右边图片中的Alpha值是从四周向圆心递增的。
(3)程序效果产生的原因!
从上面的分析,我们得知了精灵图片中:那个飞机图案的alpha值是1,而四周也就是背景的alpha值是0。这意味着,在进行纹理alpha值混合的时候,背景处的alpha值依次与顶点的alpha值和后台缓冲区中的alpha值混合(乘积)都是0,即完全透明;而飞机图案alpha=1而完全不透明。最终在打开和关闭纹理混合的时候,呈现出运行中的效果。
(4)关键代码
有关渲染状态的设置:

//设置渲染状态g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);    g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);    

从文件中加载纹理:

//创建纹理对象if (FAILED(D3DXCreateTextureFromFile(g_pd3dDevice, "images/plane5.png", &g_pTexture))) {MessageBox(NULL, "fail to create texture.", "error", MB_OK);return E_FAIL;}

场景渲染:

//开始渲染图形if (SUCCEEDED(g_pd3dDevice->BeginScene())) {g_pd3dDevice->SetTexture(0, g_pTexture);g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);g_pd3dDevice->EndScene();}

源码下载

链接:https://pan.baidu.com/s/1HCOIeY-_Ai2hfnEGDzPzYA 密码:dxao

有关纹理渲染状态的设置是一个庞大并且复杂的主题,在以后的文章中还会接触和学习。通过这个小例子可以看出纹理alpha混合可以很好的制作出透明精灵的效果,在2D游戏中也有广泛的应用。

8.3 初步理解 Texture Alpha相关推荐

  1. Hamiltonian Monte Carlo抽样算法的初步理解

    Hamiltonian Monte Carlo抽样算法的初步理解 接受拒绝采样算法 MCMC回顾 Hamiltonian dynamics 拉格朗日方程 从牛顿方程出发推导拉格朗日方程 勒让德变换 哈 ...

  2. 如何让人大致理解RxJava思想:第一节 初步理解RxJava

    如何让人大致理解RxJava思想:第一节 初步理解RxJava 首先,我们需要明确,一个人不可能一口气吃成一个胖子,你不可能仅仅花5分钟看完我这篇文章,然后一拍桌子,大叫一声,我知道了,然后赢取白富美 ...

  3. CSharpGL(29)初步封装Texture和Framebuffer

    +BIT祝威+悄悄在此留下版了个权的信息说: CSharpGL(29)初步封装Texture和Framebuffer +BIT祝威+悄悄在此留下版了个权的信息说: Texture和Framebuffe ...

  4. JAVA 枚举类的初步理解

    JAVA 枚举类的初步理解 现在Java的枚举类在真实项目中已经用的比较频繁,比静态常量更好用,也更有限定性,enum类可以用来表示有限的类对象,比如星期.月份.性别或者项目中的产品类型 像诸如此类的 ...

  5. 非常易于理解‘类'与'对象’ 间 属性 引用关系,暨《Python 中的引用和类属性的初步理解》读后感...

    关键字:名称,名称空间,引用,指针,指针类型的指针(即指向指针的指针) 我读完后的理解总结: 1. 我们知道,python中的变量的赋值操作,变量其实就是一个名称name,赋值就是将name引用到一个 ...

  6. 初步理解pagerank算法

    初步理解pagerank算法 第一次写不是课程要求的博客,可能有不严谨的地方,如果有写错的希望能在评论区指出. 算法思想 pagerank算法用于网页排序,根据给网页的重要程度给各个网页打分,根据分数 ...

  7. Adaboost算法的初步理解

    菜鸟初次接触Adaboost,虽然算法流程比较清晰简单,但对于其中的理论,存在着不少疑惑之处,如下所示: 1)如何训练得到的弱分类器,我们需要训练出多少个弱分类器进行后续的计算?对若分类器有什么要求吗 ...

  8. 我对SNS游戏的初步理解

    国庆期间,我专门研究了一款SNS游戏,巴别小精灵,这是一款背单词的游戏.算是一款交互式英语学习的应用.一点初步理解和体会,与大家分享. SNS游戏的特点 (1)      异步性 (2)      真 ...

  9. 红黑树插入操作的初步理解

    红黑树插入操作的初步理解 文章目录 红黑树插入操作的初步理解 红黑树的特征 红黑树的插入节点总是红色的 红黑树的修正 变色 左旋 右旋 插入操作 插入操作的代码实现 红黑树和AVL树的对比 参考链接 ...

  10. wmts格式说明_WMTS服务初步理解与读取

    WMTS 服务初步理解与读取 当前在网络地图服务中,大部分都会采取缓存技术来替代实时对数据进行可视化,用以提高地图响应能 力.介绍 OGC 提出的缓存技术标准的 WMTS 服务. WMTS 简介 WM ...

最新文章

  1. mysql @value := 用法
  2. mac电脑抹掉数据要多久_macbook怎么抹掉所有的数据?
  3. php绘制历史曲线,thinkphp浏览历史功能实现方法
  4. 使用tensorflow书写逻辑回归
  5. java实训 :异常(try-catch执行顺序与自定义异常)
  6. javase哪部分最难_高中物理哪部分最难?这里有答案和方法!一定要收藏
  7. dockerfile 创建Jenkins镜像
  8. java源代码1000_Java源代码
  9. ROS系统学习8---节点间的内存共享(初级篇)
  10. 弹力弹珠java_Java趣味小程序:打弹珠
  11. 微服务--应对每秒上万并发下的参数优化实战(实战经验)
  12. Unity Shader (Wave Trail)波追踪效果(一)
  13. 大数据(0b)离线数据仓库
  14. jq 清空、删除、添加、替换数组的简单用法
  15. 信息用短信服务器发送什么意思,已用短信息服务发送是什么意思
  16. PADS 快捷命令(无模指令)
  17. Pulmonary--Detection2
  18. python输入十个学生的成绩、判断优良中差并计算人数_大数据基础习题(1)
  19. mybatis association select 性能分析
  20. mysql解决不可重复读_mysql怎么解决不可重复读

热门文章

  1. 首行缩进,文字之间的间距
  2. 计算机玩游戏黑屏的原因,为什么电脑玩一会游戏就黑屏,这是为什么??????...
  3. bert tensorflow2 serving部署
  4. java分享微博_java_java实现的新浪微博分享代码实例,weibo.java {@link IWeiboShareAPI#handle - phpStudy...
  5. 当RPM包安装遇上“依赖性”问题时的解决办法
  6. Apple HomeKit
  7. 三大特殊类(String Object 包装类)与异常
  8. mysql 告警日志_错误日志监控报警脚本
  9. c语言编程仓鼠吃豆子,动态规划之仓鼠吃豆子 - osc_8quu62cg的个人空间 - OSCHINA - 中文开源技术交流社区...
  10. Creator动态获取,数据文,JSON并使用,枚举Enum,cc.sys.localStorage获取音效的判断 ,冒泡排序做排行榜 ,动态获取提示(cc.loader.loadRes),制作签到