Games101笔记【超采样抗锯齿(MSAA)】的C实现

上一篇文章中讲到了多边形的绘制实现,但是有一个问题:锯齿感比较强。本文也顺着Games101在上一篇文章的基础上,实现其中的一种抗锯齿方法,实现方式大致是,将每个点再“细分”成多个点,计算细分点在多边形中所占的比例以决定该点的透明度。结果就是将边缘模糊(去除边缘的高频信号)。话不多少,代码如下

// 画一条分割线
cv::line(_mainMatImg, cv::Point(500, 0), cv::Point(500, 500), cv::Scalar(255, 0, 0));
// 再画抗锯齿的三角形
int posPtCnt;
unsigned char mixColor[4], fColor[4] = {0, 0, 255, 0};
const int antiTime = 4;     // 超分辨率倍率
double dTmp;

for (int y = 0; y < _mainMatImg.rows; ++y)
{
    for (int x = 0; x < _mainMatImg.cols / 2; ++x)
    {
        // 此处将一个像素通过“超分辨率”提升为 antiTime*antiTime 个像素
        posPtCnt = 0;

        for (int yy = 0; yy < antiTime; ++yy)
        {
            for (int xx = 0; xx < antiTime; ++xx)
            {
                for (i = 0; i < polyEdgeNum; ++i)
                {
                    // 求多边形形边向量
                    v1[0] = triAngPt[(i + 1) % polyEdgeNum][0] - triAngPt[i][0];
                    v1[1] = triAngPt[(i + 1) % polyEdgeNum][1] - triAngPt[i][1];
                    // 求当前“超分辨率”点和多边形当前边起始点的向量
                    v2[0] = (x - 0.5 + 1.0 / (antiTime * 2) + xx * 1.0 / antiTime) - triAngPt[i][0];
                    v2[1] = (y - 0.5 + 1.0 / (antiTime * 2) + yy * 1.0 / antiTime) - triAngPt[i][1];
                    // 将上述两个向量叉乘以求方向
                    vxvRst = v1[0] * v2[1] - v1[1] * v2[0];

                    //
                    if (i == 0)
                    {
                        ifNegative = (vxvRst > 0 ? false : true);
                    }
                    else
                    {
                        if (ifNegative == true && vxvRst > 0
                            || ifNegative == false && vxvRst < 0)
                        {
                            break;
                        }
                    }
                }

                //
                if (i >= polyEdgeNum)
                {
                    ++posPtCnt;
                }
            }
        }

        if (posPtCnt > 0)
        {
            // dTmp即求得的当前像素点的透明度值
            dTmp = posPtCnt * 1.0 / (antiTime * antiTime);
#if 0
            fColor[3] = dTmp * 255.0;
            // 使用颜色融合,将前景色和背景色进行融合
            ColorMix(fColor, bkColor, mixColor);
            _mainMatImg.data[y * _mainMatImg.step + (x + _mainMatImg.cols / 2) * 3 + 0] = mixColor[0];
            _mainMatImg.data[y * _mainMatImg.step + (x + _mainMatImg.cols / 2) * 3 + 1] = mixColor[1];
            _mainMatImg.data[y * _mainMatImg.step + (x + _mainMatImg.cols / 2) * 3 + 2] = mixColor[2];
#else
            _mainMatImg.data[y * _mainMatImg.step + (x + _mainMatImg.cols / 2) * 3 + 0] = fColor[0] * posPtCnt * 1.0 / (antiTime * antiTime);
            _mainMatImg.data[y * _mainMatImg.step + (x + _mainMatImg.cols / 2) * 3 + 1] = fColor[1] * posPtCnt * 1.0 / (antiTime * antiTime);
            _mainMatImg.data[y * _mainMatImg.step + (x + _mainMatImg.cols / 2) * 3 + 2] = fColor[2] * posPtCnt * 1.0 / (antiTime * antiTime);
#endif
        }
    }
}

为了便于展示,我们先把背景颜色调成黑色,结果如下,左边是上一篇文章的结果,右边是此处抗锯齿后的结果,可以修改代码查看不同倍率的抗锯齿效果。

 特别说明:

(1)为什么此处我们改用黑色背景,我们把背景调成其他颜色就可以知道了,下面是不同背景颜色的显示结果

可以发现不仅没有抗锯齿效果,还多了黑色的“锯齿”!究其原因是此处使用了简单的计算结果得到的颜色填充(这种方式在背景为黑色的时候没有问题),而正确的做法是需要将前景颜色和背景颜色进行颜色叠加才是最终的颜色,下面就是使用了颜色叠加的效果,而且可以任意更改背景颜色也不会影响显示效果

关于颜色融合可以查看这里:如何实现颜色叠加? - 知乎 

 最后,感谢闫令琪和Games101!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值