Directx11教程(44) alpha blend(1)
原文:Directx11教程(44) alpha blend(1)
我们知道,D3D11中按Frame来渲染物体,每个Frame中又可能包含若干个primitive,如下面的示意图所示:


gpu在实际渲染中,会按帧来渲染,比如上图frame0中,有两个primitive(三角形),经过vs以后,PA(primitive assemble) block会进行体元装配,然后进行光栅化操作,光栅化操作时候,会比较depth buffer的值。因为红色的三角形面的z值更小,所以它会覆盖黑色三角形一部分。
如果我们想要混合2个三角形的显示,该怎么做呢?这时就需要alpha blend操作,就是后缓冲中内容和当前ps输出的pixel颜色进行混合操作。使用alpha blend操作,我们可以实现透明等效果。
现在我们看看D3D11中alpha blend的实现原理:
1、混合方程

假定现在ps输出的像素颜色是Csrc = (Rs , Gs , Bs),后缓冲中的对应像素颜色值是Cdst = (Rd , Gd , Bd),
颜色Fsrc和Fdst称作源混合(blend)因子和目的混合(blend)因子,
表示颜色按分量相乘,
表示任意操作符,比如加法,减法等等。
通过方程计算后得到的C是最终的颜色值,它将覆盖后缓冲的像素颜色。
以上方程是对于RGB颜色来说的,对于alpha值也有相应的方程:

2、blend操作
混合方程中的
为下面的操作符之一:
typedef enum D3D11_BLEND_OP
{
D3D11_BLEND_OP_ADD = 1,
D3D11_BLEND_OP_SUBTRACT = 2,
D3D11_BLEND_OP_REV_SUBTRACT = 3,
D3D11_BLEND_OP_MIN = 4,
D3D11_BLEND_OP_MAX = 5,
} D3D11_BLEND_OP;
Constants
- D3D11_BLEND_OP_ADD
,把两个颜色加起来。 - D3D11_BLEND_OP_SUBTRACT
,Source1减去source2。 - D3D11_BLEND_OP_REV_SUBTRACT
,source2减去source1 - D3D11_BLEND_OP_MIN
取最小颜色值。 - D3D11_BLEND_OP_MAX
取最大颜色值。
3、blend因子
这儿还有一些其它的blend因子设置,具体请查看Directx的文档。需要注意的是对于alpha blend因子:结尾是_COLOR的不能使用。
4、blend状态
使用alpha blend之前,我们需要设置blend state,并enalbe它。
首先我们要填写一个D3D11_BLEND_DESC结构,然后调用CreateBlendState,就可以创建blend状态了。
重要的是我们要在MRT中设置blend因子以及操作方式等等。(一般是MRT[0],对应一个输出,如果使用多个MRT,可以设置不同blend因子或者操作方式)。
typedef struct D3D11_BLEND_DESC
{ BOOL AlphaToCoverageEnable;
BOOL IndependentBlendEnable;
D3D11_RENDER_TARGET_BLEND_DESC RenderTarget[8];
} D3D11_BLEND_DESC;
typedef struct D3D11_RENDER_TARGET_BLEND_DESC
{
BOOL BlendEnable;
D3D11_BLEND SrcBlend;
D3D11_BLEND DestBlend;
D3D11_BLEND_OP BlendOp;
D3D11_BLEND SrcBlendAlpha;
D3D11_BLEND DestBlendAlpha;
D3D11_BLEND_OP BlendOpAlpha;
UINT8 RenderTargetWriteMask;
} D3D11_RENDER_TARGET_BLEND_DESC;
现在我们修改myTutorialD3D11_38的代码,增加blend支持,使水有透明的效果。其实代码很简单,首先在D3DClass类中增加两个函数。
void D3DClass::TurnOnAlphaBlending()
{
float blendFactor[4];
// 设置blend因子
blendFactor[0] = 0.0f;
blendFactor[1] = 0.0f;
blendFactor[2] = 0.0f;
blendFactor[3] = 0.0f;
// 打开alpha blend
m_deviceContext->OMSetBlendState(m_alphaEnableBlendingState, blendFactor, 0xffffffff);
return;
}
void D3DClass::TurnOffAlphaBlending()
{
float blendFactor[4];
// 设置blend因子
blendFactor[0] = 0.0f;
blendFactor[1] = 0.0f;
blendFactor[2] = 0.0f;
blendFactor[3] = 0.0f;
// 关闭alpha blend
m_deviceContext->OMSetBlendState(m_alphaDisableBlendingState, blendFactor, 0xffffffff);
return;
}
我们还要在初始化函数中,创建两个blend状态,一个表示enable blend,一个表示disable blend。
D3D11_BLEND_DESC blendStateDescription;
…
// 初始化blend描述符
ZeroMemory(&blendStateDescription, sizeof(D3D11_BLEND_DESC));
// 创建一个alpha blend状态.
blendStateDescription.RenderTarget[0].BlendEnable = TRUE;
blendStateDescription.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendStateDescription.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blendStateDescription.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendStateDescription.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blendStateDescription.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blendStateDescription.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendStateDescription.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;//0x0f;
// 用描述符创建一个alpha blend状态
result = m_device->CreateBlendState(&blendStateDescription, &m_alphaEnableBlendingState);
if(FAILED(result))
{
return false;
}
//修改描述符.
blendStateDescription.RenderTarget[0].BlendEnable = FALSE;
//创建一个新的blend状态.
result = m_device->CreateBlendState(&blendStateDescription, &m_alphaDisableBlendingState);
在GraphicsClass类中,渲染水时,打开alpha blend
// 打开alpha blend.
m_D3D->TurnOnAlphaBlending();
// 把模型顶点和索引缓冲放入管线,准备渲染.
m_WaterModel->Render(m_D3D->GetDeviceContext());
result = m_LightTexShader->Render(m_D3D->GetDeviceContext(), m_WaterModel->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix,
light, material, camera,m_TexManager->createTex(m_D3D->GetDevice(),string("water2.dds")));
if(!result)
{
return false;
}
// 关闭alpha blend.
m_D3D->TurnOffAlphaBlending();
最后一点就是在lighttex.ps中做小小的改动,
float4 finalcolor1;
finalcolor1 = float4(finalcolor.xyz,0.5);
return finalcolor1;
这是因为我们的混合因子都是来自于alpha值
blendStateDescription.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendStateDescription.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
程序最终执行效果如下:

完整的代码请参考:
工程文件myTutorialD3D11_39
代码下载:
Directx11教程(44) alpha blend(1)的更多相关文章
- Directx11教程(47) alpha blend(4)-雾的实现
原文:Directx11教程(47) alpha blend(4)-雾的实现 除了用来实现透明效果之外,我们还可以用alpha blend来实现雾(fog)的效果.通过逐渐清晰的雾气效果,可 ...
- Directx11教程(46) alpha blend(3)
原文:Directx11教程(46) alpha blend(3) 现在我们尝试改变box的贴图,使用一张带alpha的dds文件wirefence.dds, 用directx textu ...
- Directx11教程(45) alpha blend(2)
原文:Directx11教程(45) alpha blend(2) 在myTutorialD3D11_40中,我们在场景中再添加一个box,并把box放在水里,实现半透明的效果.如下图所示: ...
- Directx11教程(66) D3D11屏幕文本输出(1)
原文:Directx11教程(66) D3D11屏幕文本输出(1) 在D3D10中,通过ID3DX10Font接口对象,我们可以方便的在屏幕上输出文字信息,一个DrawText函数就能解决所 ...
- Directx11教程(49) stencil的应用-镜面反射
原文:Directx11教程(49) stencil的应用-镜面反射 本教程中,我们利用stencil来实现一个镜面反射效果. 1.首先我们要在D3DClass中增加几个成员变量及函数. I ...
- Directx11教程(18) D3D11管线(7)
原文:Directx11教程(18) D3D11管线(7) 光栅化阶段(RS)之后,将进入PS/OM阶段. 参考外文资料:http://fgiesen.wordpress.com/2011/07/01 ...
- Directx11教程(57) 环境映射
原文:Directx11教程(57) 环境映射 建好skydome后,如果我们想让其中的某个物体,比如那个球体来映射出周围环境的蓝天白云(不包括自己附近的物体),该怎么做呢?此时可以把这个 ...
- Directx11教程(54) 简单的基于GS的billboard实现
原文:Directx11教程(54) 简单的基于GS的billboard实现 本章我们用一个billboard的实现来学习D3D11中的GS. 在VS shader中,我们输入的是顶点 ...
- Directx11教程(51) 简单的billboard
原文:Directx11教程(51) 简单的billboard billboard称作公告板,通常用一个quad(四边形)表示[有的billboard用两个正交的quad表示],它的特点 ...
随机推荐
- bootstrap字体图标在IE上不显示
最简单的办法就是直接下载最新的bootstrap.css替换掉旧的. 但是由于我做的项目直接替换会出现样式冲突问题,因此只好慢慢找是什么属性导致图标不显示,最后找到了解决办法: 1.首先保字体文件的位 ...
- autoreleasing的用法介绍:
在c/c++,objective-c内存管理中有一条是:谁分配谁释放. __autoreleasing则可以使对像延迟释放.比如你想传一个未初始化地对像引用到一个方法当中,在此方法中实始化此对像,那么 ...
- phpStrom编辑器 通过 git 提交代码到 gitlab
前提: 1.已经成功安装 git: 2.将 phpstrom 和 gitlab 连接起来.参考此文章 一.在 phpstrom 中打开需要推送的项目 二.将 ‘工作区’ 代码 添加到 ‘暂存区’ 三. ...
- Java 线程池 +生产者消费者+MySQL读取300 万条数据
1.1需求 数据库300 万条用户数据 ,遍历获取所有用户, 各种组合关联, 获取到一个新的json ,存到redis 上. 1.2 难点 数据库比较多, 不可能单线程查询所有的数据到内存. 1.3解 ...
- python3没有了xrange
升级到python3的同学应该会注意到以前经常用的xrange没了! 是的,python3的range就是xrange.直接看效果! Python 2.7.13 (v2.7.13:a06454b1 ...
- 跟我一起做一个vue的小项目(四)
接下来我们进行的是轮播页面下面的导航页的开发 我们需要的是实现轮播页下面的图标,并且实现轮播效果 这个话,其实基本思路先是渲染出小图标,然后,我们要对页数进行判断,如果图标的个数展示的就是8个,那个这 ...
- Echarts 的简单使用
http://echarts.baidu.com/index.html 直接用script引入从官网下载的echarts.js文件 官网的文件有几种版本的,按需下载即可,注意精简版的只显示折线.圆柱等 ...
- JS 重载页面,本地刷新,返回上一页
JS 重载页面,本地刷新,返回上一页 : <a href="javascript:history.go(-1)">返回上一页</a> <a href= ...
- Spring AOP(转)
原文:Spring实现AOP的4种方式 Spring AOP 详解 Spring实现AOP的4种方式 先了解AOP的相关术语:1.通知(Advice):通知定义了切面是什么以及何时使用.描述了切面要完 ...
- 神奇的CSS形状
在StackOverflow上有这么一个问题,有位同学在 http://css-tricks.com/examples/ShapesOfCSS/ 找到一些使用CSS做的形状,其中一位同学对下面的这个形 ...