这两年我的工作都转到了D3D11,目前新出硬件几乎全部支持此标准,加上D3D11接口清晰,概念直观,等到windows7普及,想必未来都是D3D11的天下。最近时间较空,我陆续开始写些基础文章,希望对新学者有所帮助。但文章纯属我自己随意写写,错误肯定很多,请大家多多包涵。

所谓MSAA,就是让一个像素可以同时存储多个颜色,而最终的显示结果由多个颜色重建而成。具体存储颜色的数量由DXGI_SAMPLE_DESC中的Count来决定,其中的Quality则一般用来给硬件设计厂商作为非常规发挥的余地,比如NVDIA CSAA开启方式就是用Quality某些值来实现的。在D3D9中MSAA中即使一个像素被分成多个子片段来光栅化,但实际上覆盖此像素的每个三角形依然只执行一次pixel shader,子片段的位置只用来决定各种顶点属性的插值位置,以及进行覆盖率评定,这就是MSAA相比SSAA的最大不同之处,MSAA只会增加被多个三角形同时非完全覆盖时的计算率,而且不管其覆盖率有多高,每个三角形都只执行一次Pixel shader,并将Pixel shader返回的值存入相关覆盖子像素。需要注意的是,这里存在两个细节问题,一是Pixel shader输入的值如何插值而来(插值位置和插值算法);二是子像素到底位于像素中的何处,个数如何决定,是否每个子像素都对应一个color/z/stencil存储,如何将所有这些存储的子合成为最后的结果。对于第一个问题,就牵涉到MSAA光栅化规则的问题,注意如果没有任何特殊设置,对应像素Fragment的属性插值操作都将在像素中心位置上执行,MSAA中进行覆盖率评定时,很有可能三角形并未覆盖到像素中心位置,这就牵扯到一个外部插值(extrapolate)的问题,即插值位置根本就不在三角形内,很显然这样插值出来的属性结果是错误的,为了解决这个问题,D3D引入一个配置“centroid sample”,指定在rasterize时,相关属性进行插值的位置必须位于三角形与像素相交区域内,这个通常这个位置取在某个被覆盖的子像素位置,但并不保证永远不变,可能和具体硬件设计还有关,D3D11 reference rasterizer选择centroid sample位置的具体算法,可参考D3D文档。在D3D11中想要打开centroid sample,只需在对应pixel shader input attribute上加上centroid modifier即可;属性的插值算法,就是如何用三个顶点attribute值,以及中间点A的位置,使用某种算法插值出attribute在中心点A上的值,D3D中最常用的就是带透视矫正的线性插值(linear),所有attribute默认都使用此算法插值(linear modifier),当然D3D11还提供其他几种插值方式:nointerpolation(就是不插值,使用三角形中第一个顶点的属性值作为Fragment属性值),noperspective(不带透视矫正的线性插值,只使用屏幕2D坐标位置进行插值计算),sample(在每个子像素位置进行插值)。这些modifier可以加在PS input attribute前面,不过使用起来还是有些限制和规则,比如centroid、sample明显只能在MSAA模式下才能起作用,因为普通模式下不存在非中心覆盖和子像素位置问题;而centroid很显然也不能同nointerpolation一起使用,更多信息还请参考DX文档,毕竟知道这些背后原理后,更好记忆和理解这些限制。现在讨论第二个问题,子像素分布在像素区域中的位置是因硬件设计而变的,D3D标准并没有规定具体分布的位置,而个数按道理上来讲就是DXGI_SAMPLE_DESC种的count所变量指定。是否每个子像素都会在RT surface上有相应的存储位置(color/z/stencil),这个就有点悬了,毕竟这个是要增加硬件成本的事,而且D3D标准也没强制,硬件厂商说:OK,我可以给你指定的覆盖点数,我也可以把这些点的位置进行精心设计分布,但我不一定会给每个点都分配实际的存储位置。比如CSAA就将子像素数和实际存储数分开来了,以此来节省存储和带宽,CSAA和16x实际上只有4个存储位置(但它确实有16个子像素),16个子像素(覆盖率判断)如何分享4个存储位置呢?答案是硬件设计有关。最后一个问题,每个像素中存储的多个值如何重建为最终结果?答案还是硬件设计有关,但我们可以自己resolve(http://mynameismjp.wordpress.com/2012/10/28/msaa-resolve-filters/)。

在D3D11中是可以指定pixel shader进行per-sample excution的,这个和D3D9完全不同,在pixel shader input中指定SV_SampleIndex属性或为属性指定sample modifier都会打开pixel shader逐子像素执行(这个在CSAA中就有点问题了,因为CSAA并不为每个子像素分配独立的存储)。MSAA并不由Pipeline中的一个stage完成,而牵涉到rasterization、pixel shader、output merger三个stage,D3D11对MSAA的操作进行了空前的增强,可以获取sample index, coverage mask, sub pixel value, 以及pixel shader新支持的UAV,综合这些我们可以完成一些很特别的算法。需要注意的是用centroid sample或per sample execution后会带来一个问题,就是GPU的某些地方的导数计算可能有误,比如ddx ddy以及texture lod计算,因为三角形边缘像素的采样位置会被偏置到某个sample的位置,而不再是像素中心,这样2x2像素中,变量相差之后的值就不再是基于单位的屏幕空间坐标了,这样在三角形边缘的像素上计算变量的导数就会出现跳跃起伏,这样会使ddx ddy的结果产生异常,所以要么你能容忍或解决这个问题,要么就不要在centroid sample的属性上进行导数计算。

pixel shader输出Z会给MSAA带来一些麻烦。如果pixel shader没有开启per sample exctution,但却输出了SV_Depth,这就产生一个问题,本来每个子像素在depth stencil buffer中都会输出各自独立的Z值,此Z值为光栅化时插值产生,因此每个子像素都有一个正确的Z值,但如果pixel shader人工输出了Z,而这个pixel shader只执行一次,这样被此三角形覆盖的所有子像素的Z值都将是这个单一值,此值为像素中心的Z值(没有开启centroid sample的情况下),这就会导致一个问题,所有先绘制了更近三角形的边缘像素都可能失去或产生错误的抗锯齿效果!(特别是在三角形连续交界处)请看下图,绘制顺序为红、蓝、绿,这些几何体的pixel shader都输出了SV_Depth。请注意某些边缘已经失去了抗锯齿效果。

另外D3D10引入一个新的概念ALPHA-TO-COVERAGE,以及一个SV_Coverage的pixel shader输出变量。注定要把MSAA玩出花来了!以8x的MSAA为例,在z/stencil/color buffer上每个像素均有8个子像素,如果开启了ALPHA-TO-COVERAGE,pixel shader输出的ALPHA值会被转为一个8阶的值,表示此Fragment在像素上的mask,这个主要是用来解决Alpha Test边缘锯齿问题,其原理就是将光栅化阶段产生的MASK A,AND ALPHA转化的MASK B,AND SV_Coverage MASK C。看下面的例子,三块完全重叠的面片,打开Alpha-To-Coverage,并且都输出0.5的Alpha值,从近到远分别为红、绿、蓝,发现完全不会有互相半透的效果,原因很简单,本例开的是8x msaa,0.5的ALPHA会被GPU转化为00001111B的MASK,红绿蓝三个Mesh都输出相同MASK的话,子像素的值会被最近的Mesh覆盖掉。

我们修改下输出的Alpha值,红色0.25,绿色0.5,蓝色0.75,当红绿蓝视距从近到远排列时,输出结果如下:

很简单,因为红色的MASK为00000011B,绿色为00001111B,蓝色为00111111B,互相重叠的部分,近的颜色将占据MASK相对应的子像素,较远的会被覆盖掉。如果我们再反过来看,让红绿蓝视距变为从远到近排列,结果就变成这样了:

原因大家可以自己分析。综上,Alpha-To-Coverage注定是个悲催的OIT技术!

更多MSAA资料

http://mynameismjp.wordpress.com/2012/10/24/msaa-overview/

D3D11中的MSAA的更多相关文章

  1. OpenGL和D3D11中的深度模版测试

        在OpenGL和D3D11的管线中,像素shader之后的操作就是深度模版测试,深度模版测试是以sample为单位进行的,就是一个像素上可以有多个采样点,每个采样点都有深度信息.深度模版测试对 ...

  2. [ZZ] 基于DirectX shader的Per-pixel lighting实现

    这个特效需要用到DX11 UAV吗? http://blog.tianya.cn/blogger/post_show.asp?BlogID=510979&PostID=5665974 Intr ...

  3. Directx11学习笔记【三】 第一个D3D11程序

    在先前的解决方案中新建一个新的Win32项目FirstD3D11Demo.在写代码之前,我们必须先添加dx11所需要的库.为了链接dx库,右键项目选择属性->vc++目录,在包含目录中添加你所安 ...

  4. OpenGL ES3使用MSAA(多重采样抗锯齿)的方法

    昨晚花费了我2个多小时的时间终于把OpenGL ES3.0中的MSAA给搞定了.在OpenGL ES2.0中,Khronos官方没有引入标准的MSAA全屏抗锯齿的方法,而Apple则采用了自己的GL_ ...

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

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

  6. Directx11教程(15) D3D11管线(4)

    原文:Directx11教程(15) D3D11管线(4) 本章我们首先了解一下D3D11中的逻辑管线,认识一下管线中每个stage的含义. 参考资料:http://fgiesen.wordpress ...

  7. Direct3D11学习:(五)演示程序框架

    转载请注明出处:http://www.cnblogs.com/Ray1024 一.概述 在此系列最开始的文章Direct3D11学习:(一)开发环境配置中,我们运行了一个例子BoxDemo,看过这个例 ...

  8. UE4命令行使用,解释

    命令行在外部 从命令行运行编辑项目 1 导航到您的[LauncherInstall][VersionNumber]\Engine\Binaries\Win64 目录中. 2 右键单击上 UE4Edit ...

  9. Directx11教程(4) 一个最基本D3D应用程序(2)

    原文:Directx11教程(4) 一个最基本D3D应用程序(2) 接着上篇教程的代码,本篇加入基本的D3D代码,实现一个完整的D3D11程序框架. 我们增加一个新类D3DClass, 用来处理3D渲 ...

随机推荐

  1. OJ-上海交大-1021. 从前有座山

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  2. fir.im Weekly - 我回来了

    Hey, 大家好,距离 fir.im 新版上线已匆忙过去一周多的时间,新版的fir正在慢慢稳定优化中,感谢大家的反馈与支持!后续我们将上线 FAQ 帮助中心,如还有疑问请邮件至 help@fir.im ...

  3. Liferay7 BPM门户开发之26: 集成Activiti到Liferay7

    开发顺序: 实战任务1,开发BPM管理后台(用于在Liferay管理中心管理Activiti模型上传) 一个熟悉Portlet操作的项目,为开发打好基础. http://www.cnblogs.com ...

  4. shell 时间统计脚本

    #!/bin/sh #Today=`date +%Y%m%d` YEAR=`echo $|cut -c -` MONTH=`echo $|cut -c -` DAY=`echo $|cut -c -` ...

  5. [推荐]WebService开发知识介绍

    [推荐]WebService开发知识介绍 WebService开发手册  http://wenku.baidu.com/view/df3992ce050876323112128a.html WebSe ...

  6. Java Socket网络编程常见异常(转)

    1.java.net.SocketTimeoutException 这个异常比较常见,socket超时.一般有2个地方会抛出这个,一个是connect的时候,这个超时参数由connect(Socket ...

  7. nginx用户认证配置( Basic HTTP authentication)

    ngx_http_auth_basic_module模块实现让访问着,只有输入正确的用户密码才允许访问web内容.web上的一些内容不想被其他人知道,但是又想让部分人看到.nginx的http aut ...

  8. Bitmap和Drawable相互转换方法

    很多开发者表示,不知道Android的Drawable和Bitmap之间如何相关转换.下面给大家两种比较简单高效的方法. 一.Bitmap转Drawable Bitmap bm=xxx; //xxx根 ...

  9. java匹配中文的正则表达式

    [\u4E00-\u9FA5]* public static void regxChinese(){ // 要匹配的字符串 String source = "<span title=' ...

  10. GDAL 遥感图像处理后的数据保存为图像文件的实现方法

    在遥感图像处理中,GDAL库不仅能读取和处理大部分的遥感图像数据,而且还能够实现图像处理后将数据保存为图像的功能. 本文就详细介绍如何将内存中的图像数据保存为.tif格式. 首先,遥感数据处理完,保存 ...