SMAA算法详解 - SMAANeighborhoodBlendingPS


目录 - SMAA代码详解


SMAANeighborhoodBlendingPS

//-----------------------------------------------------------------------------
// Neighborhood Blending Pixel Shader (Third Pass)

float4 SMAANeighborhoodBlendingPS(float2 texcoord,
                                  float4 offset,
                                  SMAATexture2D(colorTex),
                                  SMAATexture2D(blendTex)
                                  #if SMAA_REPROJECTION
                                  , SMAATexture2D(velocityTex)
                                  #endif
                                  ) {

混合


  1. 获取权重值
    a.x = SMAASample(blendTex, offset.xy).a; // Right
    a.y = SMAASample(blendTex, offset.zw).g; // Top
    a.wz = SMAASample(blendTex, texcoord).xz; // Bottom / Left

left / right

bottom / top
2. 没有权重

if (dot(a, float4(1.0, 1.0, 1.0, 1.0)) < 1e-5) {
float4 color = SMAASampleLevelZero(colorTex, texcoord);

#if SMAA_REPROJECTION
float2 velocity = SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, texcoord));

// Pack velocity into the alpha channel:
color.a = sqrt(5.0 * length(velocity));
#endif

return color;
} 

  1. 存在权重
bool h = max(a.x, a.z) > max(a.y, a.w); // max(horizontal) > max(vertical)

判断横向混合还是纵向混合水平锯齿纵向混合,垂直锯齿横向混合。


3.1 计算混合偏移

// Calculate the blending offsets:
float4 blendingOffset = float4(0.0, a.y, 0.0, a.w);
float2 blendingWeight = a.yw;
SMAAMovc(bool4(h, h, h, h), blendingOffset, float4(a.x, 0.0, a.z, 0.0));
SMAAMovc(bool2(h, h), blendingWeight, a.xz);

以上算法等同于:

bool h = max(a.x, a.z) > max(a.y, a.w)
if(h)
{
    blendingOffset = float4(a.x, 0.0, a.z, 0.0);
    blendingWeight = a.xz;
}
else
{
    bleningOffset = float4(0.0, a.y, 0.0, a.w);
    blendingWeight = a.yw;
}

3.2 权重归一化

blendingWeight /= dot(blendingWeight, float2(1.0, 1.0));

混合比例总和应为1


3.3 计算采样纹理坐标

// Calculate the texture coordinates:
float4 blendingCoord = mad(blendingOffset, float4(SMAA_RT_METRICS.xy, -SMAA_RT_METRICS.xy), texcoord.xyxy);

以水平锯齿为例:
ColorTex

在这里插入图片描述
weightTex
ResultTex

观察上面的各阶段纹理,

WeightTex中上边界,红色部分与上混合,绿色部分的上一行与下混合。

双线性采样,
红色部分采样坐标等于 Texcoord.y - WeightTex.r,
绿色部分上一行坐标等于 Texcoord.y + WeightTex.g。

如果当前像素有上边界的 r 值,当前纹理坐标 texcoord.y -= WeightTex.r,
如果当前像素的下一行的像素有上边界的 g 值,当前纹理坐标 texcoord.y += WeightTex.g。

当前像素的 r 值:a.w = SMAASample(blendTex, texcoord).x,
当前像素下一行的g值:a.y = SMAASample(blendTex, offset.zw).g。

if(h == false)
{
    blendingWeight = a.yw;
    blendingOffset.yw = (a.y, a.w);
    blendingCoord.yw = (texcoord.y + blendingOffset.y, texcoord.w - blendingOffset.w); 
}

同理可计算垂直锯齿。


3.4 混合颜色

// We exploit bilinear filtering to mix current pixel with the chosen
        // neighbor:
        float4 color = blendingWeight.x * SMAASampleLevelZero(colorTex, blendingCoord.xy);
        color += blendingWeight.y * SMAASampleLevelZero(colorTex, blendingCoord.zw);

每个像素的权重都分为两个部分a1, a2,把这两个部分相加。就得到最终的颜色。


3.5 reprojection

#if SMAA_REPROJECTION
        // Antialias velocity for proper reprojection in a later stage:
        float2 velocity = blendingWeight.x * SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.xy));
        velocity += blendingWeight.y * SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.zw));

        // Pack velocity into the alpha channel:
        color.a = sqrt(5.0 * length(velocity));
        #endif

for cryEngine(略)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值