反锯齿技术Anti-Aliasing

来源:互联网 发布:python 单元测试框架 编辑:程序博客网 时间:2024/05/14 18:11
反锯齿技术Anti-Aliasing
作者: 刘鹏
日期: 2011-12-22
本文总结了反锯齿技术,重点介绍了全景反锯齿。

简介

显卡经过多年的发展,其性能越来越强劲,抗锯齿技术在显卡里也是越来越复杂,而且让人困惑.MSAA,CSAA,CFAA,SSAA,Quincunx,Narrow Tent, Wide Tent,Edge Detect,Temporal AA, Adaptive AA...Nvidia和AMD(ATI)竞相推出了无数的抗锯齿名词,本文详细介绍了SSAA,MSAA,CSAA,CFAA四种技术。较全面的总结可见参考文章4.

各种反锯齿技术的比较1

常见的反锯齿技术包括:SSAA, MSAA, CSAA, CFAA。

SSAA就是super sampling antialising的抗锯齿方式,最简单的方式就是渲染的时候按照显示器分辨率的若干倍来渲染,例如显示器1024x768,那么SSAA 4X就是4096x3072,然后以box filter的方式down sample为1024x768的显示器分辨率。

MSAA本质上其实是SSAA,但是它采用了智能的算法侦测出三角形边缘,只在边缘上作SSAA,渲染分辨率倍数是和显示器分辨率一样的,但是内存带宽、占用的空间依然是取样的倍数。现在的MSAA一般会做jitter来提高FSAA的平滑效果,一般来说4x Jitter的MSAA就相当于16x SSAA的AA效果,但是SSAA除了AA外,纹理LOD也是一并提升的,同样的取样倍数下,SSAA的纹理锐利度比MSAA更好。

CSAA就是希望在MSAA节省渲染的基础上再节省内存带宽、存储空间的AA方式,目前只有NVIDIA的g8x+ GPU具备此特性。简单地说,CSAA的原理就是把取样的子像素覆盖(Coverage)坐标从深度/色彩信息剥离掉,透过改变Coverage实现取样点坐标的改变,其实可以看作是一种独特、固定模板的jitter。

CFAA(Custom Filter Anti-Aliasing): 即定制滤镜抗锯齿,其原理是通过设置滤镜改善 MSAA。虽然该技术比普通的MSAA性能有提升,但是会让画面变得比较模糊。AMD_ATI 的技术1

SSAA—SuperSampling Anti-Aliasing1

SSAA,即超级取样抗锯齿模式。这是最基本的抗锯齿模式,实现原理是渲染时把画面按照显示器分辨率的若干倍放大,如在1024x768分辨率上开启 2xSSAA,GPU会先渲染2048x1536图像,再“塞进”1024x768的边框里成型,将画面精细度提升一倍,毫无疑问会改善边缘锯齿情况。但是众所周知,高分辨率图形的渲染会极大的消耗GPU运算资源和显存容量及带宽,因此SSAA资源消耗极大,即使是最低的2x也未必就能轻易承受。

MSAA—MultiSampling Anti-Aliasing1

MSAA,即多重取样抗锯齿模式。这是nVidia在NV20即GeForce 3显卡上首次引入实用化。简单说MSAA就是SSAA的改进版。SSAA仅仅为了边缘平滑,而不得不重新以数倍的分辨率渲染整个画面,造成宝贵显卡处理资源的极大浪费,因此MSAA正是为了改善这种情况而生。MSAA实现方式类似于 SSAA,不同之处在于MSAA仅仅将3D建模的边缘部分放大处理,而不是整个画面。简单说3D模型是由大量多边形所组成,MSAA仅仅处理模型最外层的多边形,因此显卡的负担大幅减轻。nVidia和ATI也不遗余力的推出各种MSAA优化技术用以提升MSAA的画面质量与速度,MSAA虽然是2002 的技术,当前却正是红火的正式实用化时代,许多游戏在菜单里都提供了直接支持。

MSAA虽然趋于易用化,十分流行,但是缺点也很明显:1,如果画面中单位物体较多,需要处理的边缘多边形数量也自然增多,此时MSAA性能也会下降的十分厉害。2,同样倍数的MSAA,理论上边缘平滑效果与SSAA相同,但是由于仅仅处理边缘部分的多边形,因此非边缘部分的纹理锐度肯定远不如SSAA

CSAA—CoverageSampling Anti-Aliasing1

CSAA,即覆盖取样抗锯齿。这是nVidia在G80及其衍生产品首次推向实用化的AA技术,也是目前nVidia GeForce 8/9系列独享的AA技术。 CSAA就是在MSAA基础上更进一步的节省显存使用量及带宽,简单说CSAA就是将边缘多边形里需要取样的子像素坐标覆盖掉,把原像素坐标强制安置在硬件和驱动程序预先算好的坐标中。这就好比取样标准统一的MSAA,能够最高效率的执行边缘取样,效能提升非常的显著。比方说16xCSAA取样性能下降幅度仅比4xMSAA略高一点,效果却几乎和8xMSAA一样。8xCSAA有着4xMSAA的处理效果,性能消耗却和2xMSAA相同。

CSAA是目前最为先进的AA实现方式,也是GeForce 8克敌制胜的重要法宝之一,可以遇见,在将来的两三年内,CSAA必定会获得大量游戏软件的直接支持从而大放异彩。

CFAA—Custom Filter Anti-Aliasing1

即可编程过滤抗锯齿。这是AMD-ATI自R600家族起另立门户开发的自有AA技术。简单说CFAA就是扩大取样面积的MSAA,比方说之前的MSAA是严格按照边缘多边形实际数量取样,而CFAA可以通过驱动程序实现以较少的多边形像素取样数量完成抗锯齿工作,理论上看对性能会有相当幅度的改善,但是实际效果不会比CSAA和MSAA更好。12xCFAA大约以1.5个多边形为基本单位,在1.5个多边形内取样12个像素,因此理论上看与8xMSAA有着近似的效果,而性能损失却与6xMSAA相当。

然而走实际运行中观察到,CFAA由于没有按照标准的多边形像素数量进行取样,每个基本取样单元之间必然会有重复的部分,因此实际效果感觉边缘纹理质量较差,模糊。因此许多网友戏称CFAA为浆糊AA,这种模式接受程度较低,需要做更进一步的改进。

MSAA 的实现

在 OpenGL 中增加多重采样功能需要如下步骤:

  1. 获取一个支持多重采样的窗口,如果使用 GLUT,可通过如下方法实现:
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_MULTISAMPLE);}
  1. 打开窗口后,验证下多重采样功能是否可用。如果查询状态变量GL_SAMPLE_BUFFERS 返回的值是1,并查询 GL_SAMPLES返回的值大于1,就可以使用多重采样功能。(GL_SAMPLES返回子像素样本的数量。如果只返回1个样本,多重采样就被禁用)
GLint bufs, samples;glGetIntegerv (GL_SAMPLES_BUFFERS, &bufs);glGetIntegerv (GL_SAMPLES, &samples);
  1. 调用 glEnable (GL_MULTISAMPLE) 启动多重采样功能。

下面是一个启用多重采样功能的 glut 程序示例代码:

void display(){    ......    glEnable (GL_MULTISAMPLE);    draw objects...    glDisable (GL_MULTISAMPLE);    ....}    ... ...int main (){    ... ...    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_MULTISAMPLE);    ... ...}

OpenGL ES 的实现略有不同:

    EGLint pi32ConfigAttribs[11];    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE;    pi32ConfigAttribs[1] = EGL_WINDOW_BIT;    pi32ConfigAttribs[2] = EGL_BUFFER_SIZE;    pi32ConfigAttribs[3] = 32;    pi32ConfigAttribs[4] = EGL_DEPTH_SIZE;    pi32ConfigAttribs[5] = 24;    pi32ConfigAttribs[6] = EGL_SAMPLE_BUFFERS;    pi32ConfigAttribs[7] = 1;    pi32ConfigAttribs[8] = EGL_SAMPLES;    pi32ConfigAttribs[9] = 2;    pi32ConfigAttribs[10] = EGL_NONE;    EGLint iConfigs;    if (!eglChooseConfig(eglDisplay, pi32ConfigAttribs, &eglConfig, 1, &iConfigs) || (iConfigs != 1))    {        printf("Error: eglChooseConfig() failed.\n");        goto cleanup;    }    eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, ......);    eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, NULL);    eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);    ...    while (true) {        ... ...        glEnable (GL_MULTISAMPLE);        draw objects ... ...        glDisable (GL_MULTISAMPLE);        ... ...        eglSwapBuffers(eglDisplay, eglSurface);    }

CSAA 的实现

只在 NV 的硬件上支持。

使用 CSAA 需要如下步骤:

  1. 创建支持 CSAA 的 surface
  2. 打开 CSAA 支持
// create CSAA-supported surfacevoid createConfig (){    int EGL_COVERAGE_BUFFERS_NV = 0x30E0;    int EGL_COVERAGE_SAMPLES_NV = 0x30E1;    configSpec = new int[]{        EGL_RED_SIZE, 5,        EGL_GREEN_SIZE, 6,        EGL_BLUE_SIZE, 5,        EGL_DEPTH_SIZE, 16,        EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */,        EGL_COVERAGE_BUFFERS_NV, 1 /* true */,        EGL_COVERAGE_SAMPLES_NV, 2,  // always 5 in practice on tegra 2        EGL_NONE    };    if (!egl.eglChooseConfig(display, configSpec, null, 0, mValue)) {        failed.    }    else        printf ("Create coverage sample config succeeded.\n");    ....}// set CSAAvoid render (){    int clearMask = GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT;    int GL_COVERAGE_BUFFER_BIT_NV = 0x8000;    clearMask |= GL_COVERAGE_BUFFER_BIT_NV;    ... ...}
0 0
原创粉丝点击