以前 Simple2D 使用 Canvas2D 对象来绘制几何图形,而且渲染出来的几何图形存在明显的锯齿。如果想要抗锯齿的几何图形,则需要开启 OpenGL 的 MSAA,这需要很大的开销。
如果不使用 MSAA,如何实现反走样的几何图形呢?如果在网上查一查的话,很多的文章都在讲反走样直线的实现,很难找到反走样多边形的实现。不过,你可以在 ImGui 中发现反走样的直线和多边形。于是,我就看了 ImGui 的源码,探究 ImGui 使用什么算法实现反走样的。可以发现 ImGui 并没有使用图元 GL_LINES 来绘制线段,无论是线段还是多边形都使用 GL_TRIANGLES 来绘制。下面来介绍 ImGui 反走样的原理:
反走样直线
(图片只是为了说明反走样的原理,并不能表现锯齿效果或反走样效果)
上图左侧是使用普通的方法绘制的折线,只需要 3 个顶点就可以绘制,但这样绘制的折线会存在锯齿。
右侧则是 ImGui 反走样直线原理,同样是一根折线,但它是由 8个三角形绘制而成,也就是一条直线需要使用 4 个三角形绘制。有红圈圈住的顶点的 alpha 值为 0,而蓝圈圈住的顶点的 alpha 值为 1。这样绘制出来的直线的边缘会有透明效果,看起来很平滑。
上图是 Tween 动画演示中绘制的曲线,有很好的反走样效果。那么如何通过 3 个点计算出其它 6 个顶点从而构成 8 个三角形?可以先计算出直线的法线,然后往法线的方向平移 1 像素,就可以得到两条直线,按照一定的规律连接这些顶点可以得到 4 个三角形:
这是一条直线的情况下,如果是由多条直线组成的折线,再以同样的方法计算出顶点,会发现交界处的顶点没有闭合:
正常的情况应该是下图这样的:
解决的方法是把交接处的两个分离的顶点合成一个顶点即可,将两条直线的法线相加再取平均值得到新的法线,把交接点往新法线平移得到的新顶点就是外面两条直线的交点。
上面是线宽为 1 的直线的反走样实现,如果是线宽 > 1 的情况,反走样原理则和多边形的反走样类似。
反走样多边形
假设要绘制反走样的 6 边形:
和反走样直线类似,内圈顶点的 alpha 值为 1,外圈顶点的 alpha 值为 0,唯一的不同是组成三角形的方式。内、外圈的顶点都可以通过法线来计算,和直线的计算一样,最后按图所示组成三角形即可。
使用这种方法可以实现反走样,但需要额外的顶点。Simple2D 的 Painter 对象替换掉 Canvas2D 对象,提供了反走样图形的绘制。
源码下载:Simple2D-20.rar