六狼论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博账号登陆

只需一步,快速开始

搜索
查看: 354|回复: 0

Directx11教程(44) alpha blend(1)

[复制链接]

升级  91.33%

154

主题

154

主题

154

主题

举人

Rank: 3Rank: 3

积分
474
 楼主| 发表于 2012-12-30 11:52:06 | 显示全部楼层 |阅读模式
Directx11教程(44) alpha blend(1)

<div class="postbody"><div id="cnblogs_post_body">   我们知道,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

<a name="D3D11_BLEND_OP_ADD">D3D11_BLEND_OP_ADD  ,把两个颜色加起来。D3D11_BLEND_OP_SUBTRACT <a href="http://images.cnblogs.com/cnblogs_com/mikewolf2002/201205/201205110728358286.png">,Source1减去source2。D3D11_BLEND_OP_REV_SUBTRACT <a href="http://images.cnblogs.com/cnblogs_com/mikewolf2002/201205/201205110728353553.png">,source2减去source1D3D11_BLEND_OP_MIN <a href="http://images.cnblogs.com/cnblogs_com/mikewolf2002/201205/201205110728369583.png"> 取最小颜色值。D3D11_BLEND_OP_MAX <a href="http://images.cnblogs.com/cnblogs_com/mikewolf2002/201205/201205110728375613.png">取最大颜色值。
     3、blend因子
D3D11_BLEND_ZERO F = (0, 0, 0, 0)  <a name="D3D11_BLEND_ONE">D3D11_BLEND_ONE F = (1, 1, 1, 1)D3D11_BLEND_SRC_COLOR F = (Rs , Gs , Bs)<a name="D3D11_BLEND_INV_SRC_COLOR">D3D11_BLEND_INV_SRC_COLOR F = (1 – Rs ,1 – Gs ,1 - Bs)D3D11_BLEND_SRC_ALPHA F = (Alphas , Alphas, Alphas ), 混合因子为源颜色的alpha值。<a name="D3D11_BLEND_INV_SRC_ALPHA">D3D11_BLEND_INV_SRC_ALPHA F = (1 - Alphas , 1 - Alphas, 1 - Alphas )D3D11_BLEND_DEST_ALPHA F = (Alphad , Alphad , Alphad ), 混合因子为目的颜色的alpha值。<a name="D3D11_BLEND_INV_DEST_ALPHA">D3D11_BLEND_INV_DEST_ALPHA F = (1 - Alphad , 1 - Alphad , 1 - Alphad ), D3D11_BLEND_DEST_COLOR F = (Rd , Gd , Bd)<a name="D3D11_BLEND_INV_DEST_COLOR">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)<a href="http://images.cnblogs.com/cnblogs_com/mikewolf2002/201205/201205110728384368.png">        这儿还有一些其它的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
您需要登录后才可以回帖 登录 | 立即注册 新浪微博账号登陆

本版积分规则

快速回复 返回顶部 返回列表