• Filtering Approaches for Real-Time Anti-Aliasing(2011 SIGGRAPH)


    Filtering Approaches for Real-Time Anti-Aliasing(2011 SIGGRAPH)

    image

    在2011的SIGGRAPH上,NVIDA提出了FXAA3.1,本文主要介绍FXAA实现思路,提供部分简单实现的代码。

    1.What is FXAA 3.11

    • Fast approXimate Anti-Aliasing
      • Two algorithms
        • FXAA 3.11 Console (360 and PS3)
        • FXAA 3.11 Quality (PC)
    • Fixed set of constraints
      • One shader pass, only color input, only color output
      • Run on all APIs (GL, DX9, through DX11, etc)
      • Certainly better can be done under other constraints!

    FXAA全称“Fast Approximate Anti-Aliasing”,翻译成中文就是“快速近似抗锯齿”。

    FXAA3.11在之前FXAA1,2的基础上做了一些改进。

    • FXAA1:最早最基础的版本,也是在PC游戏中使用最广泛的,已用于《孤岛危机2》、《无主之地》。
    • FXAA2:针对Xbox 360游戏机专门设计。
    • FXAA3:Quality质量版本面向PC,Console主机版本则面向Xbox 360、PS3。

    FXAA是一种单程像素着色器,和MLAA一样运行于目标游戏渲染管线的后期处理阶段,但不像后者那样使用DirectCompute,而只是单纯的后期处理着色器,不依赖于任何GPU计算API。正因为如此,FXAA技术对显卡没有特殊要求,完全兼容NVIDIA、AMD的不同显卡(MLAA仅支持A卡)和DX9、DX10、DX11。

    2.How FXAA Working

    image

    • Early exit for pixels

    取4个方向以及中间像素,对5个位置的值做滤波操作,对于范围之外进行分段线性变换。对于差异较大的像素,进行AA。

    maxLuma = max(nw,ne,sw,se)
    contrast = max(nw,ne,sw,se,m) - min(nw,ne,sw,se,m)
    if(contrast  >= max(minThreshold, maxLuma * threshold))
    

    image

    • extra taps
    dir.x = -((NW+NE)-(SW+SE))
    dir.y = ((NW+SW)-(NE+SE))
    dir.xy = normalize(dir.xy) * scale
    

    使用2x2的区域,计算像素边界,做向量运算。得到dir之后归一化长度。

    image

    • Optional extra 2 taps
      缩放dir.xy,扩展到8个像素
    minDir = min(|dir.x|, |dir.y|) * sharpness
    

    image

    • Compare 4-tap filter luma to neighborhood luma
      比较4个方向的luma和相邻luma的值,
    // Use the min and max luma range of the original 4 samples
     *  {NW, NE, SW, SE}
    // If 4-tap filter luma exceeds this range,
     *   Assume invalid and use just the first 2 taps
    
    

    image

    • 效果展示
      image

    image

    3.简单实现

    我自己再Direct11的环境下,参考FXAA思路,实现了简单版本的FXAA,相比自带d3d实现的4xMSAA,效果较为不明显,仅供交流学习。

    //--------------------------------------------------------------------------------------
    // File: FXAA.fx
    //--------------------------------------------------------------------------------------
    
    SamplerState samLinear : register(s0);
    Texture2D txFxaa : register(t0);
    
    struct PS_INPUT
    {
    	float4 Pos			: SV_POSITION;
    	float4 PosProj		: POSITION;
    	float3 Norm			: NORMAL;
    
    	float4 Diffuse		: COLOR0;
    	float2 Tex			: TEXCOORD;
    	float3 Tangent		: TANGENT;
    };
    
    float4 FxaaPS(PS_INPUT input) : SV_Target
    {
    	float4 texColor = txFxaa.Sample(samLinear, input.Tex);
    
    	// FXAA 3x3取9个像素
    	float3 luma = float3(0.299, 0.587, 0.114);
    	//luma = float3(0.33, 0.33, 0.33);
    	float lumaTL = dot(luma, txFxaa.Sample(samLinear, input.Tex.xy + float2(-1.0, -1.0)).xyz);
    	float lumaTR = dot(luma, txFxaa.Sample(samLinear, input.Tex.xy + float2(1.0, -1.0)).xyz);
    	float lumaBL = dot(luma, txFxaa.Sample(samLinear, input.Tex.xy + float2(-1.0, 1.0)).xyz);
    	float lumaBR = dot(luma, txFxaa.Sample(samLinear, input.Tex.xy + float2(1.0, 1.0)).xyz);
    	float lumaM = dot(luma, txFxaa.Sample(samLinear, input.Tex.xy).xyz);
    
    	float2 dir;
    	dir.x = -((lumaTL + lumaTR) - (lumaBL + lumaBR));
    	dir.y = (lumaTL + lumaBL) - (lumaTR + lumaBR);
    
    	float FXAA_SPAN_MAX = 8.0;
    
    	float direReduce = 1.0 / 128.0;
    	float inverseDir = 1.0 / (min(abs(dir.x), abs(dir.y)) + direReduce);
    
    	dir = min(float2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),
    		max(float2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), dir*inverseDir));
    
    	float3 res1 = (1.0 / 2.0) * (
    		txFxaa.Sample(samLinear, input.Tex.xy + (dir * float2(1.0 / 3.0 - 0.5, 1.0 / 3.0 - 0.5))).xyz +
    		txFxaa.Sample(samLinear, input.Tex.xy + (dir * float2(2.0 / 3.0 - 0.5, 2.0 / 3.0 - 0.5))).xyz);
    
    	float3 res2 = res1 * (1.0 / 2.0) + (1.0 / 4.0) * (
    		txFxaa.Sample(samLinear, input.Tex.xy + (dir * float2(0.0 / 3.0 - 0.5, 0.0 / 3.0 - 0.5))).xyz +
    		txFxaa.Sample(samLinear, input.Tex.xy + (dir * float2(3.0 / 3.0 - 0.5, 3.0 / 3.0 - 0.5))).xyz);
    
    	float lumaRes = dot(luma, res2);
    
    	float lumaMin = min(lumaM, min(min(lumaTL, lumaTR), min(lumaBL, lumaBR)));
    	float lumaMax = max(lumaM, max(max(lumaTL, lumaTR), max(lumaBL, lumaBR)));
    
    	if (lumaRes <lumaMin || lumaRes > lumaMax)
    		texColor = float4(res2, 1.0);
    	else
    		texColor = float4(res1, 1.0);
    
    	return texColor;
    }
    
    
    
    • 效果对比(左为无FXAA)

    image

    image

  • 相关阅读:
    Spring AOP
    Spring Bean的生命周期
    MySQL中的SQL的常见优化策略
    垃圾收集器
    JWT
    Zookeeper
    RabbitMQ原理介绍
    kafka 安装配置
    kafka 简介
    ELK logstash 各种报错
  • 原文地址:https://www.cnblogs.com/SeekHit/p/9010571.html
Copyright © 2020-2023  润新知