原文: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因子

D3D11_BLEND_ZERO F = (0, 0, 0, 0)

D3D11_BLEND_ONE F = (1, 1, 1, 1)
D3D11_BLEND_SRC_COLOR F = (Rs , Gs , Bs)
D3D11_BLEND_INV_SRC_COLOR F = (1 – Rs ,1 – Gs ,1 - Bs)
D3D11_BLEND_SRC_ALPHA F = (Alphas , Alphas, Alphas ), 混合因子为源颜色的alpha值。
D3D11_BLEND_INV_SRC_ALPHA F = (1 - Alphas , 1 - Alphas, 1 - Alphas )
D3D11_BLEND_DEST_ALPHA F = (Alphad , Alphad , Alphad ), 混合因子为目的颜色的alpha值。
D3D11_BLEND_INV_DEST_ALPHA F = (1 - Alphad , 1 - Alphad , 1 - Alphad ),
D3D11_BLEND_DEST_COLOR F = (Rd , Gd , Bd)
D3D11_BLEND_INV_DEST_COLOR F = (1 – Rd ,1 – Gd ,1 – Bd)
D3D11_BLEND_SRC_ALPHA_SAT F = (Alpha’s , Alpha’s, Alpha’s ), Alpha’s  = clamp(Alphas , 0, 1)

     这儿还有一些其它的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

代码下载:

http://files.cnblogs.com/mikewolf2002/d3d1139-49.zip

http://files.cnblogs.com/mikewolf2002/pictures.zip

Directx11教程(44) alpha blend(1)的更多相关文章

  1. Directx11教程(47) alpha blend(4)-雾的实现

    原文:Directx11教程(47) alpha blend(4)-雾的实现      除了用来实现透明效果之外,我们还可以用alpha blend来实现雾(fog)的效果.通过逐渐清晰的雾气效果,可 ...

  2. Directx11教程(46) alpha blend(3)

    原文:Directx11教程(46) alpha blend(3)       现在我们尝试改变box的贴图,使用一张带alpha的dds文件wirefence.dds, 用directx textu ...

  3. Directx11教程(45) alpha blend(2)

    原文:Directx11教程(45) alpha blend(2)     在myTutorialD3D11_40中,我们在场景中再添加一个box,并把box放在水里,实现半透明的效果.如下图所示: ...

  4. Directx11教程(66) D3D11屏幕文本输出(1)

    原文:Directx11教程(66) D3D11屏幕文本输出(1)      在D3D10中,通过ID3DX10Font接口对象,我们可以方便的在屏幕上输出文字信息,一个DrawText函数就能解决所 ...

  5. Directx11教程(49) stencil的应用-镜面反射

    原文:Directx11教程(49) stencil的应用-镜面反射      本教程中,我们利用stencil来实现一个镜面反射效果. 1.首先我们要在D3DClass中增加几个成员变量及函数. I ...

  6. Directx11教程(18) D3D11管线(7)

    原文:Directx11教程(18) D3D11管线(7) 光栅化阶段(RS)之后,将进入PS/OM阶段. 参考外文资料:http://fgiesen.wordpress.com/2011/07/01 ...

  7. Directx11教程(57) 环境映射

    原文:Directx11教程(57) 环境映射       建好skydome后,如果我们想让其中的某个物体,比如那个球体来映射出周围环境的蓝天白云(不包括自己附近的物体),该怎么做呢?此时可以把这个 ...

  8. Directx11教程(54) 简单的基于GS的billboard实现

    原文:Directx11教程(54) 简单的基于GS的billboard实现     本章我们用一个billboard的实现来学习D3D11中的GS.     在VS shader中,我们输入的是顶点 ...

  9. Directx11教程(51) 简单的billboard

    原文:Directx11教程(51) 简单的billboard        billboard称作公告板,通常用一个quad(四边形)表示[有的billboard用两个正交的quad表示],它的特点 ...

随机推荐

  1. Delphi 设计模式:《HeadFirst设计模式》Delphi代码---工厂模式之抽象工厂[转]

     1  2 {<HeadFirst设计模式>工厂模式之抽象工厂 }  3 { 抽象工厂的产品                       }  4 { 编译工具:Delphi7.0     ...

  2. Delphi 设计模式:《HeadFirst设计模式》Delphi2007代码---组合模式之Menus[转]

     1  2{<HeadFirst设计模式>之组合模式 }  3{ 组合与单项的抽象父类           }  4{ 编译工具:Delphi2007 for win32}  5{ E-M ...

  3. MyBatis-Spring(五)--MapperScannerConfigurer实现增删改查

    上一篇文章中已经介绍,MapperScannerConfigurer可以通过扫描的方式获取我们需要的mapper,而不需要我们自己去配置,它的基本配置如下: <bean class=" ...

  4. 第15章 RMAN备份 ​

    第15章 RMAN备份 oracle推荐的备份工具是rman(恢复管理器:recovery manager),用操作系统命令执行的备份被称为用户管理的备份.使用rman执行的备份被称为服务器管理备份. ...

  5. c++ 链接mysql:error LNK2019: 无法解析的外部符号

    使用VS2012编译项目报错如下: error LNK2019: 无法解析的外部符号 _mysql_real_connect@32,该符号在函数 _main 中被引用 error LNK2019: 无 ...

  6. 初学linux时遇到的那些哭笑不得的问题

    1.终端中无法输入密码? 在终端输入密码,是不会在输入密码的时候看见星号或者圆点符号的.它不会有任何输入密码的视觉指示,也不会有任何光标移动,什么也不显示. 其实是输进去了,只是没有明文显示出来而已. ...

  7. 使用innerHTML属性向head中插入字符时报“无法设置 innerHTML 属性。 该操作的目标元件无效”的错误

    向head中动态插入script文件,代码如下: var sc = document.createElement("script"); sc.src = "//www.c ...

  8. PHP搜索优化 sphinx 实战

    环境:win7 64 wamp 解压sphinx安装包后,简历如下结构.注意,conf目录是我的配置文件目录 在conf目录下,简历newdefend.conf文件,配置内容如下 # 配置数据源 so ...

  9. vim 简明教程(转自飘过的小牛)

    vim的学习曲线相当的大(参看各种文本编辑器的学习曲线),所以,如果你一开始看到的是一大堆VIM的命令分类,你一定会对这个编辑器失去兴趣的.下面的文章翻译自<Learn Vim Progress ...

  10. win7开机启动项设置

    Windows系统自身就有启动项命令可以进行设置: 要说到修改启动项,当然首推Windows系统自带的“MSCONFIG”命令,XP等其他Windows系统用户使用方法是一模一样的. 1.点击“开始” ...