今天我们学习一下如何给图元增加一点混合效果,这样看起来会更透明。

混合等式

D3D中的混合效果和把render target上的像素与在它之前的透明图元用混合等式执行像素融合

(FC) - Final Color
(SP) - Source Pixel
(DP) - Destination Pixel
(SBF) - Source Blend Factor
(DBF) - Destination Blend Factor
(FA) - Final Alpha
(SA) - Source Alpha
(DA) - Destination Alpha
(+) - Binaray Operator described below
(X) - Cross Multiply Matrices

D3D主要使用两种不同的等式,一个是针对颜色,一个是针对透明度(alpha),我们可以同时处理这两个不同的等式实现效果。

(FC) = (SP) (X) (SBF) (+) (DP) (X) (DPF)(FA) = (SA)(SBF) (+) (DA)(DBF)

The binary (+) operator can be one of the following:

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;

SBF和DBF混合因子是D3D11_BLEND枚举值类型。

typedef enum D3D11_BLEND {D3D11_BLEND_ZERO               = 1,D3D11_BLEND_ONE                = 2,D3D11_BLEND_SRC_COLOR          = 3,D3D11_BLEND_INV_SRC_COLOR      = 4,D3D11_BLEND_SRC_ALPHA          = 5,D3D11_BLEND_INV_SRC_ALPHA      = 6,D3D11_BLEND_DEST_ALPHA         = 7,D3D11_BLEND_INV_DEST_ALPHA     = 8,D3D11_BLEND_DEST_COLOR         = 9,D3D11_BLEND_INV_DEST_COLOR     = 10,D3D11_BLEND_SRC_ALPHA_SAT      = 11,D3D11_BLEND_BLEND_FACTOR       = 14,D3D11_BLEND_INV_BLEND_FACTOR   = 15,D3D11_BLEND_SRC1_COLOR         = 16,D3D11_BLEND_INV_SRC1_COLOR     = 17,D3D11_BLEND_SRC1_ALPHA         = 18,D3D11_BLEND_INV_SRC1_ALPHA     = 19
} D3D11_BLEND;

D3D11_BLEND_ZERO - 数据是黑色

D3D11_BLEND_ONE - 数据是白色

D3D11_BLEND_SRC_COLOR - 数据来源于PS着色器中的RGB(PS中的数据,就是混合等式中被添加的部分)

D3D11_BLEND_INV_SRC_COLOR - 数据来源于PS着色器中的RGB,但是有预处理,结果为1-RGB

D3D11_BLEND_SRC_ALPHA - 数据为PS中的A值

D3D11_BLEND_INV_SRC_ALPHA - PS中的1-A值

D3D11_BLEND_DEST_ALPHA - 数据来自已经存在render target上的A值

D3D11_BLEND_INV_DEST_ALPHA - 数据来自已经存在render target上的1-A值

D3D11_BLEND_DEST_COLOR  - 数据来自已经存在render target上的RGB值

D3D11_BLEND_INV_DEST_COLOR -  数据来自已经存在render target上的1- RGB值

D3D11_BLEND_SRC_ALPHA_SAT  - 数据来自源于PS着色器中的A,但是blend操作会把数据缩小到1及以下

D3D11_BLEND_BLEND_FACTOR - 数据来源于ID3D10Device::OMSetBlendState函数中设置的belnd factor

D3D11_BLEND_INV_BLEND_FACTOR -同上,结果为1-factor

D3D11_BLEND_SRC1_COLOR - 两个数据都是由PS产生,这个操作支持两个源数据颜色混合,而不是把一个PS上的数据与rendertarget混合

D3D11_BLEND_INV_SRC1_COLOR - 同上,结果为1-RGB

D3D11_BLEND_SRC1_ALPHA - 同上结果为A

D3D11_BLEND_INV_SRC1_ALPHA - 同上,结果为1-A

了解了混合等式之后,我们就要创建我们的混合描述信息了

typedef struct D3D11_BLEND_DESC {BOOL                           AlphaToCoverageEnable;BOOL                           IndependentBlendEnable;D3D11_RENDER_TARGET_BLEND_DESC RenderTarget[8];
} D3D11_BLEND_DESC;

AlphaToCoverageEnable  - 多重采样在这里很有用,现在只是将它设为true

IndependentBlendEnable - 我们能够一次和多个render target进行混合,最多为8个,设为false默认与第一个进行混合

RenderTarget[8] - 数组中的每一个结构体都是一个对render target 的blending描述

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;

BlendEnable - 是否能进行混合

SrcBlend  - 等式中的SBF,可以设为D3D11_BLEND 中的一个

DestBlend - DBF,同上

BlendOpD3D11_BLEND_OP 枚举值

SrcBlendAlpha - SBF(alpha channel),D3D11_BLEND 枚举值

DestBlendAlpha - DBF,同上

BlendOpAlpha  - 这里我们设为D3D10_BLEND_OP 枚举值

RenderTargetWriteMask - 指定要混合的channel

typedef enum D3D11_COLOR_WRITE_ENABLE {D3D11_COLOR_WRITE_ENABLE_RED     = 1,D3D11_COLOR_WRITE_ENABLE_GREEN   = 2,D3D11_COLOR_WRITE_ENABLE_BLUE    = 4,D3D11_COLOR_WRITE_ENABLE_ALPHA   = 8,D3D11_COLOR_WRITE_ENABLE_ALL     = ( D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN |  D3D11_COLOR_WRITE_ENABLE_BLUE | D3D11_COLOR_WRITE_ENABLE_ALPHA )
} D3D11_COLOR_WRITE_ENABLE;

Transparent Object's Depth Order.

当我们想要看到一个透明物体的背面的时候,我们可能会遇到一点问题。

当我们执行blend的时候,我们先假设此时render target上已经存在像素(被渲染好的物体)了。

先渲染不透明的物体,再渲染透明的物体,这一点很重要,下面就是我们的问题

eg:当我们第一次渲染框时,绕第二个盒子运行的第一个盒子开始于第二个盒子之后,并在代码中首先渲染。因此,当渲染第二个盒子时,它能够与第一个盒子混合,因为第一个盒子已经在渲染目标上。但是,当第一个盒子围绕第二个盒子旋转,并且位于第二个盒子的前面时,它将不会与第二个盒子混合

为了解决这个问题,我们需要每帧都计算物体到相机的距离,来决定先渲染哪个物体

除此之外,我们还有一些其他的问题,D3D是默认裁剪掉逆时针的平面,也就是说,当一个三角形面对摄像机是逆时针绘制的,即不可见。所以我们一般看不到背面,所以当绘制了Box的前面的时候,就不能和背面进行混合,因为背面其实看不到。

如果我们更改裁剪顺序,也不能满足我们的问题,此外,如果同一个box的一个距离相机更近的面先被绘制,他们就不能和其他面进行混合。所以一个box的面有时候不透明,有时候不可见

为了解决上面这个问题,我们需要绘制box两次,这样我们就能看的到背面,并且绘制前面的时候,背面已经在render target上了

首先我们要创建两个render states,一个顺时针,一个逆时针。

然后我们先用逆时针绘制一遍,因为我们的面试顺时针的,这样就能把box内部的面绘制出来(从里面看是逆时针的)

上述问题搞定了之后,我们开始写本节的代码

Global Declarations

ID3D11BlendState* Transparency;
ID3D11RasterizerState* CCWcullMode;
ID3D11RasterizerState* CWcullMode;

Clean Up

别忘了删除指针

    Transparency->Release();CCWcullMode->Release();CWcullMode->Release();

The Blending Equation

首先我们要创建render target blending desc,然后创建blend desc(结构太多,要看仔细,不然容易搞混)

D3D11_BLEND_DESC blendDesc;
ZeroMemory( &blendDesc, sizeof(blendDesc) );D3D11_RENDER_TARGET_BLEND_DESC rtbd;
ZeroMemory( &rtbd, sizeof(rtbd) );rtbd.BlendEnable             = true;
rtbd.SrcBlend                 = D3D11_BLEND_SRC_COLOR;
rtbd.DestBlend                 = D3D11_BLEND_BLEND_FACTOR;
rtbd.BlendOp                 = D3D11_BLEND_OP_ADD;
rtbd.SrcBlendAlpha             = D3D11_BLEND_ONE;
rtbd.DestBlendAlpha             = D3D11_BLEND_ZERO;
rtbd.BlendOpAlpha             = D3D11_BLEND_OP_ADD;
rtbd.RenderTargetWriteMask     = D3D10_COLOR_WRITE_ENABLE_ALL;blendDesc.AlphaToCoverageEnable = false;
blendDesc.RenderTarget[0] = rtbd;d3d11Device->CreateBlendState(&blendDesc, &Transparency);

CW & CCW Culling

为了绘制两遍,我们要创建两个RSstate

这部分的内容我们之前已经讲过一些

D3D11_RASTERIZER_DESC cmdesc;
ZeroMemory(&cmdesc, sizeof(D3D11_RASTERIZER_DESC));cmdesc.FillMode = D3D11_FILL_SOLID;
cmdesc.CullMode = D3D11_CULL_BACK;cmdesc.FrontCounterClockwise = true;
hr = d3d11Device->CreateRasterizerState(&cmdesc, &CCWcullMode);cmdesc.FrontCounterClockwise = false;
hr = d3d11Device->CreateRasterizerState(&cmdesc, &CWcullMode);

DrawScene() Function

最后就是利用blend等式和创建好的RS state来进行绘制啦,别忘了实时计算物体到相机的位置

void DrawScene()
{//Clear our backbufferfloat bgColor[4] = {(0.0f, 0.0f, 0.0f, 0.0f)};d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor);//Refresh the Depth/Stencil viewd3d11DevCon->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0);///**************new**************//"fine-tune" the blending equationfloat blendFactor[] = {0.75f, 0.75f, 0.75f, 1.0f};//Set the default blend state (no blending) for opaque objectsd3d11DevCon->OMSetBlendState(0, 0, 0xffffffff);//Render opaque objects////Set the blend state for transparent objectsd3d11DevCon->OMSetBlendState(Transparency, blendFactor, 0xffffffff);//*****Transparency Depth Ordering*****////Find which transparent object is further from the camera//So we can render the objects in depth order to the render target//Find distance from first cube to cameraXMVECTOR cubePos = XMVectorZero();cubePos = XMVector3TransformCoord(cubePos, cube1World);float distX = XMVectorGetX(cubePos) - XMVectorGetX(camPosition);float distY = XMVectorGetY(cubePos) - XMVectorGetY(camPosition);float distZ = XMVectorGetZ(cubePos) - XMVectorGetZ(camPosition);float cube1Dist = distX*distX + distY*distY + distZ*distZ;//Find distance from second cube to cameracubePos = XMVectorZero();cubePos = XMVector3TransformCoord(cubePos, cube2World);distX = XMVectorGetX(cubePos) - XMVectorGetX(camPosition);distY = XMVectorGetY(cubePos) - XMVectorGetY(camPosition);distZ = XMVectorGetZ(cubePos) - XMVectorGetZ(camPosition);float cube2Dist = distX*distX + distY*distY + distZ*distZ;//If the first cubes distance is less than the second cubesif(cube1Dist < cube2Dist){//Switch the order in which the cubes are drawnXMMATRIX tempMatrix = cube1World;cube1World = cube2World;cube2World = tempMatrix;}///**************new**************//Set the WVP matrix and send it to the constant buffer in effect fileWVP = cube1World * camView * camProjection;cbPerObj.WVP = XMMatrixTranspose(WVP);    d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture );d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState );///**************new**************//Counter clockwise culling first because we need the back side of//the cube to be rendered first, so the front side can blend with itd3d11DevCon->RSSetState(CCWcullMode);///**************new**************//Draw the first cubed3d11DevCon->DrawIndexed( 36, 0, 0 );///**************new**************d3d11DevCon->RSSetState(CWcullMode);d3d11DevCon->DrawIndexed( 36, 0, 0 );///**************new**************WVP = cube2World * camView * camProjection;cbPerObj.WVP = XMMatrixTranspose(WVP);    d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture );d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState );///**************new**************d3d11DevCon->RSSetState(CCWcullMode);///**************new**************//Draw the second cubed3d11DevCon->DrawIndexed( 36, 0, 0 );///**************new**************d3d11DevCon->RSSetState(CWcullMode);d3d11DevCon->DrawIndexed( 36, 0, 0 );///**************new**************//Present the backbuffer to the screenSwapChain->Present(0, 0);
}

本节内容就到这里拉。

本节内容代码可以在我的Github找到

游戏开发路途遥远,但我相信只要坚持,总能到达彼岸!

如果我的文章对于你学习DirectX11有点帮助,欢迎评论给出建议,让我们一起学习进步!

———————— 小明 2018.12.4 11.56

【DirectX11】【学习笔记(10)】混合相关推荐

  1. Directx11学习笔记【二】 将HelloWin封装成类

    我们把上一个教程的代码封装到一个类中来方便以后的使用. 首先新建一个空工程叫做MyHelloWin,添加一个main.cpp文件,然后新建一个类叫做MyWindow,将于窗体有关的操作封装到里面 My ...

  2. thinkphp学习笔记10—看不懂的路由规则

    原文:thinkphp学习笔记10-看不懂的路由规则 路由这部分貌似在实际工作中没有怎么设计过,只是在用默认的设置,在手册里面看到部分,艰涩难懂. 1.路由定义 要使用路由功能需要支持PATH_INF ...

  3. SpringMVC:学习笔记(10)——整合Ckeditor且实现图片上传

    SpringMVC:学习笔记(10)--整合Ckeditor且实现图片上传 配置CKEDITOR 精简文件 解压之后可以看到ckeditor/lang下面有很多语言的js,如果不需要那么多种语言的,可 ...

  4. springmvc学习笔记(10)-springmvc注解开发之商品改动功能

    springmvc学习笔记(10)-springmvc注解开发之商品改动功能 springmvc学习笔记(10)-springmvc注解开发之商品改动功能 标签: springmvc springmv ...

  5. Hadoop学习笔记—10.Shuffle过程那点事儿

    Hadoop学习笔记-10.Shuffle过程那点事儿 一.回顾Reduce阶段三大步骤 在第四篇博文<初识MapReduce>中,我们认识了MapReduce的八大步骤,其中在Reduc ...

  6. Linux学习笔记10

    Linux学习笔记10 Linux学习笔记10 正则表达式 源码包约定目录 Shell脚本约定目录 Shell脚本的创建与执行 date命令 同步时间 Shell脚本预设变量 与用户交互 数学计算 S ...

  7. HALCON 20.11:深度学习笔记(10)---分类

    HALCON 20.11:深度学习笔记(10)---分类 HALCON 20.11.0.0中,实现了深度学习方法. 本章解释了如何在训练和推理阶段使用基于深度学习的分类. 基于深度学习的分类是一种对一 ...

  8. 台大李宏毅Machine Learning 2017Fall学习笔记 (10)Tips for Deep Learning

    台大李宏毅Machine Learning 2017Fall学习笔记 (10)Tips for Deep Learning 注:本博客主要参照 http://blog.csdn.net/xzy_thu ...

  9. Python学习笔记--10.Django框架快速入门之后台管理admin(书籍管理系统)

    Python学习笔记--10.Django框架快速入门之后台管理 一.Django框架介绍 二.创建第一个Django项目 三.应用的创建和使用 四.项目的数据库模型 ORM对象关系映射 sqlite ...

  10. 史上最牛最强的linux学习笔记 10.shell基础

    史上最牛最强的linux学习笔记 10.shell基础 写在最前面: 本文是基于某站的视频学习所得,第一个链接如下: https://www.bilibili.com/video/BV1mW411i7 ...

最新文章

  1. 解决Docker容器 iptables问题
  2. 老手讲解在JSP开发中与Web的中文问题解决方法
  3. 小程序 座位管理系统(一)(纯前端)
  4. 【C 语言】文件操作 ( 文件加密解密 | 加密解密原理 | 对称加密 | 非对称加密 | 散列函数 )
  5. AAAI 2018论文解读 | 基于文档级问答任务的新注意力模型
  6. Android 通信 EventBus
  7. python爱因斯坦的问题_爱因斯坦的思考题.py
  8. 洛谷——P2077 红绿灯(解法2)
  9. C++中类的继承和组合
  10. presto、druid、sparkSQL、kylin的对比分析
  11. 测试电脑电源是否正常的办法
  12. 下列符合c语言语法的实型常量,以下各项中,符合C语言语法规定的实型常量是()...
  13. C++ RapidXml快速入门
  14. \t\t中国机械工程师资格认证中心及各分中心通讯录
  15. windows系统镜像修复计算机,Win10系统下修复Windows映像方法
  16. systemverilog随机函数
  17. 互联网晚报 | 9月14日 星期三 | ​理想汽车总裁5天抛售理想100万股港股;微信坚决抵制无底线追星;Phone15要改名?...
  18. android简易记账,简单记账(便捷快速记账)
  19. 基于android的电子词典设计_基于Android平台下的电子词典的设计与实现
  20. 7.设计模式--抽象工厂模式(AbstractFactory模式)

热门文章

  1. SolidWorks学习笔记5创建基准面,基准线,基准点
  2. 简述人工智能的发展历程图_人工智能的发展进程及现状
  3. 十分钟教你写个软件防火墙!powershell。
  4. JavaScript不清不楚之Array.isArray
  5. C语言编译器开发之旅(二):解析器
  6. 微信小程序 控制台报错net::ERR_UNSAFE_PORT
  7. revit二开之获取嵌套族中的子族(过滤族)
  8. Matlab——常用函数的用法总结(部分直接摘自mathwork,持续更新)
  9. 【中创算力】第六届优秀员工表彰大会暨四月中创生日会
  10. 基于 Next.js实现在线Excel