Anti-Aliasing
抗锯齿是图形学中的一个重要概念,它指的是消除或减少图像中的锯齿现象,也就是边缘不平滑的现象。锯齿现象会影响图像的质量和真实感,所以在游戏或视频中,通常会使用一些抗锯齿算法来提高画面的美观度。
抗锯齿算法有很多种,其中比较常见的有FXAA、SMAA、MSAA、TAA等。这些算法各有优缺点,适用于不同的场景和需求。本文将主要介绍两种抗锯齿算法:TAA和FXAA,并比较它们的区别。
一、多重采样抗锯齿(MSAA)
多重采样抗锯齿(MultiSampling Anti-Aliasing,简称MSAA),这是一种在OpenGL中的特殊的超级采样抗锯齿(SSAA),MSAA主要是对 Z-Buffer 和 Stencil Buffer(模板缓冲)进行SSAA处理,其原理是通过提取像素界面周围的颜色信息,通过混合颜色信息来消除高对比界面所产生的锯齿。只对多边形的边缘进行抗锯齿处理。
缺点:
资源耗费,画质上有些不如一般的SSAA。
OpenGL Extension Multsample
二、快速近似抗锯齿(FXAA)
快速近似抗锯齿(Fast Approximately -Aliasing,简称FXAA),是一种典型的边缘检查取样操作。FXAA原理与MSAA相同,其原理是通过提取像素界面周围的颜色信息,通过混合颜色信息来消除高对比界面所产生的锯齿。但是,FXAA将像素的提取和混合过程交由GPU 内的ALU(arithmetic and logic unit,算术逻辑单元)执行,所占用的显存带宽会 << 传统的MSAA。
优缺点
消耗低,速度快;但是是一种粗糙的模糊处理。
三、子像素增强抗锯齿(SMAA)
子像素增强抗锯齿(Enhanced Subpixel Morphological,简称SMAA),SMAA 与 FXAA类似,性能消耗小,但是相比FXAA更清晰。SMAA是后处理抗锯齿技术的一种,它的基本处理流程建立在Jimenez优化改造后的MLAA(形态学抗锯齿)算法之上。原始的MLAA是由英特尔实验室提出的抗锯齿技术,这项技术代表着后处理式抗锯齿蓬勃发展的开端。最初,MLAA是为CPU设计的,Jimenez对其进行改造并移植到GPU上,使其适用于实时渲染。SMAA则是在此基础上进一步发展而来的。
缺点
动态画面时,锯齿抖动厉害。
smaa参考文献
四、覆盖采样抗锯齿(CSAA)
覆盖采样抗锯齿(Coverage Sampling Anti-Aliasing,简称CSAA),这是一种覆盖的采样,它的原理是将边缘多边形里需要采样的子像素坐标覆盖掉,抒原像素坐标强制安置在硬件和驱动程序预告算好的坐标中。这就好比采样标准统一的MSAA,能够最高效率地执行边缘采样,交通提升非常明显,同时资源占用也比较低。
相比MSAA减少了带宽和存储开销。
五、时间性抗锯齿(TXAA)
让电影画质的游戏体验达到逼真水平。TXAA 抗锯齿比 MSAA和FXAA 以及 CSAA 的画质更高,制作CG电影的电影制片厂会在抗锯齿方面花费大量的计算资源,从而可确保观众不会因不逼真的锯齿状线条而分心。如果想要让游戏接近这种级别的保真度,那么开发商需要全新的抗锯齿技术,不但要减少锯齿状的线条,而且要减少锯齿状闪烁情形,同时还不降低性能。为了便于开发商实现这种保真度的提升,英伟达设计了画质更高的抗锯齿模式,名为TXAA.该模式专为直接集成到游戏引擎中而设计。
与CG电影中所采用的技术类似,TXAA集MSAA的强大功能与复杂的解析滤镜于一身,可呈现出更加平滑的图像效果,远远超越了所有同类技术。此外,TXAA还能够对帧之间的整个场景进行抖动采样,以减少闪烁情形,闪烁情形在技术上又称作时间性锯齿。
目前,TXAA有两种模式:TXAA 2X和TXAA 4X。TXAA 2X可提供堪比8X MSAA的视觉保真度,然而所需性能却与2X MSAA相类似;TXAA 4X的图像保真度胜过8XMSAA,所需性能仅仅与4X MSAA相当。
API
glBlendFunc
有两个参数,前者表示源因子,后者表示目标因子。
源因子 作用于源颜色(即即将要绘制的颜色或纹理值)
目标因子 作用于目标颜色(即之前所有绘制的颜色或纹理值结果)
glReadPixels 输出渲染结果
bin格式输出
char* pixels=new char[1600*2000*4];
glReadPixels(0, 0, 1600, 2000, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
FILE* outfile=fopen( "./img.bin","wb");
fwrite(pixels, 1600 * 2000 *4, 1,outfile);
fclose(outfile);
cvMat输出
glPixelStorei(GL_PACK_ALIGNMENT, 4);
cv::Mat rgba(2000, 1600, CV_8UC4);
glReadPixels(0, 0, 1600, 2000, GL_RGBA, GL_UNSIGNED_BYTE, rgba.data);
{
cv::imwrite("./img.png", rgba);
}