SMAANeighborhoodBlendingPS
//-----------------------------------------------------------------------------
// Neighborhood Blending Pixel Shader (Third Pass)
float4 SMAANeighborhoodBlendingPS(float2 texcoord,
float4 offset,
SMAATexture2D(colorTex),
SMAATexture2D(blendTex)
#if SMAA_REPROJECTION
, SMAATexture2D(velocityTex)
#endif
) {
混合
- 获取权重值
a.x = SMAASample(blendTex, offset.xy).a; // Right
a.y = SMAASample(blendTex, offset.zw).g; // Top
a.wz = SMAASample(blendTex, texcoord).xz; // Bottom / Left
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;
}
- 存在权重
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);
以水平锯齿为例:
观察上面的各阶段纹理,
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(略)